diff --git a/pkg/apis/options/alpha_options.go b/pkg/apis/options/alpha_options.go index a438518c..b40d650b 100644 --- a/pkg/apis/options/alpha_options.go +++ b/pkg/apis/options/alpha_options.go @@ -45,6 +45,9 @@ type AlphaOptions struct { // yet working.** [This feature is tracked in // #925](https://github.com/oauth2-proxy/oauth2-proxy/issues/926) Providers Providers `json:"providers,omitempty"` + + // AWS IAM Options is used to configure IAM authentication for your redis instance. + AWSIAMOptions *AWSIAMOptions `json:"awsIAM,omitempty"` } // MergeInto replaces alpha options in the Options struct with the values @@ -56,6 +59,7 @@ func (a *AlphaOptions) MergeInto(opts *Options) { opts.Server = a.Server opts.MetricsServer = a.MetricsServer opts.Providers = a.Providers + opts.Session.Redis.AWSIAMConfig = a.AWSIAMOptions } // ExtractFrom populates the fields in the AlphaOptions with the values from @@ -67,4 +71,5 @@ func (a *AlphaOptions) ExtractFrom(opts *Options) { a.Server = opts.Server a.MetricsServer = opts.MetricsServer a.Providers = opts.Providers + a.AWSIAMOptions = opts.Session.Redis.AWSIAMConfig } diff --git a/pkg/apis/options/aws_iam.go b/pkg/apis/options/aws_iam.go new file mode 100644 index 00000000..01093b45 --- /dev/null +++ b/pkg/apis/options/aws_iam.go @@ -0,0 +1,10 @@ +package options + +type AWSIAMOptions struct { + // AWS service redis service being used. "elasticache" or "memorydb" + ServiceName string `json:"serviceName,omitempty` + // AWS Cluster name + ClusterName string `json:"clusterName,omitempty` + // AWS Username + Username string `json:"userName,omitempty` +} diff --git a/pkg/apis/options/options.go b/pkg/apis/options/options.go index 8fa72c7c..9e4b6369 100644 --- a/pkg/apis/options/options.go +++ b/pkg/apis/options/options.go @@ -159,6 +159,7 @@ func NewFlagSet() *pflag.FlagSet { flagSet.Bool("redis-use-cluster", false, "Connect to redis cluster. Must set --redis-cluster-connection-urls to use this feature") flagSet.StringSlice("redis-cluster-connection-urls", []string{}, "List of Redis cluster connection URLs (eg redis://[USER[:PASSWORD]@]HOST[:PORT]). Used in conjunction with --redis-use-cluster") flagSet.Int("redis-connection-idle-timeout", 0, "Redis connection idle timeout seconds, if Redis timeout option is non-zero, the --redis-connection-idle-timeout must be less then Redis timeout option") + flagSet.String("signature-key", "", "GAP-Signature request signature key (algorithm:secretkey)") flagSet.Bool("gcp-healthchecks", false, "Enable GCP/GKE healthcheck endpoints") diff --git a/pkg/apis/options/sessions.go b/pkg/apis/options/sessions.go index 86b0d9b8..4fd8d59f 100644 --- a/pkg/apis/options/sessions.go +++ b/pkg/apis/options/sessions.go @@ -22,22 +22,19 @@ type CookieStoreOptions struct { // RedisStoreOptions contains configuration options for the RedisSessionStore. type RedisStoreOptions struct { - ConnectionURL string `flag:"redis-connection-url" cfg:"redis_connection_url"` - Username string `flag:"redis-username" cfg:"redis_username"` - Password string `flag:"redis-password" cfg:"redis_password"` - UseSentinel bool `flag:"redis-use-sentinel" cfg:"redis_use_sentinel"` - SentinelPassword string `flag:"redis-sentinel-password" cfg:"redis_sentinel_password"` - SentinelMasterName string `flag:"redis-sentinel-master-name" cfg:"redis_sentinel_master_name"` - SentinelConnectionURLs []string `flag:"redis-sentinel-connection-urls" cfg:"redis_sentinel_connection_urls"` - UseCluster bool `flag:"redis-use-cluster" cfg:"redis_use_cluster"` - UseAWSIAMAuth bool `cfg:"redis_aws_use_iam_auth"` - AWSServiceName string `cfg:"redis_aws_service_name"` - AWSClusterName string `cfg:"redis_aws_cluster_name"` - AWSUsername string `cfg:"redis_aws_username"` - ClusterConnectionURLs []string `flag:"redis-cluster-connection-urls" cfg:"redis_cluster_connection_urls"` - CAPath string `flag:"redis-ca-path" cfg:"redis_ca_path"` - InsecureSkipTLSVerify bool `flag:"redis-insecure-skip-tls-verify" cfg:"redis_insecure_skip_tls_verify"` - IdleTimeout int `flag:"redis-connection-idle-timeout" cfg:"redis_connection_idle_timeout"` + ConnectionURL string `flag:"redis-connection-url" cfg:"redis_connection_url"` + Username string `flag:"redis-username" cfg:"redis_username"` + Password string `flag:"redis-password" cfg:"redis_password"` + UseSentinel bool `flag:"redis-use-sentinel" cfg:"redis_use_sentinel"` + SentinelPassword string `flag:"redis-sentinel-password" cfg:"redis_sentinel_password"` + SentinelMasterName string `flag:"redis-sentinel-master-name" cfg:"redis_sentinel_master_name"` + SentinelConnectionURLs []string `flag:"redis-sentinel-connection-urls" cfg:"redis_sentinel_connection_urls"` + UseCluster bool `flag:"redis-use-cluster" cfg:"redis_use_cluster"` + ClusterConnectionURLs []string `flag:"redis-cluster-connection-urls" cfg:"redis_cluster_connection_urls"` + CAPath string `flag:"redis-ca-path" cfg:"redis_ca_path"` + InsecureSkipTLSVerify bool `flag:"redis-insecure-skip-tls-verify" cfg:"redis_insecure_skip_tls_verify"` + IdleTimeout int `flag:"redis-connection-idle-timeout" cfg:"redis_connection_idle_timeout"` + AWSIAMConfig *AWSIAMOptions `cfg:",internal"` } func sessionOptionsDefaults() SessionOptions { diff --git a/pkg/sessions/redis/aws-iam/auth.go b/pkg/sessions/redis/aws-iam/auth.go index 526a8069..b2387abf 100644 --- a/pkg/sessions/redis/aws-iam/auth.go +++ b/pkg/sessions/redis/aws-iam/auth.go @@ -27,8 +27,12 @@ const ( hexEncodedSHA256EmptyString = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" ) +type TokenGenerator interface { + GenerateToken() (string, error) +} + // IAMTokenGenerator generates an IAM token for AWS Redis authentication. -type IAMTokenGenerator interface { +type iamTokenGenerator struct { serviceName string region string req *http.Request @@ -65,7 +69,7 @@ func New(serviceName, clusterName, userName string) (*IAMTokenGenerator, error) return nil, err } - return &IAMTokenGenerator{ + return &iamTokenGenerator{ serviceName: serviceName, region: cfg.Region, req: req, @@ -74,7 +78,7 @@ func New(serviceName, clusterName, userName string) (*IAMTokenGenerator, error) }, nil } -func (atg IAMTokenGenerator) Generate() (string, error) { +func (atg iamTokenGenerator) GenerateToken() (string, error) { ctx := context.Background() credentials, err := atg.credentialsProvider.Retrieve(ctx) if err != nil { diff --git a/pkg/sessions/redis/redis_store.go b/pkg/sessions/redis/redis_store.go index c1daaec2..a9775740 100644 --- a/pkg/sessions/redis/redis_store.go +++ b/pkg/sessions/redis/redis_store.go @@ -185,22 +185,22 @@ func buildStandaloneClient(opts options.RedisStoreOptions) (Client, error) { } func setupAWSIAMAuth(opts options.RedisStoreOptions, opt *redis.Options) error { - if !opts.UseAWSIAMAuth { + if opts.AWSIAMConfig == nil { return nil } - if opts.AWSServiceName != "elasticache" && opts.AWSServiceName != "memorydb" { + if opts.AWSIAMConfig.ServiceName != "elasticache" && opts.AWSIAMConfig.ServiceName != "memorydb" { return fmt.Errorf("AWS IAM auth is only supported for elasticache and memorydb") } - generator, err := auth.New(opts.AWSServiceName, opts.AWSClusterName, opts.AWSUsername) + generator, err := auth.New(opts.AWSIAMConfig.ServiceName, opts.AWSIAMConfig.ClusterName, opts.AWSIAMConfig.Username) if err != nil { return fmt.Errorf("error creating AWS IAM auth token generator: %v", err) } opt.CredentialsProvider = func() (username string, password string) { - token, err := generator.Generate() + token, err := generator.GenerateToken() if err != nil { logger.Errorf("error generating AWS IAM auth token: %v", err) } - return opts.AWSUsername, token + return opts.AWSIAMConfig.Username, token } // AWS services has a max connection lifetime of 12 hours. This is set to 11 hours to give some buffer time opt.ConnMaxLifetime = 11 * time.Hour