Skip to content

Commit

Permalink
feat: Memcached: Add TLS support (#12318)
Browse files Browse the repository at this point in the history
  • Loading branch information
DylanGuedes authored Mar 22, 2024
1 parent 611cb01 commit 51c54ad
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 1 deletion.
66 changes: 66 additions & 0 deletions docs/sources/configure/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4552,6 +4552,72 @@ memcached_client:
# CLI flag: -<prefix>.memcached.circuit-breaker-interval
[circuit_breaker_interval: <duration> | default = 10s]
# Enable connecting to Memcached with TLS.
# CLI flag: -<prefix>.memcached.tls-enabled
[tls_enabled: <boolean> | default = false]
# Path to the client certificate, which will be used for authenticating with
# the server. Also requires the key path to be configured.
# CLI flag: -<prefix>.memcached.tls-cert-path
[tls_cert_path: <string> | default = ""]
# Path to the key for the client certificate. Also requires the client
# certificate to be configured.
# CLI flag: -<prefix>.memcached.tls-key-path
[tls_key_path: <string> | default = ""]
# Path to the CA certificates to validate server certificate against. If not
# set, the host's root CA certificates are used.
# CLI flag: -<prefix>.memcached.tls-ca-path
[tls_ca_path: <string> | default = ""]
# Override the expected name on the server certificate.
# CLI flag: -<prefix>.memcached.tls-server-name
[tls_server_name: <string> | default = ""]
# Skip validating server certificate.
# CLI flag: -<prefix>.memcached.tls-insecure-skip-verify
[tls_insecure_skip_verify: <boolean> | default = false]
# Override the default cipher suite list (separated by commas). Allowed
# values:
#
# Secure Ciphers:
# - TLS_RSA_WITH_AES_128_CBC_SHA
# - TLS_RSA_WITH_AES_256_CBC_SHA
# - TLS_RSA_WITH_AES_128_GCM_SHA256
# - TLS_RSA_WITH_AES_256_GCM_SHA384
# - TLS_AES_128_GCM_SHA256
# - TLS_AES_256_GCM_SHA384
# - TLS_CHACHA20_POLY1305_SHA256
# - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
# - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
# - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
# - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
# - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
# - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
# - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
# - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
# - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
# - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
#
# Insecure Ciphers:
# - TLS_RSA_WITH_RC4_128_SHA
# - TLS_RSA_WITH_3DES_EDE_CBC_SHA
# - TLS_RSA_WITH_AES_128_CBC_SHA256
# - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
# - TLS_ECDHE_RSA_WITH_RC4_128_SHA
# - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
# - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
# - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
# CLI flag: -<prefix>.memcached.tls-cipher-suites
[tls_cipher_suites: <string> | default = ""]
# Override the default minimum TLS version. Allowed values: VersionTLS10,
# VersionTLS11, VersionTLS12, VersionTLS13
# CLI flag: -<prefix>.memcached.tls-min-version
[tls_min_version: <string> | default = ""]
redis:
# Redis Server or Cluster configuration endpoint to use for caching. A
# comma-separated list of endpoints for Redis Cluster or Redis Sentinel. If
Expand Down
36 changes: 35 additions & 1 deletion pkg/storage/chunk/cache/memcached_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cache

import (
"context"
"crypto/tls"
"flag"
"net"
"sort"
Expand All @@ -12,6 +13,7 @@ import (

"github.com/go-kit/log"
"github.com/go-kit/log/level"
dstls "github.com/grafana/dskit/crypto/tls"
"github.com/grafana/dskit/dns"
"github.com/grafana/gomemcache/memcache"
"github.com/pkg/errors"
Expand Down Expand Up @@ -62,6 +64,11 @@ type memcachedClient struct {
skipped prometheus.Counter

logger log.Logger

cfg MemcachedClientConfig

// DialTimeout specifies a custom dialer used to dial new connections to a server.
DialTimeout func(network, address string, timeout time.Duration) (net.Conn, error)
}

// MemcachedClientConfig defines how a MemcachedClient should be constructed.
Expand All @@ -77,6 +84,12 @@ type MemcachedClientConfig struct {
CBFailures uint `yaml:"circuit_breaker_consecutive_failures"`
CBTimeout time.Duration `yaml:"circuit_breaker_timeout"` // reset error count after this long
CBInterval time.Duration `yaml:"circuit_breaker_interval"` // remain closed for this long after CBFailures errors

// TLSEnabled enables connecting to Memcached with TLS.
TLSEnabled bool `yaml:"tls_enabled"`

// TLS to use to connect to the Memcached server.
TLS dstls.ClientConfig `yaml:",inline"`
}

// RegisterFlagsWithPrefix adds the flags required to config this to the given FlagSet
Expand All @@ -92,6 +105,8 @@ func (cfg *MemcachedClientConfig) RegisterFlagsWithPrefix(prefix, description st
f.DurationVar(&cfg.CBTimeout, prefix+"memcached.circuit-breaker-timeout", 10*time.Second, description+"Duration circuit-breaker remains open after tripping (if zero then 60 seconds is used).")
f.DurationVar(&cfg.CBInterval, prefix+"memcached.circuit-breaker-interval", 10*time.Second, description+"Reset circuit-breaker counts after this long (if zero then never reset).")
f.IntVar(&cfg.MaxItemSize, prefix+"memcached.max-item-size", 0, description+"The maximum size of an item stored in memcached. Bigger items are not stored. If set to 0, no maximum size is enforced.")
f.BoolVar(&cfg.TLSEnabled, prefix+"memcached.tls-enabled", false, "Enable connecting to Memcached with TLS.")
cfg.TLS.RegisterFlagsWithPrefix(prefix+"memcached.", f)
}

// NewMemcachedClient creates a new MemcacheClient that gets its server list
Expand All @@ -112,9 +127,26 @@ func NewMemcachedClient(cfg MemcachedClientConfig, name string, r prometheus.Reg
"name": name,
}, r))

dialTimeout := net.DialTimeout
if cfg.TLSEnabled {
cfg, err := cfg.TLS.GetTLSConfig()
if err != nil {
level.Error(logger).Log("msg", "couldn't create TLS configuration", "err", err)
} else {
dialTimeout = func(network, address string, timeout time.Duration) (net.Conn, error) {
base := new(net.Dialer)
base.Timeout = timeout

return tls.DialWithDialer(base, network, address, cfg)
}
}
}

newClient := &memcachedClient{
DialTimeout: dialTimeout,
name: name,
Client: client,
cfg: cfg,
serverList: selector,
hostname: cfg.Host,
service: cfg.Service,
Expand Down Expand Up @@ -143,6 +175,8 @@ func NewMemcachedClient(cfg MemcachedClientConfig, name string, r prometheus.Reg
}
if cfg.CBFailures > 0 {
newClient.Client.DialTimeout = newClient.dialViaCircuitBreaker
} else {
newClient.Client.DialTimeout = dialTimeout
}

if len(cfg.Addresses) > 0 {
Expand Down Expand Up @@ -182,7 +216,7 @@ func (c *memcachedClient) dialViaCircuitBreaker(network, address string, timeout
c.Unlock()

conn, err := cb.Execute(func() (interface{}, error) {
return net.DialTimeout(network, address, timeout)
return c.DialTimeout(network, address, timeout)
})
if err != nil {
return nil, err
Expand Down

0 comments on commit 51c54ad

Please sign in to comment.