Repository navigation
Conversation
Introduce spec.tls to opt into TLS for the Redis failover cluster. TLS is provisioned either by cert-manager (operator creates a Certificate CR) or by referencing an existing Secret, never both. CRD shape: spec.tls.enabled bool spec.tls.authClients "no" | "optional" | "yes" (default "no") spec.tls.certManager.issuerRef cmmeta.ObjectReference spec.tls.certManager.secretName string (optional override) spec.tls.certManager.duration *metav1.Duration spec.tls.certManager.renewBefore *metav1.Duration spec.tls.certManager.privateKey *cmapi.CertificatePrivateKey spec.tls.certificateSecret.secretName string Validation: - enabled=true requires exactly one of certManager / certificateSecret - certManager.issuerRef.name is required; kind defaults to "Issuer" and group to "cert-manager.io" when empty - certificateSecret.secretName is required - authClients must be one of "no"/"optional"/"yes" when set Deps: - github.com/cert-manager/cert-manager v1.18.2 (typed CRD API; the operator never requires cert-manager to be installed at runtime when TLS is disabled, the import only brings in Go types) The operator does not yet consume the new fields. Subsequent commits plumb the settings through to the Redis/Sentinel pods, the issued Certificate resource and the operator's own redis client. Ported from a downstream fork of spotahome/redis-operator. Adapted: the cert-manager pin is v1.18.2 rather than a 1.20.x release so that k8s.io/api, apimachinery and client-go stay on the versions this repo already uses; issuerRef is therefore typed cmmeta.ObjectReference, which is the same struct cert-manager 1.19+ exposes as IssuerReference. k8s.io/apiextensions-apiserver moves from v0.28.4 to v0.32.0 because cert-manager's clientset requires it. Deepcopy functions come from the repo's own generator rather than the fork's hand-written ones. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
When spec.tls.enabled is true the operator now emits a configuration
that drives Redis (server, replication and Sentinel traffic) entirely
over TLS:
- redis.conf and sentinel.conf get a TLS block (port 0, tls-port, the
three /tls/{tls.crt,tls.key,ca.crt} paths, tls-auth-clients from
spec, tls-replication yes). The plaintext port is closed
- The Redis StatefulSet and Sentinel Deployment mount the TLS Secret
read-only at /tls. The Secret name is resolved with a clear
precedence: spec.tls.certificateSecret.secretName takes priority,
then spec.tls.certManager.secretName, then a generated default
(rftls-<name>) used in the cert-manager-managed path
- The shutdown.sh and ready.sh scripts in the operator-managed
ConfigMaps inject the matching --tls --cert --key --cacert flags
into every redis-cli invocation
- The inline exec probes (liveness on the redis container, both
probes on the sentinel container) get the same flags
- The redis_exporter sidecars receive REDIS_EXPORTER_TLS_* env vars
pointing at the mounted certificate; REDIS_ADDR switches to
rediss:// so the exporter dials TLS as well
The operator does not yet create the cert-manager Certificate
resource; that lands in a separate commit. spec.tls.certificateSecret
(bring-your-own) is already wired through.
New tests under generator_tls_test.go cover the config files, the
volume + mount layout, the exporter env, the probe scripts and the
GetTLSSecretName precedence rules. With TLS disabled all existing
test fixtures continue to pass unchanged.
Ported from a downstream fork of spotahome/redis-operator. Adapted
to this codebase: the TLS flags go through the engine-aware CLI
binary and the auth env name resolved by EngineFor(), so Valkey
failovers pick up valkey-cli; the sentinel config template keeps the
DisableMyMaster branch and gains the TLS block ahead of it; the probe
for the sentinel master address keeps rf.MasterName(); and the new
tests stub GetStatefulSet, which EnsureRedisStatefulset now calls for
maxmemory validation.
Signed-off-by: Arsolitt <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
…vers When spec.tls.enabled is true and spec.tls.certManager is set, the operator now creates (and reconciles) a cert-manager Certificate that issues into the Secret the pods already mount. The Certificate is a no-op for the bring-your-own-secret mode (spec.tls.certificateSecret) and obviously for TLS-disabled failovers. Wiring: - service/k8s: new Certificate service interface and CertificateService implementation talking to cert-manager's typed clientset; added to Services so existing call sites pick it up via embedding - cmd: CreateKubernetesClients now also builds the cert-manager client; main.go passes it into k8s.New - service generator: generateRedisCertificate builds a Certificate with the IssuerRef from spec.tls.certManager, the resolved Secret name, optional duration / renewBefore / privateKey overrides, and the ServerAuth + ClientAuth key usages - ensurer: EnsureRedisCertificate runs before the ConfigMaps and pods so the Secret cert-manager populates exists by the time pods mount it SAN coverage on the issued certificate: - the four Service names (redis headless, redis master, redis slave, sentinel) each in short, namespaced, .svc and .svc.cluster.local form - a wildcard against the redis headless service so per-pod DNS records (<pod>.rfr-<name>.<ns>.svc.cluster.local) validate without re-issuing when replica count changes - no IP SANs — pod IPs are unstable; the operator client validates pod-IP-targeted dials via ServerName override against the headless DNS SAN Mocks for Services and RedisFailoverClient carry the new methods. They are written by hand in the generated style because `go generate ./mocks` cannot run: mockery 2.45.0, the version this repo pins, fails under the Go toolchain in go.mod with "internal error: package \"fmt\" without types". Tests: - EnsureRedisCertificate creates a Certificate with the right SANs, issuer ref, secret name, duration/renewBefore and usages - EnsureRedisCertificate is a no-op when TLS is disabled - EnsureRedisCertificate is a no-op for bring-your-own-secret mode - The existing TestEnsure suite now stubs EnsureRedisCertificate The operator's own redis client still dials plaintext, so a failover with TLS enabled is not yet reconcilable end to end; teaching service/redis/client.go to speak TLS is separate work. Ported from a downstream fork of spotahome/redis-operator. Adapted to this codebase: cmmeta.ObjectReference in place of IssuerReference to match the cert-manager version pinned here, and the mock additions described above. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
Introduce an optional caCertSecretName on spec.tls. It names the Opaque Secret the operator publishes with only ca.crt, letting clients verify the server under narrowly scoped RBAC without access to any private key. Ported from a downstream fork of spotahome/redis-operator. Adapted: the CRD schema is not touched here. The fork regenerated its manifests in a separate commit that is not part of this port, so a single regeneration covering the whole of spec.tls follows this commit instead. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
The secret service could only read secrets. Add create/update and a create-or-update helper mirroring the configmap service so the operator can manage secrets it owns. Extend the Services mock and cover the create and update paths with a unit test. Ported unchanged from a downstream fork of spotahome/redis-operator. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
When TLS is enabled the operator extracts ca.crt from the cluster TLS secret and publishes it into a dedicated Opaque Secret (default <tls-secret>-ca, overridable via spec.tls.caCertSecretName). The Secret never holds a private key, so RBAC can be scoped to it for client trust distribution. Works in both cert-manager and bring-your-own modes and defers gracefully until ca.crt is available. Widen the chart RBAC so the operator can manage secrets. Ported from a downstream fork of spotahome/redis-operator. Adapted to this codebase: the fork's version of this change sat on top of a --cluster-domain flag and an extended SAN helper that are not part of this port, so the CA-secret code is grafted onto the SAN helper and the three-argument client constructor that exist here. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
CreateOrUpdateSecret compares the stored Secret's type and data against the desired state and returns early when they match, avoiding a redundant API write (and resourceVersion bump) on every reconcile of the owning resource. The operator does not watch Secrets, so this is a churn-reduction optimization rather than a loop fix. Ported unchanged from a downstream fork of spotahome/redis-operator. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
Run the repository's CRD generator over the new TLS fields so the manifest, the kustomize base and the chart CRD all carry spec.tls. Generated with controller-gen 0.17.3 and crd:crdVersions=v1, which is what ghcr.io/slok/kube-code-generator:v0.7.0 runs; that image has no arm64 build, so controller-gen was invoked directly at the same version and its output is byte-identical to the committed CRD apart from the new block. Bump the chart to 3.4.0, which the version-check job requires whenever the CRD manifest changes. Signed-off-by: Aleksei Sviridkin <[email protected]>
The operator's own redis/sentinel client (service/redis/client.go) now dials TLS when the failover has spec.tls.enabled. Approach: every Client method gains a final *tls.Config parameter that is fed straight into rediscli.Options.TLSConfig. A nil config preserves the historical plaintext behavior, so disabled-TLS clusters are unaffected. Plumbing: - service/redis/tls.go: new BuildTLSConfig helper. Loads the CA out of the ca.crt key of the cluster Secret (the one cert-manager or the user populates), produces a tls.Config with the supplied ServerName for SAN-based validation, MinVersion TLS 1.2, no InsecureSkipVerify. - operator/redisfailover/service/check.go: new tlsConfigFor helper reads the Secret named by GetTLSSecretName and feeds BuildTLSConfig with ServerName = GetRedisName(rf) (the redis headless service, which is the SAN every issued cert covers). - check.go and heal.go: every method that already loaded the password now also calls tlsConfigFor and passes the resulting config to the client. tlsConfigFor returns nil for TLS-disabled failovers so the pre-existing call sites keep their plaintext semantics. Interface changes: - service/redis.Client: each method gains a trailing *tls.Config - service.RedisFailoverCheck.CheckSentinelMonitor: gains a leading *redisfailoverv1.RedisFailover so tlsConfigFor has access to it - service.RedisFailoverHeal.RestoreSentinel: same, leading rf Callers in operator/redisfailover/checker.go updated to pass rf. Why ServerName, not InsecureSkipVerify: pod IPs are unstable, but the issued cert covers the headless service DNS name. Dialing pod IP + ServerName override gives strong validation against the SAN list without juggling IP SANs that would churn on every reschedule. Mocks (mocks/service/redis/Client.go, the two RedisFailover* mocks) are updated by hand to match the new signatures. The check_test and heal_test fixtures are updated en masse (mock.Anything for the new trailing tlsConfig arg). New tests cover BuildTLSConfig: nil/empty CA, missing ServerName, malformed PEM, success path. Ported from a downstream fork of spotahome/redis-operator. Adapted to this codebase: the *tls.Config goes on after the masterName parameter this repo already threads through MonitorRedisWithPort, GetSentinelMonitor, SetCustomSentinelConfig and SentinelCheckQuorum, and CheckSentinelMonitor derives masterName from rf.MasterName() rather than taking it separately. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
The integration suite builds the operator's clients directly, so the cert-manager client added to CreateKubernetesClients and k8s.New and the trailing *tls.Config on the redis client reach it too. Ported from a downstream fork of spotahome/redis-operator. Adapted: this repo has a second integration file and a second client setup in creation_test.go that the fork did not, and its GetSentinelMonitor call also carries masterName. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
…xample The operator now requires write access to cert-manager Certificate resources whenever a RedisFailover opts into TLS with the spec.tls.certManager block. Grant create/delete/get/list/patch/ update/watch on cert-manager.io/certificates from the operator's ClusterRole. The rule is always present; the operator only issues requests when a failover has TLS enabled, so installations that do not have cert-manager installed remain unaffected. Add example/redisfailover/tls.yaml that demonstrates the cert-manager managed path and documents the bring-your-own-Secret alternative in a comment. Ported unchanged from a downstream fork of spotahome/redis-operator. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
Adds spec.tls.certManager.extraSANs: a list of additional Subject Alternative Names appended to the service and per-pod SANs the operator already computes. Entries are auto-classified by net.ParseIP — IPv4 and IPv6 strings become IP SANs, everything else becomes a DNS SAN. The merge is purely additive so in-cluster connectivity is preserved when operators add external hostnames or LoadBalancer VIPs for off-cluster clients. The CRD is regenerated in all three published locations: chart crds, kustomize base and manifests root. Ported from a downstream fork of spotahome/redis-operator. Adapted: the deepcopy and CRD output stay on this repo's generators (deepcopy-gen style and controller-gen 0.17.3) instead of the newer controller-gen the fork had migrated to, and the go directive is left alone. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
tlsConfigFor only verified that the ca.crt key existed in the TLS Secret, not that its value was non-empty. When the key is present but empty, redis.BuildTLSConfig returns (nil, nil), which callers interpret as "no TLS" and dial in plaintext, silently downgrading the connection even though spec.tls.enabled is true. Fail fast instead. Ported unchanged from a downstream fork of spotahome/redis-operator. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
The operator only loaded the CA bundle from the TLS Secret, so its internal Redis client could reach a server running without mutual TLS (tls-auth-clients: no) but had no way to satisfy one running in mutual mode: the handshake is rejected because there is no client certificate to validate. BuildTLSConfig now takes optional certPEM/keyPEM blobs and attaches them as tls.Config.Certificates when both are supplied; supplying only one is rejected. tlsConfigFor reads the leaf certificate and key from the same cert-manager Secret (the tls.crt / tls.key entries populated by the issued Certificate, which carries serverAuth and clientAuth EKUs) when spec.tls.authClients is yes, and fails fast with a descriptive error if either entry is missing or empty. Unit tests cover the new branches: client cert loaded, mismatched cert/key arguments, and malformed cert/key PEMs. Ported unchanged from a downstream fork of spotahome/redis-operator. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
MakeSlaveOfWithPort dialed the local Redis instance at net.JoinHostPort(ip, masterPort) and sent SLAVEOF masterIP masterPort, collapsing two distinct ports into one. In same-cluster failover the two are equal so the bug was dormant, but SetExternalMasterOnAll threads the external master's port through this API: when that port differs from the local Redis port the operator dials the local pod on the wrong port and the slave-of reconfig fails for every external master takeover. The function now takes localPort and masterPort as independent arguments. The dial uses ip:localPort, the SLAVEOF command keeps masterIP:masterPort. SetExternalMasterOnAll resolves localPort from spec.Redis.Port before iterating pods; the same-cluster callers (SetOldestAsMaster, SetMasterOnAll) pass the same port for both values since their masterPort always equals localPort. Ported from a downstream fork of spotahome/redis-operator. Adapted: the interface line also carries the masterName parameters this repo threads through GetSentinelMonitor and SetCustomSentinelConfig. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
The early (nil, nil) return on len(caPEM) == 0 also accepted a non-empty certPEM/keyPEM pair, which would silently disable TLS in a misconfigured mTLS path, the same silent plaintext fallback already guarded against on the caller side. Fail fast in BuildTLSConfig instead. New test TestBuildTLSConfigRejectsClientMaterialWithoutCA covers both cert+key without CA and cert-only without CA. Ported unchanged from a downstream fork of spotahome/redis-operator. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
In-pod self-dials hit hosts that were not in the cert SAN list, breaking startup whenever the verifying party (redis-cli >= 6, oliver006/redis_exporter, the Sentinel monitor target) actually checks the certificate against the dialed host. Three call sites were affected: - The liveness probe dialed `$(hostname)`, the bare StatefulSet pod name (e.g. `rfr-myrf-0`). The wildcard `*.<headless>` SAN does not match a bare label: X.509 wildcards consume exactly one label. - redis_exporter and sentinel-exporter dialed `127.0.0.1`, and the Sentinel monitor config statement did the same. 127.0.0.1 was not in the cert's IPAddresses field, only DNS SANs were emitted. Fix: - redisCertificateSANs (renamed from redisCertificateDNSNames) now returns both DNSNames and IPAddresses. localhost joins the DNS set so the redis-cli liveness probe verifies cleanly; 127.0.0.1 and ::1 join the IP set so the in-pod exporter and Sentinel monitor target verify against the same cert. - The Redis and Sentinel liveness/readiness probes switch from `-h $(hostname)` to `-h localhost`, which the new DNS SAN covers. Tests assert the new default IP SANs and the localhost DNS SAN, guard against silent regression of the default IPAddresses slice, and check that the probes dial localhost. The plain-text probe expectations move to localhost too: the SAN-mismatch concern does not apply there, but the codepath is shared. Ported from a downstream fork of spotahome/redis-operator. Adapted: the probes keep the engine-aware CLI binary and the configured master name, and this repo has a DisableMyMaster probe fixture the fork did not, updated to match. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
The FQDN SAN entries hardcoded ".svc.cluster.local", so on a cluster running with a non-default --cluster-domain (on-prem clusters routinely use "cluster.internal" or a site-specific value) the cert-manager Certificate produced by the operator did not cover the FQDNs clients actually resolve, and TLS verification failed for every routed FQDN dial. Plumbing: - New `--cluster-domain` CLI flag (default "cluster.local") on the operator binary. - Threaded through the existing `redisfailover.Config` struct, the factory, and `NewRedisFailoverKubeClient`, which now takes the cluster domain as a constructor argument and stores it on the client. - `generateRedisCertificate` and `redisCertificateSANs` accept the cluster domain and template the `.svc.<domain>` FQDN SAN entries accordingly. An empty value falls back to "cluster.local" so deployments that never set the flag keep working. Tests: every NewRedisFailoverKubeClient caller passes the default "cluster.local", and a new case asserts that with --cluster-domain=cozy.local the FQDN SANs use ".cozy.local" and the default ".cluster.local" form is not silently added alongside, which would mask SAN-mismatch bugs. Ported from a downstream fork of spotahome/redis-operator. Adapted: this repo has additional test fixtures constructing the kube client, all updated to the new signature. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
The operator only reads the TLS secret (get) and publishes the CA-only secret (create/update/patch); it never lists or watches secrets, so granting list and watch widened cluster-wide secret read exposure for nothing. Scope the ClusterRole to create/get/patch/update. Ported unchanged from a downstream fork of spotahome/redis-operator. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
A TLS secret without a populated ca.crt is an expected transient state under asynchronous cert-manager issuance, and the operator already treats it as a soft deferral. Log it at debug to match the sibling "TLS secret not present yet" branch instead of warning on every reconcile before the CA is ready. Ported unchanged from a downstream fork of spotahome/redis-operator. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
The CA-only secret tests configured GetSecret and CreateOrUpdateSecret expectations but never asserted them, so a missing interaction passed silently. Add ms.AssertExpectations(t) to every test that sets expectations. Ported unchanged from a downstream fork of spotahome/redis-operator. Signed-off-by: Arsolitt <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
Replace the hand-written DeepCopy functions for TLSSettings, CertManagerSettings and LocalSecretReference with the output of the repository's own generator, so the file matches what update-codegen produces: alphabetical placement and the certmanagerv1 import alias. The copy semantics are unchanged. Generated with kube::codegen::gen_helpers from k8s.io/code-generator kubernetes-1.33.0, the version ghcr.io/slok/kube-code-generator:v0.7.0 bundles; that image has no arm64 build, so the generator was invoked directly at the same version. Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
marked this pull request as ready for review
September 1, 2026 18:06
lexfrei
requested review from
Kaushik-Vijayakumar-1,
Sasidharan-Gopal and
pratheep-kumar
as code owners
September 1, 2026 18:06
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 1, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants what the patched operator calls: Create, Get and Update on Secrets, so it can publish the CA-only Secret, and Create, Delete, Get and Update on cert-manager Certificates, for the spec.tls.certManager path this platform does not use. Every verb is one the patched source actually calls; neither resource is listed or watched, so neither carries list or watch. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. The RBAC grant is narrower than the ported operator's own chart asks for: that one adds delete, list, patch and watch on Secrets and every verb on Certificates. Neither is reachable from the source, so they are not granted here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 1, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 1, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 1, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 1, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. tls.diff is cut from that PR's commit 1b23aa4b4 rebased onto v3.3.5, and its header pins that SHA so the next refresh can be diffed against it. Beyond the TLS listener it carries the renewal roll: on every reconcile the operator stamps a hash of the TLS Secret's tls.crt and ca.crt into the pod template of the Redis StatefulSet and the Sentinel Deployment, so a renewed certificate rolls Redis through the operator's own roller and Sentinel through its Deployment. It also mounts the TLS volume 0440 when the pod declares an fsGroup, rejects a caCertSecretName that names the TLS Secret itself, and waits for the TLS material before it writes the ConfigMaps and the workloads, so a first TLS install starts its pods once. tls.enabled is fixed at creation. Redis replication and Sentinel cannot straddle plaintext and TLS: a replica restarted onto the other protocol cannot sync from the master, and Sentinels restarted onto it fail over to such a replica while the master still takes writes. The rule that refuses the change is a CEL transition rule on the RedisFailover spec; it lives in the CRD, so it ships here through patches/crd-tls.diff together with the schema block it references. The cut carries source only, and two upstream tests read the CRD YAML that stays behind, so `go test ./...` on the patched tree fails in exactly those two; the image build runs `go build` alone. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. tls.diff also carries two changes that are not TLS and take effect with TLS off: the Redis and Sentinel probes dial -h localhost instead of -h $(hostname), and MakeSlaveOfWithPort connects to the replica on its own port rather than on the master's. Both come with the upstream PR as ported, and the probe change alters the pod template, so the first reconcile with this image rolls every existing Redis StatefulSet and Sentinel Deployment once. The patch header names them, so a reader of patches/ does not take the file for TLS-only. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
1 of 11 tasks
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 1, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. tls.diff is cut from that PR's commit 20580032e rebased onto v3.3.5, and its header pins that SHA so the next refresh can be diffed against it. Beyond the TLS listener it carries the renewal roll: on every reconcile the operator stamps a hash of the TLS Secret's tls.crt and ca.crt into the pod template of the Redis StatefulSet and the Sentinel Deployment, so a renewed certificate rolls Redis through the operator's own roller and Sentinel through its Deployment. It also mounts the TLS volume 0440 when the pod declares an fsGroup, rejects a caCertSecretName that names the TLS Secret itself, and waits for the TLS material before it writes the ConfigMaps and the workloads, so a first TLS install starts its pods once. tls.enabled is fixed at creation. Redis replication and Sentinel cannot straddle plaintext and TLS: a replica restarted onto the other protocol cannot sync from the master, and Sentinels restarted onto it fail over to such a replica while the master still takes writes. The rule that refuses the change is a CEL transition rule on the RedisFailover spec; it lives in the CRD, so it ships here through patches/crd-tls.diff together with the schema block it references. The cut carries source only, and the Dockerfile strips the tarball's manifests/, charts/, example/ and .github/ before applying the patches, so the image builds from source alone and the two upstream tests that read the CRD YAML skip instead of failing against v3.3.5's stale copy; the CRD half is patches/crd-tls.diff. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. tls.diff also carries one change that is not TLS and takes effect with TLS off: MakeSlaveOfWithPort connects to the replica on its own port rather than on the master's. It changes a dial, not a pod template, so nothing rolls when this image ships; the probes dial localhost only under TLS, and the plaintext pod templates stay byte-identical to v3.3.5. The patch header names it, so a reader of patches/ does not take the file for TLS-only. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
The probes dialled -h $(hostname). Under TLS the probe host was changed to localhost, which is a SAN entry on the server certificate along with the loopback addresses, while the bare pod hostname is not. It was changed for every failover, including those that never enabled TLS. The probe command is part of the pod template, so with that change every existing RedisFailover's Redis StatefulSet and Sentinel Deployment differ from their live spec the moment the new operator image starts, and each one rolls its pods once — a restart of every Redis cluster under management, caused by an operator upgrade rather than by any spec change the user made. Plaintext therefore has to render byte-identically to what the operator emitted before. Pick the probe host from whether TLS is enabled for that failover: localhost with TLS on, $(hostname) otherwise. Restore the plaintext expectations in the existing probe tests and pin them, across custom port, master name and engine, so an unconditional host cannot come back unnoticed. Signed-off-by: Aleksei Sviridkin <[email protected]>
The two tests read the generated CRD from manifests/ and from the chart's crds/ directory. Consumers that carry this operator as a source-only patch take the Go tree and leave those directories out, so both tests fail there for want of a fixture rather than for anything about the operator, and `go test ./...` cannot be used to check the patched tree at all. Skip when none of the three committed copies is present, naming the paths that were looked for. A tree carrying some copies but not the others is a different case — they are written together and expected to travel together — so a partial set stays a failure, and in a full checkout both tests run and assert exactly as before. Signed-off-by: Aleksei Sviridkin <[email protected]>
The cert-manager secretName godoc named "<rfname>-tls" as the default it overrides. The operator generates "rftls-<name>", so the name in the doc matches nothing the operator ever creates. That godoc becomes the CRD field description, so the wrong default also shipped into kubectl explain on every cluster carrying the CRD; the three committed CRD copies are regenerated with it. The probeHost comment said the probes have to dial localhost because the bare pod hostname is not a SAN entry. redis-cli verifies the certificate chain and not the hostname, so the SAN list does not force the choice. State what is true instead: localhost is dialled because it is a SAN entry on the generated certificate, alongside the loopback addresses. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
force-pushed
the
feat/tls-support
branch
from
September 2, 2026 00:31
7fe92e4 to
38b9e37
Compare
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 2, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. tls.diff is cut from that PR's commit 7fe92e4e7 rebased onto v3.3.5, and its header pins that SHA so the next refresh can be diffed against it. Beyond the TLS listener it carries the renewal roll: on every reconcile the operator stamps a hash of the TLS Secret's tls.crt and ca.crt into the pod template of the Redis StatefulSet and the Sentinel Deployment, so a renewed certificate rolls Redis through the operator's own roller and Sentinel through its Deployment. It also mounts the TLS volume 0440 when the pod declares an fsGroup, rejects a caCertSecretName that names the TLS Secret itself, and waits for the TLS material before it writes the ConfigMaps and the workloads, so a first TLS install starts its pods once. tls.enabled is fixed at creation. Redis replication and Sentinel cannot straddle plaintext and TLS: a replica restarted onto the other protocol cannot sync from the master, and Sentinels restarted onto it fail over to such a replica while the master still takes writes. The rule that refuses the change is a CEL transition rule on the RedisFailover spec; it lives in the CRD, so it ships here through patches/crd-tls.diff together with the schema block it references. The cut carries source only, and the Dockerfile strips the tarball's manifests/, charts/, example/ and .github/ before applying the patches, so the image builds from source alone and the two upstream tests that read the CRD YAML skip instead of failing against v3.3.5's stale copy; the CRD half is patches/crd-tls.diff. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. tls.diff also carries one change that is not TLS and takes effect with TLS off: MakeSlaveOfWithPort connects to the replica on its own port rather than on the master's. It changes a dial, not a pod template, so nothing rolls when this image ships; the probes dial localhost only under TLS, and the plaintext pod templates stay byte-identical to v3.3.5. The patch header names it, so a reader of patches/ does not take the file for TLS-only. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 2, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. tls.diff is cut from that PR's commit 38b9e3732 rebased onto v3.3.5, and its header pins that SHA so the next refresh can be diffed against it. Beyond the TLS listener it carries the renewal roll: on every reconcile the operator stamps a hash of the TLS Secret's tls.crt and ca.crt into the pod template of the Redis StatefulSet and the Sentinel Deployment, so a renewed certificate rolls Redis through the operator's own roller and Sentinel through its Deployment. It also mounts the TLS volume 0440 when the pod declares an fsGroup, rejects a caCertSecretName that names the TLS Secret itself, and waits for the TLS material before it writes the ConfigMaps and the workloads, so a first TLS install starts its pods once. tls.enabled is fixed at creation. Redis replication and Sentinel cannot straddle plaintext and TLS: a replica restarted onto the other protocol cannot sync from the master, and Sentinels restarted onto it fail over to such a replica while the master still takes writes. The rule that refuses the change is a CEL transition rule on the RedisFailover spec; it lives in the CRD, so it ships here through patches/crd-tls.diff together with the schema block it references. The cut carries source only, and the Dockerfile strips the tarball's manifests/, charts/, example/ and .github/ before applying the patches, so the image builds from source alone and the two upstream tests that read the CRD YAML skip instead of failing against v3.3.5's stale copy; the CRD half is patches/crd-tls.diff. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. tls.diff also carries one change that is not TLS and takes effect with TLS off: MakeSlaveOfWithPort connects to the replica on its own port rather than on the master's. It changes a dial, not a pod template, so nothing rolls when this image ships; the probes dial localhost only under TLS, and the plaintext pod templates stay byte-identical to v3.3.5. The patch header names it, so a reader of patches/ does not take the file for TLS-only. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 2, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. tls.diff is cut from that PR's commit 38b9e3732 rebased onto v3.3.5, and its header pins that SHA so the next refresh can be diffed against it. Beyond the TLS listener it carries the renewal roll: on every reconcile the operator stamps a hash of the TLS Secret's tls.crt and ca.crt into the pod template of the Redis StatefulSet and the Sentinel Deployment, so a renewed certificate rolls Redis through the operator's own roller and Sentinel through its Deployment. It also mounts the TLS volume 0440 when the pod declares an fsGroup, rejects a caCertSecretName that names the TLS Secret itself, and waits for the TLS material before it writes the ConfigMaps and the workloads, so a first TLS install starts its pods once. tls.enabled is fixed at creation. Redis replication and Sentinel cannot straddle plaintext and TLS: a replica restarted onto the other protocol cannot sync from the master, and Sentinels restarted onto it fail over to such a replica while the master still takes writes. The rule that refuses the change is a CEL transition rule on the RedisFailover spec; it lives in the CRD, so it ships here through patches/crd-tls.diff together with the schema block it references. The cut carries source only, and the Dockerfile strips the tarball's manifests/, charts/, example/ and .github/ before applying the patches, so the image builds from source alone and the two upstream tests that read the CRD YAML skip instead of failing against v3.3.5's stale copy; the CRD half is patches/crd-tls.diff. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. tls.diff also carries one change that is not TLS and takes effect with TLS off: MakeSlaveOfWithPort connects to the replica on its own port rather than on the master's. It changes a dial, not a pod template, so nothing rolls when this image ships; the probes dial localhost only under TLS, and the plaintext pod templates stay byte-identical to v3.3.5. The patch header names it, so a reader of patches/ does not take the file for TLS-only. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 2, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. tls.diff is cut from that PR's commit 38b9e3732 rebased onto v3.3.5, and its header pins that SHA so the next refresh can be diffed against it. Beyond the TLS listener it carries the renewal roll: on every reconcile the operator stamps a hash of the TLS Secret's tls.crt and ca.crt into the pod template of the Redis StatefulSet and the Sentinel Deployment, so a renewed certificate rolls Redis through the operator's own roller and Sentinel through its Deployment. It also mounts the TLS volume 0440 when the pod declares an fsGroup, rejects a caCertSecretName that names the TLS Secret itself, and waits for the TLS material before it writes the ConfigMaps and the workloads, so a first TLS install starts its pods once. tls.enabled is fixed at creation. Redis replication and Sentinel cannot straddle plaintext and TLS: a replica restarted onto the other protocol cannot sync from the master, and Sentinels restarted onto it fail over to such a replica while the master still takes writes. The rule that refuses the change is a CEL transition rule on the RedisFailover spec; it lives in the CRD, so it ships here through patches/crd-tls.diff together with the schema block it references. The cut carries source only, and the Dockerfile strips the tarball's manifests/, charts/, example/ and .github/ before applying the patches, so the image builds from source alone and the two upstream tests that read the CRD YAML skip instead of failing against v3.3.5's stale copy; the CRD half is patches/crd-tls.diff. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. tls.diff also carries one change that is not TLS and takes effect with TLS off: MakeSlaveOfWithPort connects to the replica on its own port rather than on the master's. It changes a dial, not a pod template, so nothing rolls when this image ships; the probes dial localhost only under TLS, and the plaintext pod templates stay byte-identical to v3.3.5. The patch header names it, so a reader of patches/ does not take the file for TLS-only. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 2, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. tls.diff is cut from that PR's commit 38b9e3732 rebased onto v3.3.5, and its header pins that SHA so the next refresh can be diffed against it. Beyond the TLS listener it carries the renewal roll: on every reconcile the operator stamps a hash of the TLS Secret's tls.crt and ca.crt into the pod template of the Redis StatefulSet and the Sentinel Deployment, so a renewed certificate rolls Redis through the operator's own roller and Sentinel through its Deployment. It also mounts the TLS volume 0440 when the pod declares an fsGroup, rejects a caCertSecretName that names the TLS Secret itself, and waits for the TLS material before it writes the ConfigMaps and the workloads, so a first TLS install starts its pods once. tls.enabled is fixed at creation. Redis replication and Sentinel cannot straddle plaintext and TLS: a replica restarted onto the other protocol cannot sync from the master, and Sentinels restarted onto it fail over to such a replica while the master still takes writes. The rule that refuses the change is a CEL transition rule on the RedisFailover spec; it lives in the CRD, so it ships here through patches/crd-tls.diff together with the schema block it references. The cut carries source only, and the Dockerfile strips the tarball's manifests/, charts/, example/ and .github/ before applying the patches, so the image builds from source alone and the two upstream tests that read the CRD YAML skip instead of failing against v3.3.5's stale copy; the CRD half is patches/crd-tls.diff. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. tls.diff also carries one change that is not TLS and takes effect with TLS off: MakeSlaveOfWithPort connects to the replica on its own port rather than on the master's. It changes a dial, not a pod template, so nothing rolls when this image ships; the probes dial localhost only under TLS, and the plaintext pod templates stay byte-identical to v3.3.5. The patch header names it, so a reader of patches/ does not take the file for TLS-only. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
Redis and Sentinel reject a client that presents no certificate while tls-auth-clients is yes. tlsConfigFor loaded the operator's own certificate only while spec.tls.authClients read yes, but that field is mutable and the pods keep enforcing the value they booted with until they roll. Flipping it to no therefore stopped the operator presenting a certificate while the running pods still demanded one, so every check and heal ran against its own instance and failed, until the pods happened to restart for an unrelated reason. Load the pair from the TLS Secret whenever it carries both tls.crt and tls.key, independently of the spec. Offering a certificate to a server that does not ask for one costs nothing; withholding it from a server that does locks the operator out. A Secret carrying only one half still yields no client certificate, so the dial reports what is missing instead of every check failing early. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <[email protected]>
spec.tls.authClients is mutable, but its only carrier is the generated redis.conf and sentinel.conf. Redis reads that file once at startup, the Redis StatefulSet rolls OnDelete and the roller keys on the StatefulSet revision, and the healer pushes only spec.redis.customConfig over CONFIG SET (heal.go:365). A change was therefore admitted, rewrote the ConfigMaps, and then landed pod by pod at whatever unrelated restart came next: a node drain, an OOM, or the certificate renewal roll months later, with nothing in the release history to point at as the cause. Fold the effective directive into the content hashed for the tls-secret-hash pod annotation, length-prefixed like the Secret keys already are, so that "no" and "yes" cannot collide with a different split of the same bytes. An unset value hashes as the "no" the API defaulting fills in, so the two spellings of one server leave the pods alone. Changing the value now changes the pod template, which publishes a new StatefulSet updateRevision and rolls the Sentinel Deployment, exactly as a renewed certificate does. Unlike a tls.enabled flip, this roll cannot deadlock. The roller refuses to delete any pod until every slave answers (operator/redisfailover/checker.go:27), and that check dials with the config built by tlsConfigFor (operator/redisfailover/service/check.go:608, dialled at :614). The operator now presents its client certificate whatever the spec says, so pods still enforcing the old directive keep answering it, and tls-auth-clients moves no listener: both sides of the roll speak TLS on the same port. Old and new pods stay reachable for the whole rollout. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <[email protected]>
The const block lost its alignment when the TLS plumbing landed, and the repo's lint gate does not report gofmt violations. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 2, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. tls.diff is cut from that PR's commit 38b9e3732 rebased onto v3.3.5, and its header pins that SHA so the next refresh can be diffed against it. Beyond the TLS listener it carries the renewal roll: on every reconcile the operator stamps a hash of the TLS Secret's tls.crt and ca.crt into the pod template of the Redis StatefulSet and the Sentinel Deployment, so a renewed certificate rolls Redis through the operator's own roller and Sentinel through its Deployment. It also mounts the TLS volume 0440 when the pod declares an fsGroup, rejects a caCertSecretName that names the TLS Secret itself, and waits for the TLS material before it writes the ConfigMaps and the workloads, so a first TLS install starts its pods once. tls.enabled is fixed at creation. Redis replication and Sentinel cannot straddle plaintext and TLS: a replica restarted onto the other protocol cannot sync from the master, and Sentinels restarted onto it fail over to such a replica while the master still takes writes. The rule that refuses the change is a CEL transition rule on the RedisFailover spec; it lives in the CRD, so it ships here through patches/crd-tls.diff together with the schema block it references. The cut carries source only, and the Dockerfile strips the tarball's manifests/, charts/, example/ and .github/ before applying the patches, so the image builds from source alone and the two upstream tests that read the CRD YAML skip instead of failing against v3.3.5's stale copy; the CRD half is patches/crd-tls.diff. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. tls.diff also carries one change that is not TLS and takes effect with TLS off: MakeSlaveOfWithPort connects to the replica on its own port rather than on the master's. It changes a dial, not a pod template, so nothing rolls when this image ships; the probes dial localhost only under TLS, and the plaintext pod templates stay byte-identical to v3.3.5. The patch header names it, so a reader of patches/ does not take the file for TLS-only. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 2, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. tls.diff is cut from that PR's commit 2ad2ed8d1 rebased onto v3.3.5, and its header pins that SHA so the next refresh can be diffed against it. Beyond the TLS listener it carries the renewal roll: on every reconcile the operator stamps a hash of the TLS Secret's tls.crt and ca.crt into the pod template of the Redis StatefulSet and the Sentinel Deployment, so a renewed certificate rolls Redis through the operator's own roller and Sentinel through its Deployment. The effective spec.tls.authClients value is folded into the same hash, so changing it rolls the pods the same way instead of landing at the next unrelated restart, and the operator presents its client certificate whenever the Secret carries one, independent of that field, so neither direction of the change locks it out of the instance it reconciles. It also mounts the TLS volume 0440 when the pod declares an fsGroup, rejects a caCertSecretName that names the TLS Secret itself, and waits for the TLS material before it writes the ConfigMaps and the workloads, so a first TLS install starts its pods once. tls.enabled is fixed at creation. Redis replication and Sentinel cannot straddle plaintext and TLS: a replica restarted onto the other protocol cannot sync from the master, and Sentinels restarted onto it fail over to such a replica while the master still takes writes. The rule that refuses the change is a CEL transition rule on the RedisFailover spec; it lives in the CRD, so it ships here through patches/crd-tls.diff together with the schema block it references. The cut carries source only, and the Dockerfile strips the tarball's manifests/, charts/, example/ and .github/ before applying the patches, so the image builds from source alone and the two upstream tests that read the CRD YAML skip instead of failing against v3.3.5's stale copy; the CRD half is patches/crd-tls.diff. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. tls.diff also carries one change that is not TLS and takes effect with TLS off: MakeSlaveOfWithPort connects to the replica on its own port rather than on the master's. It changes a dial, not a pod template, so nothing rolls when this image ships; the probes dial localhost only under TLS, and the plaintext pod templates stay byte-identical to v3.3.5. The patch header names it, so a reader of patches/ does not take the file for TLS-only. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 2, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. tls.diff is cut from that PR's commit 2ad2ed8d1 rebased onto v3.3.5, and its header pins that SHA so the next refresh can be diffed against it. Beyond the TLS listener it carries the renewal roll: on every reconcile the operator stamps a hash of the TLS Secret's tls.crt and ca.crt into the pod template of the Redis StatefulSet and the Sentinel Deployment, so a renewed certificate rolls Redis through the operator's own roller and Sentinel through its Deployment. The effective spec.tls.authClients value is folded into the same hash, so changing it rolls the pods the same way instead of landing at the next unrelated restart, and the operator presents its client certificate whenever the Secret carries one, independent of that field, so neither direction of the change locks it out of the instance it reconciles. It also mounts the TLS volume 0440 when the pod declares an fsGroup, rejects a caCertSecretName that names the TLS Secret itself, and waits for the TLS material before it writes the ConfigMaps and the workloads, so a first TLS install starts its pods once. tls.enabled is fixed at creation. Redis replication and Sentinel cannot straddle plaintext and TLS: a replica restarted onto the other protocol cannot sync from the master, and Sentinels restarted onto it fail over to such a replica while the master still takes writes. The rule that refuses the change is a CEL transition rule on the RedisFailover spec; it lives in the CRD, so it ships here through patches/crd-tls.diff together with the schema block it references. The cut carries source only, and the Dockerfile strips the tarball's manifests/, charts/, example/ and .github/ before applying the patches, so the image builds from source alone and the two upstream tests that read the CRD YAML skip instead of failing against v3.3.5's stale copy; the CRD half is patches/crd-tls.diff. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. tls.diff also carries one change that is not TLS and takes effect with TLS off: MakeSlaveOfWithPort connects to the replica on its own port rather than on the master's. It changes a dial, not a pod template, so nothing rolls when this image ships; the probes dial localhost only under TLS, and the plaintext pod templates stay byte-identical to v3.3.5. The patch header names it, so a reader of patches/ does not take the file for TLS-only. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 2, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. tls.diff is cut from that PR's commit 2ad2ed8d1 rebased onto v3.3.5, and its header pins that SHA so the next refresh can be diffed against it. Beyond the TLS listener it carries the renewal roll: on every reconcile the operator stamps a hash of the TLS Secret's tls.crt and ca.crt into the pod template of the Redis StatefulSet and the Sentinel Deployment, so a renewed certificate rolls Redis through the operator's own roller and Sentinel through its Deployment. The effective spec.tls.authClients value is folded into the same hash, so changing it rolls the pods the same way instead of landing at the next unrelated restart, and the operator presents its client certificate whenever the Secret carries one, independent of that field, so neither direction of the change locks it out of the instance it reconciles. It also mounts the TLS volume 0440 when the pod declares an fsGroup, rejects a caCertSecretName that names the TLS Secret itself, and waits for the TLS material before it writes the ConfigMaps and the workloads, so a first TLS install starts its pods once. tls.enabled is fixed at creation. Redis replication and Sentinel cannot straddle plaintext and TLS: a replica restarted onto the other protocol cannot sync from the master, and Sentinels restarted onto it fail over to such a replica while the master still takes writes. The rule that refuses the change is a CEL transition rule on the RedisFailover spec; it lives in the CRD, so it ships here through patches/crd-tls.diff together with the schema block it references. The cut carries source only, and the Dockerfile strips the tarball's manifests/, charts/, example/ and .github/ before applying the patches, so the image builds from source alone and the two upstream tests that read the CRD YAML skip instead of failing against v3.3.5's stale copy; the CRD half is patches/crd-tls.diff. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. tls.diff also carries one change that is not TLS and takes effect with TLS off: MakeSlaveOfWithPort connects to the replica on its own port rather than on the master's. It changes a dial, not a pod template, so nothing rolls when this image ships; the probes dial localhost only under TLS, and the plaintext pod templates stay byte-identical to v3.3.5. The patch header names it, so a reader of patches/ does not take the file for TLS-only. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 2, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. tls.diff is cut from that PR's commit 2ad2ed8d1 rebased onto v3.3.5, and its header pins that SHA so the next refresh can be diffed against it. Beyond the TLS listener it carries the renewal roll: on every reconcile the operator stamps a hash of the TLS Secret's tls.crt and ca.crt into the pod template of the Redis StatefulSet and the Sentinel Deployment, so a renewed certificate rolls Redis through the operator's own roller and Sentinel through its Deployment. The effective spec.tls.authClients value is folded into the same hash, so changing it rolls the pods the same way instead of landing at the next unrelated restart, and the operator presents its client certificate whenever the Secret carries one, independent of that field, so neither direction of the change locks it out of the instance it reconciles. It also mounts the TLS volume 0440 when the pod declares an fsGroup, rejects a caCertSecretName that names the TLS Secret itself, and waits for the TLS material before it writes the ConfigMaps and the workloads, so a first TLS install starts its pods once. tls.enabled is fixed at creation. Redis replication and Sentinel cannot straddle plaintext and TLS: a replica restarted onto the other protocol cannot sync from the master, and Sentinels restarted onto it fail over to such a replica while the master still takes writes. The rule that refuses the change is a CEL transition rule on the RedisFailover spec; it lives in the CRD, so it ships here through patches/crd-tls.diff together with the schema block it references. The cut carries source only, and the Dockerfile strips the tarball's manifests/, charts/, example/ and .github/ before applying the patches, so the image builds from source alone and the two upstream tests that read the CRD YAML skip instead of failing against v3.3.5's stale copy; the CRD half is patches/crd-tls.diff. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. tls.diff also carries one change that is not TLS and takes effect with TLS off: MakeSlaveOfWithPort connects to the replica on its own port rather than on the master's. It changes a dial, not a pod template, so nothing rolls when this image ships; the probes dial localhost only under TLS, and the plaintext pod templates stay byte-identical to v3.3.5. The patch header names it, so a reader of patches/ does not take the file for TLS-only. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 2, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. tls.diff is cut from that PR's commit 2ad2ed8d1 rebased onto v3.3.5, and its header pins that SHA so the next refresh can be diffed against it. Beyond the TLS listener it carries the renewal roll: on every reconcile the operator stamps a hash of the TLS Secret's tls.crt and ca.crt into the pod template of the Redis StatefulSet and the Sentinel Deployment, so a renewed certificate rolls Redis through the operator's own roller and Sentinel through its Deployment. The effective spec.tls.authClients value is folded into the same hash, so changing it rolls the pods the same way instead of landing at the next unrelated restart, and the operator presents its client certificate whenever the Secret carries one, independent of that field, so neither direction of the change locks it out of the instance it reconciles. It also mounts the TLS volume 0440 when the pod declares an fsGroup, rejects a caCertSecretName that names the TLS Secret itself, and waits for the TLS material before it writes the ConfigMaps and the workloads, so a first TLS install starts its pods once. tls.enabled is fixed at creation. Redis replication and Sentinel cannot straddle plaintext and TLS: a replica restarted onto the other protocol cannot sync from the master, and Sentinels restarted onto it fail over to such a replica while the master still takes writes. The rule that refuses the change is a CEL transition rule on the RedisFailover spec; it lives in the CRD, so it ships here through patches/crd-tls.diff together with the schema block it references. The cut carries source only, and the Dockerfile strips the tarball's manifests/, charts/, example/ and .github/ before applying the patches, so the image builds from source alone and the two upstream tests that read the CRD YAML skip instead of failing against v3.3.5's stale copy; the CRD half is patches/crd-tls.diff. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. tls.diff also carries one change that is not TLS and takes effect with TLS off: MakeSlaveOfWithPort connects to the replica on its own port rather than on the master's. It changes a dial, not a pod template, so nothing rolls when this image ships; the probes dial localhost only under TLS, and the plaintext pod templates stay byte-identical to v3.3.5. The patch header names it, so a reader of patches/ does not take the file for TLS-only. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 2, 2026
freshworks-oss/redis-operator v3.3.5 has no TLS support. The operator work that packages/apps/redis renders against was ported upstream as freshworks-oss/redis-operator#85 and is not in a release yet, so carry it here over the v3.3.5 tarball until one lands. Three pieces, and TLS is silently off unless all three are present: - images/redis-operator/patches/tls.diff is the source half. The Dockerfile already applies patches/*.diff, and the shell expands that to labels.diff then tls.diff; they touch disjoint files, so the order does not matter, but it is alphabetically stable either way. - patches/crd-tls.diff teaches the vendored CRD about spec.tls. Without it the apiserver prunes spec.tls from every RedisFailover the redis chart renders and the patched binary waits for a field it never sees. - patches/rbac-tls.diff grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret named by spec.tls.caCertSecretName. Those are the only Secret calls in the patched source: upstream v3.3.5 only ever reads one, and the patch adds Create and Update on a Secret it addresses by name, so nothing lists, watches, patches or deletes. tls.diff is cut from that PR's commit 2ad2ed8d1 rebased onto v3.3.5, and its header pins that SHA so the next refresh can be diffed against it. Beyond the TLS listener it carries the renewal roll: on every reconcile the operator stamps a hash of the TLS Secret's tls.crt and ca.crt into the pod template of the Redis StatefulSet and the Sentinel Deployment, so a renewed certificate rolls Redis through the operator's own roller and Sentinel through its Deployment. The effective spec.tls.authClients value is folded into the same hash, so changing it rolls the pods the same way instead of landing at the next unrelated restart, and the operator presents its client certificate whenever the Secret carries one, independent of that field, so neither direction of the change locks it out of the instance it reconciles. It also mounts the TLS volume 0440 when the pod declares an fsGroup, rejects a caCertSecretName that names the TLS Secret itself, and waits for the TLS material before it writes the ConfigMaps and the workloads, so a first TLS install starts its pods once. tls.enabled is fixed at creation. Redis replication and Sentinel cannot straddle plaintext and TLS: a replica restarted onto the other protocol cannot sync from the master, and Sentinels restarted onto it fail over to such a replica while the master still takes writes. The rule that refuses the change is a CEL transition rule on the RedisFailover spec; it lives in the CRD, so it ships here through patches/crd-tls.diff together with the schema block it references. The cut carries source only, and the Dockerfile strips the tarball's manifests/, charts/, example/ and .github/ before applying the patches, so the image builds from source alone and the two upstream tests that read the CRD YAML skip instead of failing against v3.3.5's stale copy; the CRD half is patches/crd-tls.diff. cert-manager Certificates get no grant. The patched operator manages a Certificate only under spec.tls.certManager, and packages/apps/redis pins the other mode: it always supplies spec.tls.certificateSecret, so that code path is unreachable as the platform ships it. A comment at the rule site records the decision and names the verbs the rule would need, so a re-vendor review reads the absence as deliberate. The chart patches go through the mechanism the packages that customise a vendored chart already use — reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji all re-apply a patches/*.diff at the end of update: — because `rm -rf charts` discards a hand-edit and the next `make update` would take TLS back out without failing. tls.diff also carries one change that is not TLS and takes effect with TLS off: MakeSlaveOfWithPort connects to the replica on its own port rather than on the master's. It changes a dial, not a pod template, so nothing rolls when this image ships; the probes dial localhost only under TLS, and the plaintext pod templates stay byte-identical to v3.3.5. The patch header names it, so a reader of patches/ does not take the file for TLS-only. The grant is narrower than the ported operator's own chart asks for: that one also grants patch on Secrets, and create, delete, get, list, patch, update and watch on Certificates. None of that is reachable from the source as shipped here. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
This was referenced Sep 2, 2026
lllamnyp
added a commit
to cozystack/community
that referenced
this pull request
Sep 3, 2026
The engine table described `main` in the present tense, so it goes stale every time the contract lands somewhere new. Anchor it to one dated moment and drop "today" from the two column headers and the takeaway; the table is a record of the gap this contract closes, not a tracker of `main`. Three claims were stale under that anchor. postgres, nats and qdrant all render a TenantProjection sentinel on `main` and deliver `<release>.tenant-ca`, so their "ca.crt to tenant?" cells and the takeaway now say so, and section 6 and the rollout list no longer carry nats and qdrant as convergence still to come. Two identifiers were wrong outright: redis's CA Secret is `<release>.ca-tls`, with a dot for the same collision-across-releases reason section 4 gives for the canonical name, and the carried operator patch is cut from freshworks-oss/redis-operator#85 commit 2ad2ed8d1. mariadb's `<release>-ca-tls` is hyphenated and is left alone. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01EoDWFXj3QE4Afg7Et9wFxy Signed-off-by: Timofei Larkin <[email protected]>
lexfrei
pushed a commit
to cozystack/community
that referenced
this pull request
Sep 3, 2026
The engine table described `main` in the present tense, so it goes stale every time the contract lands somewhere new. Anchor it to one dated moment and drop "today" from the two column headers and the takeaway; the table is a record of the gap this contract closes, not a tracker of `main`. Three claims were stale under that anchor. postgres, nats and qdrant all render a TenantProjection sentinel on `main` and deliver `<release>.tenant-ca`, so their "ca.crt to tenant?" cells and the takeaway now say so, and section 6 and the rollout list no longer carry nats and qdrant as convergence still to come. Two identifiers were wrong outright: redis's CA Secret is `<release>.ca-tls`, with a dot for the same collision-across-releases reason section 4 gives for the canonical name, and the carried operator patch is cut from freshworks-oss/redis-operator#85 commit 2ad2ed8d1. mariadb's `<release>-ca-tls` is hyphenated and is left alone. Assisted-by: LLM Signed-off-by: Timofei Larkin <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
pushed a commit
to cozystack/community
that referenced
this pull request
Sep 3, 2026
The engine table described `main` in the present tense, so it goes stale every time the contract lands somewhere new. Anchor it to one dated moment and drop "today" from the two column headers and the takeaway; the table is a record of the gap this contract closes, not a tracker of `main`. Three claims were stale under that anchor. postgres, nats and qdrant all render a TenantProjection sentinel on `main` and deliver `<release>.tenant-ca`, so their "ca.crt to tenant?" cells and the takeaway now say so, and section 6 and the rollout list no longer carry nats and qdrant as convergence still to come. Two identifiers were wrong outright: redis's CA Secret is `<release>.ca-tls`, with a dot for the same collision-across-releases reason section 4 gives for the canonical name, and the carried operator patch is cut from freshworks-oss/redis-operator#85 commit 2ad2ed8d1. mariadb's `<release>-ca-tls` is hyphenated and is left alone. Assisted-by: LLM Signed-off-by: Timofei Larkin <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
pushed a commit
to cozystack/community
that referenced
this pull request
Sep 4, 2026
The engine table described `main` in the present tense, so it goes stale every time the contract lands somewhere new. Anchor it to one dated moment and drop "today" from the two column headers and the takeaway; the table is a record of the gap this contract closes, not a tracker of `main`. Three claims were stale under that anchor. postgres, nats and qdrant all render a TenantProjection sentinel on `main` and deliver `<release>.tenant-ca`, so their "ca.crt to tenant?" cells and the takeaway now say so, and section 6 and the rollout list no longer carry nats and qdrant as convergence still to come. Two identifiers were wrong outright: redis's CA Secret is `<release>.ca-tls`, with a dot for the same collision-across-releases reason section 4 gives for the canonical name, and the carried operator patch is cut from freshworks-oss/redis-operator#85 commit 2ad2ed8d1. mariadb's `<release>-ca-tls` is hyphenated and is left alone. Assisted-by: LLM Signed-off-by: Timofei Larkin <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei
added a commit
to cozystack/cozystack
that referenced
this pull request
Sep 4, 2026
## What this PR does `tls.enabled` puts Redis and Sentinel on a TLS-only listener with a per-release cert-manager chain, and hands the tenant the CA certificate as `redis-<name>.tenant-ca`. Off unless set. redis-operator v3.3.5 has no TLS support. The work is ported upstream in freshworks-oss/redis-operator#85, which is open and not in a release, so this carries it as three patches over the v3.3.5 tarball. `images/redis-operator/patches/tls.diff` is the source half, cut from that PR's commit `2ad2ed8d1`, which the patch header pins; it is applied by the glob the image Dockerfile already runs, after the Dockerfile strips the tarball's `manifests`, `charts`, `example` and `.github`, so the image builds from source alone and the upstream tests that read the CRD YAML skip instead of failing against the stale v3.3.5 copy. `patches/crd-tls.diff` adds `spec.tls` to the vendored CRD, and with it the CEL rule that fixes `tls.enabled` at creation; without the schema block the apiserver prunes the field on admission and the patched binary waits for something it never sees, and the rule cannot exist without the block it references. `patches/rbac-tls.diff` grants Create, Get and Update on Secrets, so the operator can publish the CA-only Secret it addresses by name. That is the whole delta, and it is narrower than the ported operator's own chart asks for: those three are the only Secret calls in the patched source, and cert-manager Certificates get no grant at all, because the operator only touches one under `spec.tls.certManager` and this chart pins `certificateSecret` mode instead. One change in `tls.diff` is not TLS and takes effect with TLS off, named in the patch header: `MakeSlaveOfWithPort` connects to the replica on its own port rather than on the master's. It changes a dial, not a pod template, so shipping the rebuilt image rolls nothing; the plaintext pod templates stay byte-identical to v3.3.5. The image build registration this branch used to carry (`make -C packages/system/redis-operator image` in the root `build:` target) landed on main with the Valkey service (#3380), so the rebuilt operator image is produced by CI from main as well; the digest in `values.yaml` is still refreshed by release preparation, not here. The chart patches re-apply at the end of `update:`, the same way reloader, grafana-operator, ingress-nginx, seaweedfs and kamaji carry theirs. Otherwise `rm -rf charts` takes TLS back out on the next `make update` and nothing fails. `make update` reproduces the committed tree byte for byte. TLS is chosen when the instance is created. The config gets `port 0` and the listener moves to `tls-port`, so TLS replaces plaintext rather than running beside it, and a running instance cannot change mode: a replica restarted onto the TLS listener cannot replicate from a master still on plaintext, and Sentinels already on TLS would fail over to a stale replica. The RedisFailover schema in the carried CRD patch rejects a change of `tls.enabled`, which on an existing instance surfaces as a failed HelmRelease upgrade while the instance keeps serving what it did; the README points at creating a new instance and migrating. That is also why TLS is not inferred from `external`: an externally reachable instance is the one most likely to have clients an upgrade must not drop. Existing releases keep their plaintext listener and are not restarted by the rebuilt operator image. The tenant gets `ca.crt` and nothing else, through `tenantsecrets`. The chart's own Secrets take a dot between the release and the suffix (`<release>.ca-tls`, `<release>.tls`, `<release>.ca-cert`): the suffixes are dot-free, so the split is unique and release `foo`'s CA Secret can no longer be release `foo-ca`'s leaf, the collision the hyphenated form had. The chart renders a `TenantProjection` pointing at `<release>.ca-tls`, and the CA-extraction controller re-encodes the one named key from the parsed certificate, so nothing that is not a certificate gets through. Same path as postgres, mongodb, nats and qdrant. No Secret of this release is granted to the tenant by name beyond the generated password, and that includes `<release>.ca-cert`, the CA-only copy the operator publishes for itself. It holds no key today, but the operator has Create and Update on Secrets cluster-wide, so what sits at that name is the operator's call rather than the platform's, and RBAC cannot filter by key. `hack/check-redis-rd-secrets.bats` pins the whole rendered Secret surface instead of a list of known-bad names, because an include with no `resourceNames` and no `matchLabels` restricts nothing. The chainsaw suite for redis gains two cases. A TLS fixture asserts the cert-manager chain is issued, the TLS-probed Redis replicas and Sentinel come up, the operator publishes its CA-only Secret under the widened ClusterRole, the tenant receives exactly `ca.crt` through `tenantsecrets` while the key-bearing Secrets stay off that path, and a `redis-cli --tls` PING through the service name completes with the same CA. A second case applies `tls.enabled` to a running plaintext release and asserts the refusal: the HelmRelease upgrade fails with the schema's message, the StatefulSet keeps its revision with both replicas Ready, plaintext still answers and no TLS listener appears. Certificate renewal rolls the pods from inside the operator. Redis and Sentinel read the certificate once at startup, so the patched operator stamps a hash of the TLS Secret's `tls.crt` and `ca.crt` into the pod template of both the Redis StatefulSet and the Sentinel Deployment on every reconcile, as `redis-failover.freshworks.com/tls-secret-hash`. A renewal changes the hash; the operator's own roller replaces the Redis pods one at a time and the Deployment controller rolls Sentinel. README names the fallback: if the roll cannot run, the deadline is the old certificate's expiry, past which the operator's own TLS connections fail along with the clients. `tls.authClients` maps to `tls-auth-clients` and defaults to `no`. The platform mints no client certificate for the tenant and the CA key is out of reach, so `yes` is only usable when the client certificate comes from whoever also controls the CA. Changing the value on a running release restarts the Redis and Sentinel pods: Redis reads the directive from its config file only at startup, so the operator folds the effective value into the certificate hash that drives the rollout, and the change lands when it is made rather than at the next unrelated restart. Follow-ups in the carried operator patch go upstream first, to freshworks-oss/redis-operator#85 or a successor there, and are picked up here afterwards; the carried patch does not grow Go that upstream has not seen. `tlsConfigFor` fetches the Secret on every call, tens of GETs per reconcile. The renewal roll is static analysis so far: the live check, `cmctl renew` on a running release while watching the `rfr-*` and `rfs-*` pods roll, is still owed and belongs with the e2e follow-up. Two facts about the shipped image rather than the patch. `packages/system/redis-operator/values.yaml` keeps the digest of the image built before the patch until release preparation rebuilds it, so on `main` between this merge and the next release-prep, `tls.enabled` renders the chain and `spec.tls` while the running operator ignores them and serves plaintext. And the pinned v3.3.5 tarball carries GO-2026-5026 in `golang.org/x/net` v0.53.0, reached through `PodService.UpdatePodLabels`; the port neither introduces nor fixes it, upstream `master` is already on v0.55.0, so it lands with the next tag bump rather than here. Outside the patch: `cozyvalues-gen` renders `{}` in the README Value column for `tls.authClients`: a child property without a default inherits the parent object's `{}`, and `make generate` reproduces it byte for byte, so it is a generator bug rather than something to hand-edit here. ### Screenshots No UI changes. ### Downstream repositories - [ ] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [x] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: cozystack/terraform-provider-cozystack#37 - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: I walked the trigger map against the diff file by file. terraform-provider-cozystack is reached, tracked as cozystack/terraform-provider-cozystack#37 rather than a speculative PR: `values.schema.json` gains a `tls` object, and the provider hand-writes a schema, model and expand/flatten pair per Kind. It already models `tls` for postgres, kafka, nats and qdrant, not for redis. Redis needs different wording from those four, whose descriptions say to omit the block to follow `external`, which is the one thing redis does not do. Nothing else is reached. The website regenerates this package's reference page from `README.md` on a stable tag, so the README changes need no PR there. No package added, renamed or removed. `packages/core/platform/values.yaml`, variant and bundle composition and release asset names are untouched, and so are `hack/package.mk`, `hack/common-envs.mk` and `hack/update-crd.sh`, which is what ccp and external-apps-example read. The two new files under `hack/` are bats unit tests. No node prerequisite, installer value, telemetry metric or cozy-proxy label changes. ### Release note ```release-note feat(redis): add opt-in TLS for Redis and Sentinel. Set `tls.enabled: true` to serve both on a TLS-only listener backed by a per-release cert-manager chain; the tenant reads the CA certificate as the `<release>.tenant-ca` tenant secret. TLS is off unless set and is not inferred from `external`, so existing releases keep serving plaintext and are not restarted by the rebuilt operator image. TLS is chosen at creation: a running instance cannot switch modes, the change is rejected and surfaces as a failed HelmRelease upgrade, so add TLS by creating a new instance and migrating to it. Requires cert-manager, which the platform's `system` bundle installs on every variant. A renewed certificate rolls the Redis and Sentinel pods through the operator. TLS support is carried as a downstream patch over redis-operator v3.3.5 until freshworks-oss/redis-operator#85 lands in a release. ```
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
New optional
spec.tls. With it on, Redis and Sentinel close the plaintext port, listen ontls-port, and mount the cert read-only at/tls, at mode 0440 when the pod has an fsGroup (without one the kubelet leaves the projected filesroot:rootand a non-root container could not read them, so the default mode stays). Every redis-cli the operator generates (shutdown and readiness scripts, exec probes) gets--tls --cert --key --cacert, and the redis_exporter sidecars get the matchingREDIS_EXPORTER_TLS_*env and dialrediss://.The cert comes from one of two places, and validation rejects both or neither.
spec.tls.certManager.issuerRefpoints at an Issuer or ClusterIssuer and the operator creates the Certificate itself.spec.tls.certificateSecret.secretNamepoints at a Secret managed elsewhere. Validation also rejects acaCertSecretNamethat names the TLS Secret itself, in either mode, because publishing the CA-only Secret there would overwrite the serving certificate.SANs cover the four Service names in short, namespaced,
.svcand.svc.<domain>form, a wildcard for the headless per-pod records so changing the replica count does not re-issue, andlocalhostplus127.0.0.1/::1for the in-pod self-dials (probes, exporters, the Sentinel monitor target) that would otherwise fail verification. The domain comes from a new--cluster-domainflag defaulting tocluster.local, since hardcoding it breaks every cluster running a different one.spec.tls.certManager.extraSANsappends anything else; entries parse as IP or DNS automatically.The operator's own Redis and Sentinel client dials TLS as well, so check-and-heal keeps working against a TLS-only failover. It validates with the CA from the cluster Secret and a ServerName override, because pod IPs are unstable but the headless service name is in the SAN list. Under
spec.tls.authClients: yesit also presents the leaf cert and key from the same Secret, so mutual TLS is usable instead of a setting that locks the operator out.The operator also publishes a second Secret holding only
ca.crt, named<tls-secret>-caby default and overridable viaspec.tls.caCertSecretNameas long as it does not collide with the TLS Secret. A client that verifies the server needs the CA and nothing else; handing it the issued Secret hands ittls.keytoo. This one can be granted on its own. It defers quietly untilca.crtappears, since cert-manager fills the Secret asynchronously.TLS is chosen when the RedisFailover is created and cannot be turned on or off afterwards, which the CRD enforces with a transition rule on the spec. Redis replication and Sentinel cannot straddle two wire protocols: a replica restarted onto the other protocol cannot sync from the master, and Sentinels restarted onto it declare the master down and fail over to that replica while the master is still taking writes. An absent
tlsblock andenabled: falseare the same state, so adding a disabled block to a plaintext failover is fine;issuerRef,caCertSecretName,extraSANsandauthClientsstay mutable. A dual-listener transition, bothportandtls-portopen while replication moves across, would make the flip safe and is not part of this.The operator also holds off on the ConfigMaps, StatefulSet and Deployment until the TLS Secret exists, so a first install with cert-manager does not create the pods and then roll them again once the certificate lands.
Renewal rolls the pods. On every reconcile the operator stamps a hash of the Secret's
tls.crtandca.crtasredis-failover.freshworks.com/tls-secret-hashon the pod template of both the Redis StatefulSet and the Sentinel Deployment, taken from the Secret read it already does for the CA-only publish. Redis is an OnDelete StatefulSet, so the operator's own roller sees the new revision and replaces one pod per reconcile; the Sentinel Deployment rolls itself. Redis loads the certificate and the CA bundle once at startup and re-reads neither, which is why a change to either has to restart the pod.tls.keyis not part of the hash: it rotates with the certificate, and there is no reason to derive a published value from private key material.The chart's ClusterRole gains create, get and update on certificates in
cert-manager.ioand on secrets, the verbs the code calls and no others. It does not gain list, watch, patch or delete: the operator reads one Secret by name and never enumerates them, and the CA-only Secret goes away through its owner reference.spec.tlsis absent by default and every code path sits behindTLSEnabled(rf), so existing failovers are untouched. That is pinned, not assumed: the probes diallocalhostonly under TLS (the bare$(hostname)is not in the SAN list) and keep the upstream$(hostname)form otherwise, a test holds the plaintext probe commands to the v3.3.5 literals, and a dump of the generated StatefulSet, Deployment, Services and ConfigMaps across eight failover shapes withspec.tlsabsent differs from v3.3.5 by zero bytes, so an operator upgrade does not roll workloads whose spec did not change. The two CRD schema tests skip when a tree carries no generated CRD at all, for consumers that vendor the operator as source only. Two dependency changes come with it:github.com/cert-manager/cert-manager v1.18.5for the typed API and clientset, andk8s.io/apiextensions-apiserverfrom v0.28.4 to v0.32.0 because that clientset needs it.golang.org/x/textmoves to v0.39.0 as well, to clear the govulncheck finding on an indirect dependency master already carries. cert-manager itself does not have to be installed: with nothing opting into TLS the operator never touches the Certificate API.Origin: Arsolitt wrote this in a now-archived downstream fork of spotahome/redis-operator that the cozystack project used to run. I cherry-picked rather than rewrote so the authorship survives. Adapting it here meant routing the TLS flags and probes through the engine-aware CLI binary from
EngineFor()so Valkey getsvalkey-cli, keeping theDisableMyMasterbranch in the sentinel template andrf.MasterName()in the sentinel probe, threading the new*tls.Configafter themasterNameparameters this repo already carries, and pinning cert-manager on the 1.18 line because a newer pin drags k8s.io/api, apimachinery and client-go up with it. That pin is also whyissuerRefis typedcmmeta.ObjectReference, the same struct cert-manager 1.19+ renamed toIssuerReference. The renewal roll, the name-collision check and the mount mode are additions on top of the port.The immutability rule is tested by handing the committed CRD's
x-kubernetes-validationsto the apiserver's own CEL engine and validating old/new objects against it, rather than restating the rule in Go where the two could drift. That is what pullsk8s.io/apiserver,cel-goand their transitive requires intogo.modas indirect. They are test-only: the module set ofgo list -deps ./cmd/...is the same 54 modules before and after, and the image build runsgo build.Testing:
go build ./...,go test ./...andgolangci-lint run -E goimportsare green, the last two in the repo dev image, the integration suite compiles under-tags integration, and govulncheck reports no affecting vulnerabilities.helm lintandhelm templatepass. New unit tests cover the redis and sentinel config directives, the volume and mount layout on both pods including the 0440 mode with and without an fsGroup, the exporter env, the probe and script flags, the Secret name precedence and the rejection of a CA Secret name colliding with the TLS Secret in all three forms, the Certificate's SANs and usages under both the default and a custom cluster domain, the CA-only Secret carryingca.crtand neithertls.crtnortls.key, the renewal hash on both pod templates (present with TLS on, absent with it off, changing whentls.crtorca.crtchanges, user annotations preserved, the informer's map never mutated), and BuildTLSConfig across empty CA, missing ServerName, malformed PEM, client cert loaded and cert-without-key. The CRD is regenerated with controller-gen 0.17.3 and the deepcopy with code-generator 1.33.0, the versionsghcr.io/slok/kube-code-generator:v0.7.0bundles; the chart is bumped to 3.4.0 for the version-check job. Mocks are hand-written in the generated style becausego generate ./mocksdoes not run here: mockery 2.45.0 fails under the Go version in go.mod withinternal error: package "fmt" without types.