The operator now supports first-class authentication, TLS, and hardened pod defaults. This document explains how to enable and operate those features.
spec.security controls cluster-level authentication and transport settings:
spec:
security:
auth:
enabled: true
username: app
passwordSecretRef:
name: demo-redis-auth
key: password
tls:
enabled: true
secretName: demo-redis-tls
requireClientAuth: true
disablePlaintext: trueauth.enabled: when true the operator reads the referenced Secret and rendersrequirepass,masterauth, and Sentinelauth-pass/auth-userdirectives. Replication, failover, runtime config, and bootstrap clients use the same credentials automatically.auth.username: optional ACL user for replicas/Sentinels. Leave empty to keep the Redisdefaultuser.auth.passwordSecretRef: Secret key selector pointing at the Redis password. The Secret is never logged; only its resourceVersion/name participates in config hashes.tls.enabled: enables TLS listeners (tls-port) for Redis and Sentinel. The Secret must contain the usual keys (ca.crt,tls.crt,tls.key), overridable viacaCertKey/certKey/keyKey.tls.requireClientAuth: switches replicas/Sentinals/operator clients to mTLS (--tls --cert --key).tls.disablePlaintext: setsport 0, so onlytls-portstays open.
- Create the password Secret:
kubectl create secret generic demo-redis-auth \ --from-literal=password='S3cureP@ss!' - Patch the
KeyValClusterwithspec.security.auth.enabled=trueand reference the Secret. - The operator reconciles the ConfigMap and statefulset; pods restart one-by-one with
requirepass/masterauth. Sentinels authenticate automatically viaAUTH <user> <pass>. - Clients must use
AUTH(or ACL with username) from now on.
Changing the password is handled by updating the Secret and the spec; the operator recalculates the config hash and performs a safe rolling restart.
- Prepare a Secret containing
ca.crt,tls.crt, andtls.key(PEM):kubectl create secret tls demo-redis-tls \ --cert=server.pem --key=server.key kubectl patch secret demo-redis-tls --type merge -p '{"data":{"ca.crt":"$(base64 < ca.pem)"}}' - Set
spec.security.tls.enabled=trueand reference the Secret. Optional:requireClientAuth=trueenables mTLS.disablePlaintext=truecloses the plain TCP port by renderingport 0.
- The ConfigMap gains TLS directives, pods mount the Secret at
/tls, andredis-cliinside the bootstrap/init container runs with--tls/--cert/--keyflags. - Verify:
kubectl exec demo-0 -- redis-cli --tls --cacert /tls/ca.crt \ --cert /tls/tls.crt --key /tls/tls.key PING
- SLA: A Sentinel cluster with TLS/mTLS enabled must reach
Available=Trueno later than 150 s after the CR is created. The threshold is enforced by the e2e testTestSentinelAuthTLSand validated in CI. - Monitoring: Track the delta between the
BootstrapStartandBootstrapFinishevents (or inspectkubectl describe kvc/<name>). The metrickeyval_bootstrap_attempt_totalincrements at the start, whilekeyval_bootstrap_failure_totalindicates failures. Successful attempts equalmax_over_time(keyval_bootstrap_attempt_total{cluster="<name>"}[5m]) - max_over_time(keyval_bootstrap_failure_total{cluster="<name>"}[5m]). - Artifacts: When
KEEP_ARTIFACTS=1, the e2e suite storesartifacts/<cluster>-sentinel-tls-bootstrap.jsonwith the observed duration and threshold for later analysis. - Alerting: If
BootstrapFinishis missing within 150 s, inspect the Secret (kubectl get secret <tls> -o yaml), readiness probes (kubectl get pod <name> -o jsonpath='{.status.conditions}'), and init-container logs (redis-cli --tls --cacert ...). Maintain resource headroom—CPU or IO starvation often prolongs handshakes.
- All Redis and Sentinel pods run as a non-root user (
uid/gid 1000,fsGroup 1000) and drop all Linux capabilities.allowPrivilegeEscalationis disabled. - Redis containers use a read-only root filesystem; writable paths are provided via
/data,/conf, and/runtime-confvolumes. - Init containers inherit the same non-root context and rely on
fsGroupto write into ConfigMap-backed volumes.
These defaults satisfy the Kubernetes Pod Security restricted profile out of the box.
The operator does not create NetworkPolicies automatically, but examples are provided under examples/networkpolicy/:
redis.yaml: allows ingress to Redis pods only from labelled client namespaces and keeps replica traffic internal to the cluster.sentinel.yaml: restricts access to Sentinel TCP port 26379 to the operator and Redis pods.
Customize the placeholders (<cluster-name>, namespace labels) before applying them in your environment.
The operator runs with a single ClusterRole scoped to the resources it reconciles. The table below lists the effective permissions applied by both Kustomize and Helm deployments:
| API Group | Resource (subresource) | Verbs | Purpose |
|---|---|---|---|
core |
pods |
get, list, watch, patch, delete |
Inspect readiness/labels, patch labels, evict failed pods |
core |
services |
get, list, watch, create, patch, delete |
Manage headless/master services and disable them on request |
core |
configmaps |
get, list, watch, create, patch |
Render and roll config hashes |
core |
events |
create, patch, update |
Emit reconciliation events |
core |
secrets |
get, list, watch |
Read TLS/auth material referenced by the CR |
core |
persistentvolumeclaims |
get, list, watch, patch, update, delete |
Track resize status, drop PVCs when cleanupOnDelete=true |
core |
pods/eviction |
create |
Perform safe pod evictions during rolling updates |
apps |
statefulsets |
get, list, watch, create, patch |
Manage Redis/Sentinel StatefulSets via server-side apply |
policy |
poddisruptionbudgets |
get, list, watch, create, patch, delete |
Coordinate disruption budgets for Redis/Sentinel, remove during cleanup |
coordination.k8s.io |
leases |
get, list, watch, create, update, patch |
Controller-runtime leader election |
keyval.ivelok.io |
keyvalclusters |
get, list, watch, patch, update |
Read CR spec and annotate/patch status fields |
keyval.ivelok.io |
keyvalclusters/status |
get, patch, update |
Publish status updates |
keyval.ivelok.io |
keyvalclusters/finalizers |
get, patch, update |
Manage finalizer lifecycle |
To verify a live deployment, run:
hack/verify-rbac.sh # optionally pass <serviceAccount> <namespace>The check issues kubectl auth can-i calls for every rule while impersonating the controller ServiceAccount. CI runs go test ./test/rbac to ensure the rendered Kustomize and Helm roles stay in sync with the table above.
- If pods loop with
NOAUTH, ensure the password Secret exists andspec.security.auth.enabled=true. - For TLS handshake failures, verify the Secret keys align with
caCertKey/certKey/keyKeyand that clients pass--tls. - The config hash stored in
StatefulSet.spec.template.annotations['keyval.ivelok.io/config-hash']changes when secrets rotate; the operator orchestrates a rolling restart. Check the annotation to confirm.