Repository navigation
valkey: enable tls #4328
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
base: master
Are you sure you want to change the base?
valkey: enable tls #4328
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -361,6 +361,13 @@ type Config struct { | |
| SwarmValkeyDialTimeout time.Duration `yaml:"swarm-valkey-dial-timeout"` | ||
| SwarmValkeyKeepAlive time.Duration `yaml:"swarm-valkey-keepalive"` | ||
| SwarmValkeyUpdateInterval time.Duration `yaml:"swarm-valkey-update-interval"` | ||
| SwarmEnableTLS bool `yaml:"swarm-enable-tls"` | ||
| // swarm TLS | ||
| SwarmCaFile string `yaml:"swarm-ca"` | ||
| SwarmClientCertFile string `yaml:"swarm-client-cert"` | ||
| SwarmClientKeyFile string `yaml:"swarm-client-key"` | ||
| SwarmCA *x509.CertPool `yaml:"-"` | ||
|
|
||
| // swim based | ||
| SwarmKubernetesNamespace string `yaml:"swarm-namespace"` | ||
| SwarmKubernetesLabelSelectorKey string `yaml:"swarm-label-selector-key"` | ||
|
|
@@ -776,6 +783,10 @@ func NewConfig() *Config { | |
| flag.DurationVar(&cfg.SwarmValkeyDialTimeout, "swarm-valkey-dial-timeout", net.DefaultDialTimeout, "set valkey client dial timeout") | ||
| flag.DurationVar(&cfg.SwarmValkeyKeepAlive, "swarm-valkey-keepalive", net.DefaultKeepAlive, "set valkey keepalive probes interval") | ||
| flag.DurationVar(&cfg.SwarmValkeyUpdateInterval, "swarm-valkey-update-interval", net.DefaultUpdateInterval, "set update interval to update valkey addresses") | ||
| flag.StringVar(&cfg.SwarmClientCertFile, "swarm-client-cert", "", "valkey client certificate") | ||
| flag.StringVar(&cfg.SwarmClientKeyFile, "swarm-client-key", "", "valkey client key") | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. description: |
||
| flag.StringVar(&cfg.SwarmCaFile, "swarm-ca", "", "Comma-separated CA bundle file paths used to verify the valkey server certificate") | ||
| flag.BoolVar(&cfg.SwarmEnableTLS, "swarm-enable-tls", false, "Enables mutual TLS for the valkey swarm connection. It uses -swarm-valkey-client-cert and -swarm-valkey-client-key as the client keypair and -swarm-valkey-ca to verify the valkey server certificate. It only supports one cert and one key file.") | ||
| // swim | ||
| flag.StringVar(&cfg.SwarmKubernetesNamespace, "swarm-namespace", swarm.DefaultNamespace, "Kubernetes namespace to find swarm peer instances") | ||
| flag.StringVar(&cfg.SwarmKubernetesLabelSelectorKey, "swarm-label-selector-key", swarm.DefaultLabelSelectorKey, "Kubernetes labelselector key to find swarm peer instances") | ||
|
|
@@ -941,6 +952,21 @@ func (c *Config) ParseArgs(progname string, args []string) error { | |
| c.Certificates = certificates | ||
| } | ||
|
|
||
| if c.SwarmCaFile != "" { | ||
| if c.SwarmCA == nil { | ||
| c.SwarmCA = x509.NewCertPool() | ||
| } | ||
| for f := range strings.SplitSeq(c.SwarmCaFile, ",") { | ||
| pem, err := os.ReadFile(f) | ||
| if err != nil { | ||
| return fmt.Errorf("valkey failed to read %q: %v", f, err) | ||
| } | ||
| if !c.SwarmCA.AppendCertsFromPEM(pem) { | ||
| return fmt.Errorf("valkey failed to append CA cert %q", f) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if c.TLSKeyLogFile != "" { | ||
| f, err := os.OpenFile(c.TLSKeyLogFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o600) | ||
| if err != nil { | ||
|
|
@@ -1253,6 +1279,11 @@ func (c *Config) ToOptions() skipper.Options { | |
| SwarmValkeyDialTimeout: c.SwarmValkeyDialTimeout, | ||
| SwarmValkeyKeepAlive: c.SwarmValkeyKeepAlive, | ||
| SwarmValkeyUpdateInterval: c.SwarmValkeyUpdateInterval, | ||
| SwarmEnableTLS: c.SwarmEnableTLS, | ||
| SwarmClientCertFile: c.SwarmClientCertFile, | ||
| SwarmClientKeyFile: c.SwarmClientKeyFile, | ||
| SwarmCA: c.SwarmCA, | ||
| SwarmClientRefreshInterval: c.ClientCertRefreshInterval, | ||
| // swim based | ||
| SwarmKubernetesNamespace: c.SwarmKubernetesNamespace, | ||
| SwarmKubernetesLabelSelectorKey: c.SwarmKubernetesLabelSelectorKey, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -197,6 +197,24 @@ If you have [routesrv proxy](https://opensource.zalando.com/skipper/kubernetes/i | |
| you need to configure Skipper with the flag `-swarm-valkey-remote=http://<routesrv-service-name>.<routesrv-namespace>.svc.cluster.local/swarm/valkey/shards`. | ||
| `Routesrv` will be responsible for collecting Valkey endpoints and Skipper will poll them from it. | ||
|
|
||
| #### TLS / mutual TLS | ||
|
|
||
| To connect to Valkey over mutual TLS, enable TLS and provide Skipper's client | ||
| keypair plus the CA bundle that signs the Valkey server certificate: | ||
|
|
||
| ``` | ||
| -swarm-valkey-enable-tls | ||
| -swarm-valkey-client-cert=/path/client.crt | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| -swarm-valkey-client-key=/path/client.key | ||
| -swarm-valkey-ca=/path/ca.crt | ||
| ``` | ||
|
|
||
| Skipper presents the client certificate to Valkey and verifies the Valkey | ||
| server certificate against the CA bundle. The server certificate must carry a | ||
| SAN matching the address Skipper dials via `-swarm-valkey-urls`. Multiple CA | ||
| files may be given comma-separated. Only one client cert and one key file are | ||
| supported, and the keypair is loaded once at startup (no rotation). | ||
|
|
||
| #### Implementation | ||
|
|
||
| The implementation use [Valkey-Go | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ import ( | |
| "net/http" | ||
| "net/http/httptrace" | ||
| "net/url" | ||
| "os" | ||
| "strings" | ||
| "sync" | ||
| "sync/atomic" | ||
|
|
@@ -63,6 +64,9 @@ type CertReloader struct { | |
| // GetClientCertificate returns the new rotated *tls.Certificate. | ||
| // You have to use Close() in order to not leak a goroutine. | ||
| func NewCertReloader(certFile, keyFile string, interval time.Duration, log logging.Logger) (*CertReloader, error) { | ||
| if interval <= 0 { | ||
| interval = defaultRefreshInterval | ||
| } | ||
| sp := secrets.NewSecretPaths(interval) | ||
| if err := sp.Add(certFile); err != nil { | ||
| sp.Close() | ||
|
|
@@ -100,6 +104,14 @@ func NewCertReloader(certFile, keyFile string, interval time.Duration, log loggi | |
| go cr.refreshLoop(interval) | ||
| return cr, nil | ||
| } | ||
| func MustNewCertReloader(certFile, keyFile string, interval time.Duration, log logging.Logger) *CertReloader { | ||
| cr, err := NewCertReloader(certFile, keyFile, interval, log) | ||
| if err != nil { | ||
| log.Errorf("Failed to initialize cert reloader: %v", err) | ||
| os.Exit(2) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not log.Fatalf ? |
||
| } | ||
| return cr | ||
| } | ||
|
|
||
| func (cr *CertReloader) refreshLoop(interval time.Duration) { | ||
| ticker := time.NewTicker(interval) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the option is
-swarm-enable-tlsand we should always use-enable-X, so-enable-swarm-tls. There is only kubernetes that has a config option that has enable in the middle and most other use-enable-Xstyle: