mirror of
https://github.com/oauth2-proxy/oauth2-proxy.git
synced 2025-06-06 23:46:28 +02:00
Merge pull request #1403 from openstandia/fix-redis-tls
Improve TLS handling for Redis to support non-standalone mode with TLS
This commit is contained in:
commit
d82c268696
@ -48,6 +48,7 @@
|
|||||||
- [#997](https://github.com/oauth2-proxy/oauth2-proxy/pull/997) Allow passing the raw url path when proxying upstream requests - e.g. /%2F/ (@FStelzer)
|
- [#997](https://github.com/oauth2-proxy/oauth2-proxy/pull/997) Allow passing the raw url path when proxying upstream requests - e.g. /%2F/ (@FStelzer)
|
||||||
- [#1147](https://github.com/oauth2-proxy/oauth2-proxy/pull/1147) Multiarch support for docker image (@goshlanguage)
|
- [#1147](https://github.com/oauth2-proxy/oauth2-proxy/pull/1147) Multiarch support for docker image (@goshlanguage)
|
||||||
- [#1296](https://github.com/oauth2-proxy/oauth2-proxy/pull/1296) Fixed `panic` when connecting to Redis with TLS (@mstrzele)
|
- [#1296](https://github.com/oauth2-proxy/oauth2-proxy/pull/1296) Fixed `panic` when connecting to Redis with TLS (@mstrzele)
|
||||||
|
- [#1403](https://github.com/oauth2-proxy/oauth2-proxy/pull/1403) Improve TLS handling for Redis to support non-standalone mode with TLS (@wadahiro)
|
||||||
|
|
||||||
# V7.1.3
|
# V7.1.3
|
||||||
|
|
||||||
|
@ -89,28 +89,40 @@ func NewRedisClient(opts options.RedisStoreOptions) (Client, error) {
|
|||||||
// buildSentinelClient makes a redis.Client that connects to Redis Sentinel
|
// buildSentinelClient makes a redis.Client that connects to Redis Sentinel
|
||||||
// for Primary/Replica Redis node coordination
|
// for Primary/Replica Redis node coordination
|
||||||
func buildSentinelClient(opts options.RedisStoreOptions) (Client, error) {
|
func buildSentinelClient(opts options.RedisStoreOptions) (Client, error) {
|
||||||
addrs, err := parseRedisURLs(opts.SentinelConnectionURLs)
|
addrs, opt, err := parseRedisURLs(opts.SentinelConnectionURLs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not parse redis urls: %v", err)
|
return nil, fmt.Errorf("could not parse redis urls: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := setupTLSConfig(opts, opt); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
client := redis.NewFailoverClient(&redis.FailoverOptions{
|
client := redis.NewFailoverClient(&redis.FailoverOptions{
|
||||||
MasterName: opts.SentinelMasterName,
|
MasterName: opts.SentinelMasterName,
|
||||||
SentinelAddrs: addrs,
|
SentinelAddrs: addrs,
|
||||||
SentinelPassword: opts.SentinelPassword,
|
SentinelPassword: opts.SentinelPassword,
|
||||||
Password: opts.Password,
|
Password: opts.Password,
|
||||||
|
TLSConfig: opt.TLSConfig,
|
||||||
})
|
})
|
||||||
return newClient(client), nil
|
return newClient(client), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildClusterClient makes a redis.Client that is Redis Cluster aware
|
// buildClusterClient makes a redis.Client that is Redis Cluster aware
|
||||||
func buildClusterClient(opts options.RedisStoreOptions) (Client, error) {
|
func buildClusterClient(opts options.RedisStoreOptions) (Client, error) {
|
||||||
addrs, err := parseRedisURLs(opts.ClusterConnectionURLs)
|
addrs, opt, err := parseRedisURLs(opts.ClusterConnectionURLs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not parse redis urls: %v", err)
|
return nil, fmt.Errorf("could not parse redis urls: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := setupTLSConfig(opts, opt); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
client := redis.NewClusterClient(&redis.ClusterOptions{
|
client := redis.NewClusterClient(&redis.ClusterOptions{
|
||||||
Addrs: addrs,
|
Addrs: addrs,
|
||||||
Password: opts.Password,
|
Password: opts.Password,
|
||||||
|
TLSConfig: opt.TLSConfig,
|
||||||
})
|
})
|
||||||
return newClusterClient(client), nil
|
return newClusterClient(client), nil
|
||||||
}
|
}
|
||||||
@ -127,6 +139,16 @@ func buildStandaloneClient(opts options.RedisStoreOptions) (Client, error) {
|
|||||||
opt.Password = opts.Password
|
opt.Password = opts.Password
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := setupTLSConfig(opts, opt); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := redis.NewClient(opt)
|
||||||
|
return newClient(client), 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 {
|
if opts.InsecureSkipTLSVerify {
|
||||||
if opt.TLSConfig == nil {
|
if opt.TLSConfig == nil {
|
||||||
/* #nosec */
|
/* #nosec */
|
||||||
@ -146,7 +168,7 @@ func buildStandaloneClient(opts options.RedisStoreOptions) (Client, error) {
|
|||||||
}
|
}
|
||||||
certs, err := ioutil.ReadFile(opts.CAPath)
|
certs, err := ioutil.ReadFile(opts.CAPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to load %q, %v", opts.CAPath, err)
|
return fmt.Errorf("failed to load %q, %v", opts.CAPath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append our cert to the system pool
|
// Append our cert to the system pool
|
||||||
@ -161,21 +183,21 @@ func buildStandaloneClient(opts options.RedisStoreOptions) (Client, error) {
|
|||||||
|
|
||||||
opt.TLSConfig.RootCAs = rootCAs
|
opt.TLSConfig.RootCAs = rootCAs
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
client := redis.NewClient(opt)
|
|
||||||
return newClient(client), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseRedisURLs parses a list of redis urls and returns a list
|
// parseRedisURLs parses a list of redis urls and returns a list
|
||||||
// of addresses in the form of host:port that can be used to connect to Redis
|
// of addresses in the form of host:port and redis.Options that can be used to connect to Redis
|
||||||
func parseRedisURLs(urls []string) ([]string, error) {
|
func parseRedisURLs(urls []string) ([]string, *redis.Options, error) {
|
||||||
addrs := []string{}
|
addrs := []string{}
|
||||||
|
var redisOptions *redis.Options
|
||||||
for _, u := range urls {
|
for _, u := range urls {
|
||||||
parsedURL, err := redis.ParseURL(u)
|
parsedURL, err := redis.ParseURL(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to parse redis url: %v", err)
|
return nil, nil, fmt.Errorf("unable to parse redis url: %v", err)
|
||||||
}
|
}
|
||||||
addrs = append(addrs, parsedURL.Addr)
|
addrs = append(addrs, parsedURL.Addr)
|
||||||
|
redisOptions = parsedURL
|
||||||
}
|
}
|
||||||
return addrs, nil
|
return addrs, redisOptions, nil
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,35 @@ func TestSessionStore(t *testing.T) {
|
|||||||
RunSpecs(t, "Redis SessionStore")
|
RunSpecs(t, "Redis SessionStore")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
cert tls.Certificate
|
||||||
|
caPath string
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = BeforeSuite(func() {
|
||||||
|
var err error
|
||||||
|
certBytes, keyBytes, err := util.GenerateCert()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
certOut := new(bytes.Buffer)
|
||||||
|
Expect(pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes})).To(Succeed())
|
||||||
|
certData := certOut.Bytes()
|
||||||
|
keyOut := new(bytes.Buffer)
|
||||||
|
Expect(pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes})).To(Succeed())
|
||||||
|
cert, err = tls.X509KeyPair(certData, keyOut.Bytes())
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
certFile, err := os.CreateTemp("", "cert.*.pem")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
caPath = certFile.Name()
|
||||||
|
_, err = certFile.Write(certData)
|
||||||
|
defer certFile.Close()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
var _ = AfterSuite(func() {
|
||||||
|
Expect(os.Remove(caPath)).ToNot(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
var _ = Describe("Redis SessionStore Tests", func() {
|
var _ = Describe("Redis SessionStore Tests", func() {
|
||||||
// helper interface to allow us to close client connections
|
// helper interface to allow us to close client connections
|
||||||
// All non-nil redis clients should implement this
|
// All non-nil redis clients should implement this
|
||||||
@ -229,36 +258,130 @@ var _ = Describe("Redis SessionStore Tests", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Context("with custom CA path", func() {
|
Context("with TLS connection", func() {
|
||||||
var caPath string
|
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
certBytes, keyBytes, err := util.GenerateCert()
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
certOut := new(bytes.Buffer)
|
|
||||||
Expect(pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes})).To(Succeed())
|
|
||||||
certData := certOut.Bytes()
|
|
||||||
keyOut := new(bytes.Buffer)
|
|
||||||
Expect(pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes})).To(Succeed())
|
|
||||||
cert, err := tls.X509KeyPair(certData, keyOut.Bytes())
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
|
|
||||||
certFile, err := os.CreateTemp("", "cert.*.pem")
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
caPath = certFile.Name()
|
|
||||||
_, err = certFile.Write(certData)
|
|
||||||
defer certFile.Close()
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
|
|
||||||
mr.Close()
|
mr.Close()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
mr, err = miniredis.RunTLS(&tls.Config{Certificates: []tls.Certificate{cert}})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
})
|
||||||
|
AfterEach(func() {
|
||||||
|
mr.Close()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
mr, err = miniredis.Run()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("with standalone", func() {
|
||||||
|
tests.RunSessionStoreTests(
|
||||||
|
func(opts *options.SessionOptions, cookieOpts *options.Cookie) (sessionsapi.SessionStore, error) {
|
||||||
|
// Set the connection URL
|
||||||
|
opts.Type = options.RedisSessionStoreType
|
||||||
|
opts.Redis.ConnectionURL = "rediss://" + mr.Addr()
|
||||||
|
opts.Redis.CAPath = caPath
|
||||||
|
|
||||||
|
// Capture the session store so that we can close the client
|
||||||
|
ss, err := NewRedisSessionStore(opts, cookieOpts)
|
||||||
|
return ss, err
|
||||||
|
},
|
||||||
|
func(d time.Duration) error {
|
||||||
|
mr.FastForward(d)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("with cluster", func() {
|
||||||
|
tests.RunSessionStoreTests(
|
||||||
|
func(opts *options.SessionOptions, cookieOpts *options.Cookie) (sessionsapi.SessionStore, error) {
|
||||||
|
clusterAddr := "rediss://" + mr.Addr()
|
||||||
|
opts.Type = options.RedisSessionStoreType
|
||||||
|
opts.Redis.ClusterConnectionURLs = []string{clusterAddr}
|
||||||
|
opts.Redis.UseCluster = true
|
||||||
|
opts.Redis.CAPath = caPath
|
||||||
|
|
||||||
|
// Capture the session store so that we can close the client
|
||||||
|
var err error
|
||||||
|
ss, err = NewRedisSessionStore(opts, cookieOpts)
|
||||||
|
return ss, err
|
||||||
|
},
|
||||||
|
func(d time.Duration) error {
|
||||||
|
mr.FastForward(d)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("with insecure TLS connection", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
mr.Close()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
mr, err = miniredis.RunTLS(&tls.Config{Certificates: []tls.Certificate{cert}})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
})
|
||||||
|
AfterEach(func() {
|
||||||
|
mr.Close()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
mr, err = miniredis.Run()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("with standalone", func() {
|
||||||
|
tests.RunSessionStoreTests(
|
||||||
|
func(opts *options.SessionOptions, cookieOpts *options.Cookie) (sessionsapi.SessionStore, error) {
|
||||||
|
// Set the connection URL
|
||||||
|
opts.Type = options.RedisSessionStoreType
|
||||||
|
opts.Redis.ConnectionURL = "rediss://" + mr.Addr()
|
||||||
|
opts.Redis.InsecureSkipTLSVerify = true
|
||||||
|
|
||||||
|
// Capture the session store so that we can close the client
|
||||||
|
ss, err := NewRedisSessionStore(opts, cookieOpts)
|
||||||
|
return ss, err
|
||||||
|
},
|
||||||
|
func(d time.Duration) error {
|
||||||
|
mr.FastForward(d)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("with cluster", func() {
|
||||||
|
tests.RunSessionStoreTests(
|
||||||
|
func(opts *options.SessionOptions, cookieOpts *options.Cookie) (sessionsapi.SessionStore, error) {
|
||||||
|
clusterAddr := "rediss://" + mr.Addr()
|
||||||
|
opts.Type = options.RedisSessionStoreType
|
||||||
|
opts.Redis.ClusterConnectionURLs = []string{clusterAddr}
|
||||||
|
opts.Redis.UseCluster = true
|
||||||
|
opts.Redis.InsecureSkipTLSVerify = true
|
||||||
|
|
||||||
|
// Capture the session store so that we can close the client
|
||||||
|
var err error
|
||||||
|
ss, err = NewRedisSessionStore(opts, cookieOpts)
|
||||||
|
return ss, err
|
||||||
|
},
|
||||||
|
func(d time.Duration) error {
|
||||||
|
mr.FastForward(d)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("with custom CA path", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
mr.Close()
|
||||||
|
|
||||||
|
var err error
|
||||||
mr, err = miniredis.RunTLS(&tls.Config{Certificates: []tls.Certificate{cert}})
|
mr, err = miniredis.RunTLS(&tls.Config{Certificates: []tls.Certificate{cert}})
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
AfterEach(func() {
|
AfterEach(func() {
|
||||||
Expect(os.Remove(caPath)).ToNot(HaveOccurred())
|
|
||||||
|
|
||||||
mr.Close()
|
mr.Close()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@ -287,17 +410,9 @@ var _ = Describe("Redis SessionStore Tests", func() {
|
|||||||
|
|
||||||
Context("with insecure TLS connection", func() {
|
Context("with insecure TLS connection", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
certBytes, keyBytes, err := util.GenerateCert()
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
certOut := new(bytes.Buffer)
|
|
||||||
Expect(pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes})).To(Succeed())
|
|
||||||
keyOut := new(bytes.Buffer)
|
|
||||||
Expect(pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes})).To(Succeed())
|
|
||||||
cert, err := tls.X509KeyPair(certOut.Bytes(), keyOut.Bytes())
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
|
|
||||||
mr.Close()
|
mr.Close()
|
||||||
|
|
||||||
|
var err error
|
||||||
mr, err = miniredis.RunTLS(&tls.Config{Certificates: []tls.Certificate{cert}})
|
mr, err = miniredis.RunTLS(&tls.Config{Certificates: []tls.Certificate{cert}})
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user