Merge f7f52a577e into 9168731c7a
This commit is contained in:
commit
f80fd11fbd
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
## Changes since v7.12.0
|
||||
|
||||
- [#3029](https://github.com/oauth2-proxy/oauth2-proxy/pull/3029) feat: IAM auth for AWS redis (@willwill96)
|
||||
|
||||
# V7.12.0
|
||||
|
||||
## Release Highlights
|
||||
|
|
@ -119,7 +121,7 @@ For detailed information, migration guidance, and security implications, see the
|
|||
- 🕵️♀️ Vulnerabilities have been addressed
|
||||
- [CVE-2025-22871](https://github.com/advisories/GHSA-g9pc-8g42-g6vq)
|
||||
- 🐛 Squashed some bugs
|
||||
|
||||
|
||||
## Important Notes
|
||||
|
||||
## Breaking Changes
|
||||
|
|
|
|||
|
|
@ -150,6 +150,18 @@ You must remove these options before starting OAuth2 Proxy with `--alpha-config`
|
|||
| ----- | ---- | ----------- |
|
||||
| `skipScope` | _bool_ | Skip adding the scope parameter in login request<br/>Default value is 'false' |
|
||||
|
||||
### AWSIAMConfig
|
||||
|
||||
(**Appears on:** [AlphaOptions](#alphaoptions))
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| `serviceName` | _string_ | AWS service redis service being used. "elasticache" or "memorydb" |
|
||||
| `clusterName` | _string_ | AWS Cluster name |
|
||||
| `userName` | _string_ | AWS Username |
|
||||
|
||||
### AlphaOptions
|
||||
|
||||
AlphaOptions contains alpha structured configuration options.
|
||||
|
|
@ -169,6 +181,7 @@ They may change between releases without notice.
|
|||
| `server` | _[Server](#server)_ | Server is used to configure the HTTP(S) server for the proxy application.<br/>You may choose to run both HTTP and HTTPS servers simultaneously.<br/>This can be done by setting the BindAddress and the SecureBindAddress simultaneously.<br/>To use the secure server you must configure a TLS certificate and key. |
|
||||
| `metricsServer` | _[Server](#server)_ | MetricsServer is used to configure the HTTP(S) server for metrics.<br/>You may choose to run both HTTP and HTTPS servers simultaneously.<br/>This can be done by setting the BindAddress and the SecureBindAddress simultaneously.<br/>To use the secure server you must configure a TLS certificate and key. |
|
||||
| `providers` | _[Providers](#providers)_ | Providers is used to configure your provider. **Multiple-providers is not<br/>yet working.** [This feature is tracked in<br/>#925](https://github.com/oauth2-proxy/oauth2-proxy/issues/926) |
|
||||
| `redisSessionAWSIAMConfig` | _[AWSIAMConfig](#awsiamconfig)_ | AWS IAM Options is used to configure IAM authentication for your redis instance. |
|
||||
|
||||
### AzureOptions
|
||||
|
||||
|
|
|
|||
14
go.mod
14
go.mod
|
|
@ -45,6 +45,20 @@ require (
|
|||
require (
|
||||
cloud.google.com/go/auth v0.16.2 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 // indirect
|
||||
github.com/aws/smithy-go v1.22.2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
|
|
|
|||
36
go.sum
36
go.sum
|
|
@ -14,6 +14,42 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGn
|
|||
github.com/alicebob/miniredis/v2 v2.11.1/go.mod h1:UA48pmi7aSazcGAvcdKcBB49z521IC9VjTTRz2nIaJE=
|
||||
github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI=
|
||||
github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.9 h1:Kg+fAYNaJeGXp1vmjtidss8O2uXIsXwaRqsQJKXVr+0=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.9/go.mod h1:oU3jj2O53kgOU4TXq/yipt6ryiooYjlkqqVaZk7gY/U=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14 h1:f+eEi/2cKCg9pqKBoAIwRGzVb70MRKqWX4dg1BDcSJM=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14/go.mod h1:wVPHWcIFv3WO89w0rE10gzf17ZYy+UVS1Geq8Iei34g=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.62 h1:fvtQY3zFzYJ9CfixuAQ96IxDrBajbBWGqjNTCa79ocU=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.62/go.mod h1:ElETBxIQqcxej++Cs8GyPBbgMys5DgQPTwo7cUPDKt8=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67 h1:9KxtdcIA/5xPNQyZRgUSpYOE6j9Bc4+D7nZua0KGYOM=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67/go.mod h1:p3C44m+cfnbv763s52gCqrjaqyPikj9Sg47kUVaNZQQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 h1:8JdC7Gr9NROg1Rusk25IcZeTO59zLxsKgE0gkh5O6h0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.1/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 h1:1Gw+9ajCV1jogloEv1RRnvfRFia2cL6c9cuKV2Ps+G8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1 h1:KwuLovgQPcdjNMfFt9OhUd9a2OwcOKhxfvF4glTzLuA=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 h1:hXmVKytPfTy5axZ+fYbR5d0cFmC3JvwLm5kM83luako=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 h1:PZV5W8yk4OtH1JAuhV2PXwwO9v5G5Aoj+eMCn4T+1Kc=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.17/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 h1:1XuUZ8mYJw9B6lzAkXhqHlJd/XvaX32evhproijJEZY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4=
|
||||
github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ=
|
||||
github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
|
||||
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
|
||||
github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
RedisSessionAWSIAMConfig *AWSIAMConfig `json:"redisSessionAWSIAMConfig,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.RedisSessionAWSIAMConfig
|
||||
}
|
||||
|
||||
// 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.RedisSessionAWSIAMConfig = opts.Session.Redis.AWSIAMConfig
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
package options
|
||||
|
||||
type AWSIAMConfig 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"`
|
||||
}
|
||||
|
|
@ -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")
|
||||
|
||||
|
|
|
|||
|
|
@ -22,18 +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"`
|
||||
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 *AWSIAMConfig `cfg:",internal"`
|
||||
}
|
||||
|
||||
func sessionOptionsDefaults() SessionOptions {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,105 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
|
||||
"github.com/aws/aws-sdk-go-v2/config"
|
||||
)
|
||||
|
||||
// This code was largely copied from this repo: https://github.com/build-on-aws/aws-redis-iam-auth-golang/tree/main
|
||||
|
||||
const (
|
||||
// "The IAM authentication token is valid for 15 minutes"
|
||||
// https://docs.aws.amazon.com/memorydb/latest/devguide/auth-iam.html#auth-iam-limits
|
||||
tokenValiditySeconds = 900
|
||||
|
||||
connectAction = "connect"
|
||||
|
||||
// If the request has no payload you should use the hex encoded SHA-256 of an empty string as the payloadHash value.
|
||||
hexEncodedSHA256EmptyString = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
)
|
||||
|
||||
type TokenGenerator interface {
|
||||
GenerateToken() (string, error)
|
||||
}
|
||||
|
||||
// IAMTokenGenerator generates an IAM token for AWS Redis authentication.
|
||||
type iamTokenGenerator struct {
|
||||
serviceName string
|
||||
region string
|
||||
req *http.Request
|
||||
|
||||
credentialsProvider aws.CredentialsProvider
|
||||
signer *v4.Signer
|
||||
}
|
||||
|
||||
// New creates a new IAMTokenGenerator instance
|
||||
func New(serviceName, clusterName, userName string) (TokenGenerator, error) {
|
||||
|
||||
ctx := context.Background()
|
||||
cfg, err := config.LoadDefaultConfig(ctx)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
queryParams := url.Values{
|
||||
"Action": {connectAction},
|
||||
"User": {userName},
|
||||
"X-Amz-Expires": {strconv.FormatInt(int64(tokenValiditySeconds), 10)},
|
||||
}
|
||||
|
||||
authURL := url.URL{
|
||||
Host: clusterName,
|
||||
Scheme: "http",
|
||||
Path: "/",
|
||||
RawQuery: queryParams.Encode(),
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, authURL.String(), nil)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &iamTokenGenerator{
|
||||
serviceName: serviceName,
|
||||
region: cfg.Region,
|
||||
req: req,
|
||||
credentialsProvider: cfg.Credentials,
|
||||
signer: v4.NewSigner(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (atg iamTokenGenerator) GenerateToken() (string, error) {
|
||||
ctx := context.Background()
|
||||
credentials, err := atg.credentialsProvider.Retrieve(ctx)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("AWS IAM credentials retrieval failed - %v", err)
|
||||
}
|
||||
signedURL, _, err := atg.signer.PresignHTTP(
|
||||
ctx,
|
||||
credentials,
|
||||
atg.req,
|
||||
hexEncodedSHA256EmptyString,
|
||||
atg.serviceName,
|
||||
atg.region,
|
||||
time.Now().UTC(),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("AWS IAM request signing failed - %v", err)
|
||||
}
|
||||
// AWS expects the scheme to be removed before using as an auth token
|
||||
// https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/auth-iam.html#auth-iam-Connecting
|
||||
signedURL = strings.Replace(signedURL, "http://", "", 1)
|
||||
|
||||
return signedURL, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAWSIAMTokenGenerator(t *testing.T) {
|
||||
// Set up the environment, so we don't make any external calls to AWS
|
||||
t.Setenv("AWS_CONFIG_FILE", "file_not_exists")
|
||||
t.Setenv("AWS_SHARED_CREDENTIALS_FILE", "file_not_exists")
|
||||
t.Setenv("AWS_ENDPOINT_URL", "http://localhost:9999/aws")
|
||||
t.Setenv("AWS_ACCESS_KEY_ID", "access_key")
|
||||
t.Setenv("AWS_SECRET_ACCESS_KEY", "secret_key")
|
||||
t.Setenv("AWS_REGION", "us-east-1")
|
||||
|
||||
tokenGenerator, err := New("elasticache", "test-cluster", "test-user")
|
||||
require.NotNil(t, tokenGenerator)
|
||||
require.NoError(t, err)
|
||||
|
||||
token, err := tokenGenerator.GenerateToken()
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, token)
|
||||
require.Contains(t, token, "X-Amz-Algorithm", "signed token should contain algorithm attribute")
|
||||
require.Contains(t, token, "User=test-user", "signed token should contain user parameter")
|
||||
require.Contains(t, token, "X-Amz-Credential", "signed token should contain credential attribute")
|
||||
require.Contains(t, token, "X-Amz-Date", "signed token should contain date attribute")
|
||||
require.Contains(t, token, "X-Amz-Expires", "signed token should contain expires attribute")
|
||||
require.Contains(t, token, "X-Amz-SignedHeaders", "signed token should contain signed headers attribute")
|
||||
require.Contains(t, token, "X-Amz-Signature", "signed token should contain signature attribute")
|
||||
require.Contains(t, token, "Action=connect", "signed token should contain connect action")
|
||||
require.False(t, strings.HasPrefix(token, "http://"), "token should not have http:// scheme")
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/persistence"
|
||||
auth "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/redis/aws-iam"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
|
|
@ -173,12 +174,39 @@ func buildStandaloneClient(opts options.RedisStoreOptions) (Client, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := setupAWSIAMAuth(opts, opt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opt.ConnMaxIdleTime = time.Duration(opts.IdleTimeout) * time.Second
|
||||
|
||||
client := redis.NewClient(opt)
|
||||
return newClient(client), nil
|
||||
}
|
||||
|
||||
func setupAWSIAMAuth(opts options.RedisStoreOptions, opt *redis.Options) error {
|
||||
if opts.AWSIAMConfig == nil {
|
||||
return nil
|
||||
}
|
||||
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.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.GenerateToken()
|
||||
if err != nil {
|
||||
logger.Errorf("error generating AWS IAM auth token: %v", err)
|
||||
}
|
||||
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
|
||||
return nil
|
||||
}
|
||||
|
||||
// setupTLSConfig sets the TLSConfig if the TLS option is given in redis.Options
|
||||
func setupTLSConfig(opts options.RedisStoreOptions, opt *redis.Options) error {
|
||||
if opts.InsecureSkipTLSVerify {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/tests"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -271,4 +272,39 @@ var _ = Describe("Redis SessionStore Tests", func() {
|
|||
Expect(opts).To(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("AWSIAMAuth", func() {
|
||||
Context("with AWS IAM options", func() {
|
||||
It("should initialize CredentialsProvider when AWSIAMConfig is present", func() {
|
||||
redisOpts := options.RedisStoreOptions{
|
||||
AWSIAMConfig: &options.AWSIAMConfig{
|
||||
ServiceName: "elasticache",
|
||||
ClusterName: "test-cluster",
|
||||
Username: "test-user",
|
||||
},
|
||||
}
|
||||
|
||||
var opt = &redis.Options{}
|
||||
|
||||
err := setupAWSIAMAuth(redisOpts, opt)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(opt.CredentialsProvider).ToNot(BeNil())
|
||||
|
||||
username, _ := opt.CredentialsProvider()
|
||||
Expect(username).To(Equal("test-user"))
|
||||
})
|
||||
It("should not initialize CredentialsProvider when AWSIAMConfig is nil", func() {
|
||||
redisOpts := options.RedisStoreOptions{
|
||||
AWSIAMConfig: nil,
|
||||
}
|
||||
|
||||
var opt = &redis.Options{}
|
||||
|
||||
err := setupAWSIAMAuth(redisOpts, opt)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(opt.CredentialsProvider).To(BeNil())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue