-
Notifications
You must be signed in to change notification settings - Fork 2.6k
chore(tests): Add comprehensive TLS tests and example #3681
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 4 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
0f7c6b4
chore(tests): add tls tests
ndyakov 8eb85c9
fix: Use ShardPicker for keyless commands instead of random slot
ndyakov e1c44f9
Merge branch 'master' into ndyakov/tls-tests
ndyakov 02fb923
Merge branch 'master' into ndyakov/tls-tests
ndyakov e54368e
chore(image): update clients-test-lib image
ndyakov a486876
chore(tests): enable tls user auth test
ndyakov d3083b3
chore(docker): use proper envs for test image
ndyakov f8e04f9
chore(image): use latest build
ndyakov 0622456
chore(image): use latest build
ndyakov 1e009fa
fix(tests): use the correct root cert
ndyakov d6bb808
feat(tls): add example app
ndyakov a406ce2
chore(docker): address pr comments
ndyakov 423d905
chore(tests): address pr comments
ndyakov 9433bf6
chore(doc): add README.md in the example app
ndyakov 1c605ad
fix(tests): do not skip tests
ndyakov db44d7e
fix(tests): skip only because of redis version
ndyakov 7c8238b
Extracts default image name in a var (including osscluster-tls)
elena-kolevska b32cb82
fix(tlstests): remove redundent test
ndyakov 9a5effe
Merge branch 'master' into ndyakov/tls-tests
ndyakov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| # TLS Connection Examples | ||
|
|
||
| Shows different ways to connect to Redis over TLS. | ||
|
|
||
| ## Running | ||
|
|
||
| Start Redis with TLS: | ||
|
|
||
| ```shell | ||
| cd ../.. | ||
| docker compose --profile standalone up -d | ||
| ``` | ||
|
|
||
| Then run the example: | ||
|
|
||
| ```shell | ||
| go run . | ||
| ``` | ||
|
|
||
| ## Connection Methods | ||
|
|
||
| ### 1. InsecureSkipVerify (for testing) | ||
|
|
||
| Quick way to test with self-signed certs: | ||
|
|
||
| ```go | ||
| client := redis.NewClient(&redis.Options{ | ||
| Addr: "localhost:6666", | ||
| TLSConfig: &tls.Config{ | ||
| InsecureSkipVerify: true, | ||
| }, | ||
| }) | ||
| ``` | ||
|
|
||
| Don't use this in production. | ||
|
|
||
| ### 2. With CA certificate | ||
|
|
||
| Proper way for production: | ||
|
|
||
| ```go | ||
| caCert, _ := os.ReadFile("path/to/ca.crt") | ||
| caCertPool := x509.NewCertPool() | ||
| caCertPool.AppendCertsFromPEM(caCert) | ||
|
|
||
| client := redis.NewClient(&redis.Options{ | ||
| Addr: "localhost:6666", | ||
| TLSConfig: &tls.Config{ | ||
| RootCAs: caCertPool, | ||
| ServerName: "localhost", | ||
| }, | ||
| }) | ||
| ``` | ||
|
|
||
| ### 3. Mutual TLS | ||
|
|
||
| If Redis requires client certs: | ||
|
|
||
| ```go | ||
| caCert, _ := os.ReadFile("path/to/ca.crt") | ||
| caCertPool := x509.NewCertPool() | ||
| caCertPool.AppendCertsFromPEM(caCert) | ||
|
|
||
| cert, _ := tls.LoadX509KeyPair("path/to/client.crt", "path/to/client.key") | ||
|
|
||
| client := redis.NewClient(&redis.Options{ | ||
| Addr: "localhost:6666", | ||
| TLSConfig: &tls.Config{ | ||
| RootCAs: caCertPool, | ||
| Certificates: []tls.Certificate{cert}, | ||
| ServerName: "localhost", | ||
| }, | ||
| }) | ||
| ``` | ||
|
|
||
| ### 4. Using rediss:// URL | ||
|
|
||
| ```go | ||
| opt, _ := redis.ParseURL("rediss://localhost:6666") | ||
| opt.TLSConfig = &tls.Config{ | ||
| InsecureSkipVerify: true, // for testing only | ||
| } | ||
| client := redis.NewClient(opt) | ||
| ``` | ||
|
|
||
| ### 5. Certificate-based auth | ||
|
|
||
| Redis 6.2+ can authenticate users based on the certificate CN field. You need to configure Redis with: | ||
|
|
||
| ``` | ||
| tls-auth-clients optional | ||
| tls-auth-clients-user CN | ||
| ``` | ||
|
|
||
| Then the CN in your client cert becomes your username - no password needed. | ||
|
|
||
| Check `../../tls_cert_auth_test.go` for a working example that: | ||
| - Generates a client cert with a specific CN | ||
| - Connects to Redis with that cert | ||
| - Verifies auth based on the CN | ||
|
|
||
| Note: Current Redis test build doesn't support this yet, so the test skips gracefully. | ||
|
|
||
| ## Tests | ||
|
|
||
| Run the TLS tests: | ||
|
|
||
| ```shell | ||
| go test -v -run "^TestTLS" -timeout 30s | ||
| ``` | ||
|
|
||
| ## Notes | ||
|
|
||
| - Always verify certs in production (don't use InsecureSkipVerify) | ||
| - Keep your private keys safe | ||
| - Use TLS 1.2 or higher | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| module github.com/redis/go-redis/example/tls-connection | ||
|
|
||
| go 1.21 | ||
|
|
||
| replace github.com/redis/go-redis/v9 => ../.. | ||
|
|
||
| require github.com/redis/go-redis/v9 v9.18.0-beta.2 | ||
|
|
||
| require ( | ||
| github.com/cespare/xxhash/v2 v2.3.0 // indirect | ||
| github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect | ||
| go.uber.org/atomic v1.11.0 // indirect | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= | ||
| github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= | ||
| github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= | ||
| github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= | ||
| github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= | ||
| github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= | ||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
| github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= | ||
| github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= | ||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
| github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= | ||
| github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||
| go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= | ||
| go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "context" | ||
| "crypto/tls" | ||
| "crypto/x509" | ||
| "fmt" | ||
| "os" | ||
|
|
||
| "github.com/redis/go-redis/v9" | ||
| ) | ||
|
|
||
| func main() { | ||
| ctx := context.Background() | ||
|
|
||
| // Example 1: TLS with InsecureSkipVerify (for testing with self-signed certs) | ||
| fmt.Println("Example 1: TLS with InsecureSkipVerify") | ||
| client1 := redis.NewClient(&redis.Options{ | ||
| Addr: "localhost:6666", // TLS port | ||
| TLSConfig: &tls.Config{ | ||
| InsecureSkipVerify: true, | ||
|
ndyakov marked this conversation as resolved.
Dismissed
|
||
| }, | ||
| }) | ||
| defer client1.Close() | ||
|
|
||
| if err := client1.Ping(ctx).Err(); err != nil { | ||
| fmt.Printf("Failed to connect: %v\n", err) | ||
| } else { | ||
| fmt.Println("✅ Connected successfully with InsecureSkipVerify") | ||
| } | ||
|
|
||
| // Example 2: TLS with CA certificate verification | ||
| fmt.Println("\nExample 2: TLS with CA certificate verification") | ||
|
|
||
| // Load CA certificate | ||
| caCert, err := os.ReadFile("path/to/ca.crt") | ||
| if err != nil { | ||
| fmt.Printf("Note: CA cert not found (this is expected in this example): %v\n", err) | ||
| } else { | ||
| caCertPool := x509.NewCertPool() | ||
| caCertPool.AppendCertsFromPEM(caCert) | ||
|
|
||
| client2 := redis.NewClient(&redis.Options{ | ||
| Addr: "localhost:6666", | ||
| TLSConfig: &tls.Config{ | ||
| RootCAs: caCertPool, | ||
| ServerName: "localhost", | ||
| }, | ||
| }) | ||
| defer client2.Close() | ||
|
|
||
| if err := client2.Ping(ctx).Err(); err != nil { | ||
| fmt.Printf("Failed to connect: %v\n", err) | ||
| } else { | ||
| fmt.Println("✅ Connected successfully with CA verification") | ||
| } | ||
| } | ||
|
|
||
| // Example 3: TLS with client certificate (mutual TLS) | ||
| fmt.Println("\nExample 3: TLS with client certificate (mutual TLS)") | ||
|
|
||
| // Load CA certificate | ||
| caCert, err = os.ReadFile("path/to/ca.crt") | ||
| if err != nil { | ||
| fmt.Printf("Note: CA cert not found (this is expected in this example): %v\n", err) | ||
| } else { | ||
| caCertPool := x509.NewCertPool() | ||
| caCertPool.AppendCertsFromPEM(caCert) | ||
|
|
||
| // Load client certificate and key | ||
| cert, err := tls.LoadX509KeyPair("path/to/client.crt", "path/to/client.key") | ||
| if err != nil { | ||
| fmt.Printf("Note: Client cert not found (this is expected in this example): %v\n", err) | ||
| } else { | ||
| client3 := redis.NewClient(&redis.Options{ | ||
| Addr: "localhost:6666", | ||
| TLSConfig: &tls.Config{ | ||
| RootCAs: caCertPool, | ||
| Certificates: []tls.Certificate{cert}, | ||
| ServerName: "localhost", | ||
| }, | ||
| }) | ||
| defer client3.Close() | ||
|
|
||
| if err := client3.Ping(ctx).Err(); err != nil { | ||
| fmt.Printf("Failed to connect: %v\n", err) | ||
| } else { | ||
| fmt.Println("✅ Connected successfully with client certificate") | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Example 4: Using rediss:// URL scheme | ||
| fmt.Println("\nExample 4: Using rediss:// URL scheme") | ||
|
|
||
| opt, err := redis.ParseURL("rediss://localhost:6666") | ||
| if err != nil { | ||
| fmt.Printf("Failed to parse URL: %v\n", err) | ||
| return | ||
| } | ||
|
|
||
| // Add InsecureSkipVerify for testing with self-signed certs | ||
| opt.TLSConfig = &tls.Config{ | ||
| InsecureSkipVerify: true, | ||
|
ndyakov marked this conversation as resolved.
Dismissed
|
||
| } | ||
|
|
||
| client4 := redis.NewClient(opt) | ||
| defer client4.Close() | ||
|
|
||
| if err := client4.Ping(ctx).Err(); err != nil { | ||
| fmt.Printf("Failed to connect: %v\n", err) | ||
| } else { | ||
| fmt.Println("✅ Connected successfully using rediss:// URL") | ||
| } | ||
|
|
||
| // Example 5: TLS with certificate-based authentication (future feature) | ||
| // This demonstrates how to use client certificates for authentication | ||
| // when Redis is configured with: tls-auth-clients-user CN | ||
| fmt.Println("\nExample 5: TLS with certificate-based authentication") | ||
| fmt.Println("Note: This requires Redis 6.2+ with tls-auth-clients-user CN configuration") | ||
| fmt.Println("The certificate's CN (Common Name) field will be used as the Redis username") | ||
| fmt.Println("See tls_cert_auth_test.go for a complete working example") | ||
| } | ||
|
|
||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.