diff --git a/main.go b/main.go index e649eba..7f230f4 100644 --- a/main.go +++ b/main.go @@ -24,6 +24,7 @@ func main() { upstreams := StringArray{} skipAuthRegex := StringArray{} googleGroups := StringArray{} + redisSentinelConnectionURLs := StringArray{} config := flagSet.String("config", "", "path to config file") showVersion := flagSet.Bool("version", false, "print version string") @@ -76,7 +77,10 @@ func main() { flagSet.Bool("cookie-httponly", true, "set HttpOnly cookie flag") flagSet.String("session-store-type", "cookie", "the session storage provider to use") - flagSet.String("redis-connection-url", "", "URL of redis server for redis session storage type (eg: redis://HOST[:PORT])") + flagSet.String("redis-connection-url", "", "URL of redis server for redis session storage (eg: redis://HOST[:PORT])") + flagSet.Bool("redis-use-sentinel", false, "Connect to redis via sentinels. Must set --redis-sentinel-master-name and --redis-sentinel-conneciton-urls to use this feature") + flagSet.String("redis-sentinel-master-name", "", "Redis sentinel master name. Used in conjuction with --redis-use-sentinel") + flagSet.Var(&redisSentinelConnectionURLs, "redis-sentinel-connection-urls", "List of Redis sentinel conneciton URLs (eg redis://HOST[:PORT]). Used in conjuction with --redis-use-sentinel") flagSet.String("logging-filename", "", "File to log requests to, empty for stdout") flagSet.Int("logging-max-size", 100, "Maximum size in megabytes of the log file before rotation") diff --git a/pkg/apis/options/sessions.go b/pkg/apis/options/sessions.go index 6787ec9..c72da3d 100644 --- a/pkg/apis/options/sessions.go +++ b/pkg/apis/options/sessions.go @@ -25,5 +25,8 @@ var RedisSessionStoreType = "redis" // RedisStoreOptions contains configuration options for the RedisSessionStore. type RedisStoreOptions struct { - RedisConnectionURL string `flag:"redis-connection-url" cfg:"redis_connection_url" env:"OAUTH2_PROXY_REDIS_CONNECTION_URL"` + RedisConnectionURL string `flag:"redis-connection-url" cfg:"redis_connection_url" env:"OAUTH2_PROXY_REDIS_CONNECTION_URL"` + UseSentinel bool `flag:"redis-use-sentinel" cfg:"redis_use_sentinel" env:"OAUTH2_PROXY_REDIS_USE_SENTINEL"` + SentinelMasterName string `flag:"redis-sentinel-master-name" cfg:"redis_sentinel_master_name" env:"OAUTH2_PROXY_REDIS_SENTINEL_MASTER_NAME"` + SentinelConnectionURLs []string `flag:"redis-sentinel-connection-urls" cfg:"redis_sentinel_connection_urls" env:"OAUTH2_PROXY_REDIS_SENTINEL_CONNECTION_URLS"` } diff --git a/pkg/sessions/redis/redis_store.go b/pkg/sessions/redis/redis_store.go index c55e9c7..61aa1c7 100644 --- a/pkg/sessions/redis/redis_store.go +++ b/pkg/sessions/redis/redis_store.go @@ -36,13 +36,11 @@ type SessionStore struct { // NewRedisSessionStore initialises a new instance of the SessionStore from // the configuration given func NewRedisSessionStore(opts *options.SessionOptions, cookieOpts *options.CookieOptions) (sessions.SessionStore, error) { - opt, err := redis.ParseURL(opts.RedisStoreOptions.RedisConnectionURL) + client, err := newRedisClient(opts.RedisStoreOptions) if err != nil { - return nil, fmt.Errorf("unable to parse redis url: %s", err) + return nil, fmt.Errorf("error constructing redis client: %v", err) } - client := redis.NewClient(opt) - rs := &SessionStore{ Client: client, CookieCipher: opts.Cipher, @@ -52,6 +50,24 @@ func NewRedisSessionStore(opts *options.SessionOptions, cookieOpts *options.Cook } +func newRedisClient(opts options.RedisStoreOptions) (*redis.Client, error) { + if opts.UseSentinel { + client := redis.NewFailoverClient(&redis.FailoverOptions{ + MasterName: opts.SentinelMasterName, + SentinelAddrs: opts.SentinelConnectionURLs, + }) + return client, nil + } + + opt, err := redis.ParseURL(opts.RedisConnectionURL) + if err != nil { + return nil, fmt.Errorf("unable to parse redis url: %s", err) + } + + client := redis.NewClient(opt) + return client, nil +} + // Save takes a sessions.SessionState and stores the information from it // to redies, and adds a new ticket cookie on the HTTP response writer func (store *SessionStore) Save(rw http.ResponseWriter, req *http.Request, s *sessions.SessionState) error {