feat(redis): add operator-managed TLS via cert-manager PKI chain

Expose tls.enabled in the Redis chart values, mirroring the pattern
already in use by mariadb, nats, opensearch, qdrant and rabbitmq. The
flag is tri-state: when unset, TLS follows the value of `external`; an
explicit boolean overrides the default.

When TLS is enabled the chart renders the standard cozystack 4-resource
cert-manager chain in the release namespace:

  - Issuer (self-signed bootstrap)
  - Certificate (CA, ECDSA, isCA, rotationPolicy: Never, 5y)
  - Issuer (CA-backed)
  - Certificate (leaf, secret <release>-tls, ECDSA, 1y, rotationPolicy: Always)

The leaf certificate covers the SAN list the redis-operator computes for
its own Certificate (operator/redisfailover/service/generator.go:
redisCertificateDNSNames): short, namespace, .svc and .svc.<clusterDomain>
forms for rfr- / rfrm- / rfrs- / rfs- services plus a wildcard for
per-pod headless DNS names of the redis statefulset. Localhost is
included for in-pod readiness probes; when `external` is true the
tenant LB hostname is added too.

The chart hands the resulting Secret to the operator via
spec.tls.certificateSecret.secretName so the operator never creates a
duplicate Certificate; it just mounts the Secret into both Redis and
Sentinel pods and wires the redis tls-* directives. tls.authClients
maps to the Redis tls-auth-clients directive and defaults to "no".

The dashboard-resources Role is extended with the new TLS secret names
only when TLS is on, so the cozystack dashboard can read them to
display connection details.

Helm unit tests in tests/tls_test.yaml cover the tri-state resolution
(four enable/external combinations), SAN list coverage for all four
service names and the wildcard, custom cluster-domain handling, the
external SAN injection path, authClients propagation, and dashboard
RBAC expansion.

The comment above the CA usages named the wrong bits: cert-manager maps
signing to the digital signature bit, and crl sign and ocsp signing are
separate usages this chart does not request.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
This commit is contained in:
Arsolitt authored and Aleksei Sviridkin committed 2026-09-02 17:56:05 +03:00
1 parent 86fe8e5a7e
commit 2ea4aad5de
10 files changed
+626 -3

No files matched your search

+10
View File
@@ -36,6 +36,9 @@ type ConfigSpec struct {
// Enable external access from outside the cluster.
// +kubebuilder:default:=false
External bool `json:"external"`
// TLS configuration. When omitted, TLS is enabled automatically when `external` is true.
// +kubebuilder:default:={}
Tls TLS `json:"tls,omitempty"`
// Redis major version to deploy
// +kubebuilder:default:="v8"
Version Version `json:"version"`
@@ -51,6 +54,13 @@ type Resources struct {
Memory resource.Quantity `json:"memory,omitempty"`
}
type TLS struct {
// Maps to the Redis `tls-auth-clients` directive. One of `no`, `optional`, `yes`. Defaults to `no` — the server certificate is presented but client certificates are not validated.
AuthClients string `json:"authClients,omitempty"`
// Enable TLS for Redis and Sentinel connections. When omitted, defaults to the value of `external`. Encryption is provided by the redis-operator fork that mounts the certificate Secret into both Redis and Sentinel pods at `/tls`.
Enabled *bool `json:"enabled,omitempty"`
}
// +kubebuilder:validation:Enum="t1.nano";"t1.micro";"t1.small";"t1.medium";"t1.large";"t1.xlarge";"t1.2xlarge";"t1.4xlarge";"c1.nano";"c1.micro";"c1.small";"c1.medium";"c1.large";"c1.xlarge";"c1.2xlarge";"c1.4xlarge";"s1.nano";"s1.micro";"s1.small";"s1.medium";"s1.large";"s1.xlarge";"s1.2xlarge";"s1.4xlarge";"u1.nano";"u1.micro";"u1.small";"u1.medium";"u1.large";"u1.xlarge";"u1.2xlarge";"u1.4xlarge";"m1.nano";"m1.micro";"m1.small";"m1.medium";"m1.large";"m1.xlarge";"m1.2xlarge";"m1.4xlarge";"nano";"micro";"small";"medium";"large";"xlarge";"2xlarge"
type ResourcesPreset string
+10 -1
View File
@@ -25,7 +25,16 @@ Service utilizes the freshworks-oss Redis Operator (a maintained fork of the arc
| `size` | Persistent Volume Claim size available for application data. | `quantity` | `1Gi` |
| `storageClass` | StorageClass used to store the data. | `string` | `""` |
| `external` | Enable external access from outside the cluster. | `bool` | `false` |
| `version` | Redis major version to deploy | `string` | `v8` |
### TLS parameters
| Name | Description | Type | Value |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------ |
| `tls` | TLS configuration. When omitted, TLS is enabled automatically when `external` is true. | `object` | `{}` |
| `tls.enabled` | Enable TLS for Redis and Sentinel connections. When omitted, defaults to the value of `external`. Encryption is provided by the redis-operator fork that mounts the certificate Secret into both Redis and Sentinel pods at `/tls`. | `*bool` | `null` |
| `tls.authClients` | Maps to the Redis `tls-auth-clients` directive. One of `no`, `optional`, `yes`. Defaults to `no` — the server certificate is presented but client certificates are not validated. | `string` | `""` |
| `version` | Redis major version to deploy | `string` | `v8` |
### Application-specific parameters
+40
View File
@@ -0,0 +1,40 @@
{{/*
redis.tls.enabled resolves the tri-state tls.enabled field to a plain
string "true" or "false" so callers can use it with `eq`:
{{- $tlsEnabled := (include "redis.tls.enabled" .) | eq "true" -}}
Tri-state semantics:
- tls.enabled explicitly set (bool) → use that value
- tls.enabled unset or null → auto-on when external is true
- tls: null → treated as unset, falls back to external
`default (dict)` guards against tls: null (nil map). `kindIs "invalid"`
catches the case where the tls.enabled key is present but set to null
(hasKey returns true but index gives nil, and nil | toString = "<nil>"
which silently breaks the tri-state). Null value is treated the same as
unset: fall back to external.
*/}}
{{- define "redis.tls.enabled" -}}
{{- $tlsMap := default (dict) .Values.tls -}}
{{- $enabled := index $tlsMap "enabled" -}}
{{- if kindIs "invalid" $enabled -}}
{{- .Values.external | default false | toString -}}
{{- else -}}
{{- $enabled | toString -}}
{{- end -}}
{{- end -}}
{{/*
redis.tls.authClients resolves the optional tls.authClients field.
Returns "no" when unset to match the redis-operator default.
*/}}
{{- define "redis.tls.authClients" -}}
{{- $tlsMap := default (dict) .Values.tls -}}
{{- $authClients := index $tlsMap "authClients" -}}
{{- if kindIs "invalid" $authClients -}}
no
{{- else -}}
{{- $authClients -}}
{{- end -}}
{{- end -}}
@@ -0,0 +1,104 @@
{{- $tlsEnabled := (include "redis.tls.enabled" .) | eq "true" -}}
{{- if $tlsEnabled }}
{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cluster.local" }}
---
# Self-signed bootstrap Issuer — used only to sign the CA Certificate below.
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: {{ .Release.Name }}-selfsigned
namespace: {{ .Release.Namespace }}
spec:
selfSigned: {}
---
# CA Certificate. rotationPolicy: Never keeps the CA stable so existing
# client trust bundles remain valid across cert-manager renewals.
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: {{ .Release.Name }}-ca
namespace: {{ .Release.Namespace }}
spec:
isCA: true
commonName: {{ .Release.Name }}-ca
# A dot, not a hyphen: the Secret suffix set holds both -ca-tls and -tls, so
# hyphenated, release `foo`'s CA Secret and release `foo-ca`'s leaf Secret
# are both redis-foo-ca-tls. The Certificate and Issuer names keep the
# hyphen; their suffixes cannot overlap that way.
secretName: {{ .Release.Name }}.ca-tls
duration: 43800h
issuerRef:
name: {{ .Release.Name }}-selfsigned
kind: Issuer
group: cert-manager.io
privateKey:
rotationPolicy: Never
algorithm: ECDSA
size: 256
# cert sign is what lets this CA issue the leaf below; signing is the
# digital signature bit. CRL and OCSP signing are separate cert-manager
# usages and are absent, since nothing here publishes revocation.
usages:
- signing
- cert sign
---
# CA Issuer — used to sign the leaf server certificate.
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: {{ .Release.Name }}-ca
namespace: {{ .Release.Namespace }}
spec:
ca:
secretName: {{ .Release.Name }}.ca-tls
---
# Leaf server TLS Certificate passed to redis-operator via spec.tls.certificateSecret.
# The SAN list mirrors what the operator computes for its own Certificate
# (operator/redisfailover/service/generator.go: redisCertificateDNSNames):
# - per-service short, namespace, .svc and .svc.<clusterDomain> forms for
# rfr-/rfrm-/rfrs-/rfs- services
# - wildcard covering per-pod headless DNS for the redis statefulset
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: {{ .Release.Name }}-tls
namespace: {{ .Release.Namespace }}
spec:
secretName: {{ .Release.Name }}.tls
duration: 8760h
renewBefore: 720h
isCA: false
usages:
- server auth
- client auth
- key encipherment
dnsNames:
{{- $ns := .Release.Namespace }}
{{- $rfName := .Release.Name }}
{{- $redisSvc := printf "rfr-%s" $rfName }}
{{- $masterSvc := printf "rfrm-%s" $rfName }}
{{- $slaveSvc := printf "rfrs-%s" $rfName }}
{{- $sentinelSvc := printf "rfs-%s" $rfName }}
- localhost
{{- range $svc := list $redisSvc $masterSvc $slaveSvc $sentinelSvc }}
- {{ $svc | quote }}
- {{ printf "%s.%s" $svc $ns | quote }}
- {{ printf "%s.%s.svc" $svc $ns | quote }}
- {{ printf "%s.%s.svc.%s" $svc $ns $clusterDomain | quote }}
{{- end }}
- {{ printf "*.%s" $redisSvc | quote }}
- {{ printf "*.%s.%s" $redisSvc $ns | quote }}
- {{ printf "*.%s.%s.svc" $redisSvc $ns | quote }}
- {{ printf "*.%s.%s.svc.%s" $redisSvc $ns $clusterDomain | quote }}
{{- if .Values.external | default false }}
- {{ printf "%s.%s" .Release.Name .Values._namespace.host | quote }}
{{- end }}
privateKey:
rotationPolicy: Always
algorithm: ECDSA
size: 256
issuerRef:
name: {{ .Release.Name }}-ca
kind: Issuer
group: cert-manager.io
{{- end }}
@@ -1,3 +1,4 @@
{{- $tlsEnabled := (include "redis.tls.enabled" .) | eq "true" -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
@@ -19,6 +20,10 @@ rules:
- secrets
resourceNames:
- "{{ .Release.Name }}-auth"
{{- if $tlsEnabled }}
- "{{ .Release.Name }}.tls"
- "{{ .Release.Name }}.ca-tls"
{{- end }}
verbs: ["get", "list", "watch"]
- apiGroups:
- cozystack.io
@@ -1,3 +1,4 @@
{{- $tlsEnabled := (include "redis.tls.enabled" .) | eq "true" -}}
{{- if .Values.authEnabled }}
{{- $existingPassword := lookup "v1" "Secret" .Release.Namespace (printf "%s-auth" .Release.Name) }}
{{- $password := randAlphaNum 32 | b64enc }}
@@ -28,6 +29,13 @@ metadata:
# silently ignored. Keep both sides in sync.
redis-failover.freshworks.com/operator-group: cozystack
spec:
{{- if $tlsEnabled }}
tls:
enabled: true
authClients: {{ include "redis.tls.authClients" . | quote }}
certificateSecret:
secretName: {{ .Release.Name }}.tls
{{- end }}
sentinel:
# Pin the sentinel engine. The freshworks-oss operator's compiled-in default
# moved 6.2.6→7.2.4; the data pods run a deliberate versionMap image below,
+421
View File
@@ -0,0 +1,421 @@
suite: TLS configuration for Redis
# Tests cover the tri-state tls.enabled logic:
# 1. external=false, tls.enabled unset -> TLS disabled
# 2. external=true, tls.enabled unset -> TLS enabled (inherits external)
# 3. external=true, tls.enabled=false -> TLS disabled (explicit overrides)
# 4. external=false, tls.enabled=true -> TLS enabled (explicit overrides)
# Plus authClients propagation, SAN coverage and dashboard RBAC.
release:
name: my-redis
namespace: tenant-test
set:
_cluster:
cluster-domain: cluster.local
_namespace:
host: example.com
tests:
# ------------------------------------------------------------------
# Case 1: external=false, tls.enabled unset -> no TLS resources
# ------------------------------------------------------------------
- it: "certmanager.yaml renders no documents when external=false and tls.enabled is unset"
templates:
- templates/certmanager.yaml
set:
external: false
asserts:
- hasDocuments:
count: 0
- it: "redisfailover.yaml does not have spec.tls when external=false and tls.enabled is unset"
templates:
- templates/redisfailover.yaml
set:
external: false
documentSelector:
path: kind
value: RedisFailover
asserts:
- notExists:
path: spec.tls
- it: "dashboard-resourcemap.yaml does not list TLS secrets when external=false and tls.enabled is unset"
templates:
- templates/dashboard-resourcemap.yaml
set:
external: false
documentSelector:
path: kind
value: Role
asserts:
# The negatives below address rules[1] by index, and notContains is
# fail-open on a path that does not exist, so a SECOND secrets rule
# granting the key-bearing Secrets would satisfy every one of them.
# Pin the rule count: the Role renders services, secrets and
# workloadmonitors, and nothing else.
- lengthEqual:
path: rules
count: 3
- notContains:
path: rules[1].resourceNames
content: "my-redis.tls"
- notContains:
path: rules[1].resourceNames
content: "my-redis.ca-tls"
# ------------------------------------------------------------------
# Case 2: external=true, tls.enabled unset -> TLS enabled via external
# ------------------------------------------------------------------
- it: "certmanager.yaml renders 4 documents when external=true and tls.enabled is unset"
templates:
- templates/certmanager.yaml
set:
external: true
asserts:
- hasDocuments:
count: 4
- it: "first document is a selfsigned Issuer when TLS enabled via external"
templates:
- templates/certmanager.yaml
set:
external: true
documentIndex: 0
asserts:
- equal:
path: apiVersion
value: cert-manager.io/v1
- equal:
path: kind
value: Issuer
- equal:
path: metadata.name
value: my-redis-selfsigned
- exists:
path: spec.selfSigned
- it: "second document is the CA Certificate when TLS enabled via external"
templates:
- templates/certmanager.yaml
set:
external: true
documentIndex: 1
asserts:
- equal:
path: kind
value: Certificate
- equal:
path: metadata.name
value: my-redis-ca
- equal:
path: spec.isCA
value: true
- equal:
path: spec.secretName
value: my-redis.ca-tls
- equal:
path: spec.issuerRef.name
value: my-redis-selfsigned
- equal:
path: spec.privateKey.rotationPolicy
value: Never
- equal:
path: spec.privateKey.algorithm
value: ECDSA
- it: "third document is the CA Issuer when TLS enabled via external"
templates:
- templates/certmanager.yaml
set:
external: true
documentIndex: 2
asserts:
- equal:
path: kind
value: Issuer
- equal:
path: metadata.name
value: my-redis-ca
- equal:
path: spec.ca.secretName
value: my-redis.ca-tls
- it: "fourth document is the leaf Certificate when TLS enabled via external"
templates:
- templates/certmanager.yaml
set:
external: true
documentIndex: 3
asserts:
- equal:
path: kind
value: Certificate
- equal:
path: metadata.name
value: my-redis-tls
- equal:
path: spec.secretName
value: my-redis.tls
- equal:
path: spec.isCA
value: false
- equal:
path: spec.issuerRef.name
value: my-redis-ca
- equal:
path: spec.issuerRef.kind
value: Issuer
- equal:
path: spec.privateKey.rotationPolicy
value: Always
- equal:
path: spec.privateKey.algorithm
value: ECDSA
- it: "leaf Certificate SAN list covers all four redis-operator service names with all DNS variants"
templates:
- templates/certmanager.yaml
set:
external: true
documentIndex: 3
asserts:
- contains:
path: spec.dnsNames
content: "localhost"
# Redis (headless) service
- contains:
path: spec.dnsNames
content: "rfr-my-redis"
- contains:
path: spec.dnsNames
content: "rfr-my-redis.tenant-test"
- contains:
path: spec.dnsNames
content: "rfr-my-redis.tenant-test.svc"
- contains:
path: spec.dnsNames
content: "rfr-my-redis.tenant-test.svc.cluster.local"
# Redis master service
- contains:
path: spec.dnsNames
content: "rfrm-my-redis"
- contains:
path: spec.dnsNames
content: "rfrm-my-redis.tenant-test.svc.cluster.local"
# Redis slaves service
- contains:
path: spec.dnsNames
content: "rfrs-my-redis"
- contains:
path: spec.dnsNames
content: "rfrs-my-redis.tenant-test.svc.cluster.local"
# Sentinel service
- contains:
path: spec.dnsNames
content: "rfs-my-redis"
- contains:
path: spec.dnsNames
content: "rfs-my-redis.tenant-test.svc.cluster.local"
- it: "leaf Certificate SAN list includes wildcard for per-pod headless DNS"
templates:
- templates/certmanager.yaml
set:
external: true
documentIndex: 3
asserts:
- contains:
path: spec.dnsNames
content: "*.rfr-my-redis"
- contains:
path: spec.dnsNames
content: "*.rfr-my-redis.tenant-test.svc"
- contains:
path: spec.dnsNames
content: "*.rfr-my-redis.tenant-test.svc.cluster.local"
- it: "leaf Certificate SAN list includes external tenant hostname when external=true"
templates:
- templates/certmanager.yaml
set:
external: true
documentIndex: 3
asserts:
- contains:
path: spec.dnsNames
content: "my-redis.example.com"
- it: "redisfailover.yaml passes TLS settings to the operator when external=true"
templates:
- templates/redisfailover.yaml
set:
external: true
documentSelector:
path: kind
value: RedisFailover
asserts:
- equal:
path: spec.tls.enabled
value: true
- equal:
path: spec.tls.authClients
value: "no"
- equal:
path: spec.tls.certificateSecret.secretName
value: my-redis.tls
- it: "dashboard-resourcemap.yaml lists TLS secrets in RBAC when external=true"
templates:
- templates/dashboard-resourcemap.yaml
set:
external: true
documentSelector:
path: kind
value: Role
asserts:
# The negatives below address rules[1] by index, and notContains is
# fail-open on a path that does not exist, so a SECOND secrets rule
# granting the key-bearing Secrets would satisfy every one of them.
# Pin the rule count: the Role renders services, secrets and
# workloadmonitors, and nothing else.
- lengthEqual:
path: rules
count: 3
- contains:
path: rules[1].resourceNames
content: "my-redis.tls"
- contains:
path: rules[1].resourceNames
content: "my-redis.ca-tls"
# ------------------------------------------------------------------
# Case 3: external=true, tls.enabled=false -> TLS explicitly off
# ------------------------------------------------------------------
- it: "certmanager.yaml renders no documents when tls.enabled=false overrides external=true"
templates:
- templates/certmanager.yaml
set:
external: true
tls:
enabled: false
asserts:
- hasDocuments:
count: 0
- it: "redisfailover.yaml has no spec.tls when tls.enabled=false overrides external=true"
templates:
- templates/redisfailover.yaml
set:
external: true
tls:
enabled: false
documentSelector:
path: kind
value: RedisFailover
asserts:
- notExists:
path: spec.tls
# ------------------------------------------------------------------
# Case 4: external=false, tls.enabled=true -> TLS explicitly on
# ------------------------------------------------------------------
- it: "certmanager.yaml renders 4 documents when tls.enabled=true overrides external=false"
templates:
- templates/certmanager.yaml
set:
external: false
tls:
enabled: true
asserts:
- hasDocuments:
count: 4
- it: "redisfailover.yaml has spec.tls.enabled=true when tls.enabled=true overrides external=false"
templates:
- templates/redisfailover.yaml
set:
external: false
tls:
enabled: true
documentSelector:
path: kind
value: RedisFailover
asserts:
- equal:
path: spec.tls.enabled
value: true
- it: "leaf Certificate SAN list omits external hostname when external=false"
templates:
- templates/certmanager.yaml
set:
external: false
tls:
enabled: true
documentIndex: 3
asserts:
- notContains:
path: spec.dnsNames
content: "my-redis.example.com"
# ------------------------------------------------------------------
# authClients propagation
# ------------------------------------------------------------------
- it: "redisfailover.yaml passes tls.authClients=yes to spec.tls.authClients"
templates:
- templates/redisfailover.yaml
set:
tls:
enabled: true
authClients: "yes"
documentSelector:
path: kind
value: RedisFailover
asserts:
- equal:
path: spec.tls.authClients
value: "yes"
- it: "redisfailover.yaml passes tls.authClients=optional to spec.tls.authClients"
templates:
- templates/redisfailover.yaml
set:
tls:
enabled: true
authClients: "optional"
documentSelector:
path: kind
value: RedisFailover
asserts:
- equal:
path: spec.tls.authClients
value: "optional"
# ------------------------------------------------------------------
# Cluster domain customization
# ------------------------------------------------------------------
- it: "leaf Certificate SAN list honours a custom cluster domain"
templates:
- templates/certmanager.yaml
set:
tls:
enabled: true
_cluster:
cluster-domain: my.cluster.local
documentIndex: 3
asserts:
- contains:
path: spec.dnsNames
content: "rfr-my-redis.tenant-test.svc.my.cluster.local"
- contains:
path: spec.dnsNames
content: "rfrm-my-redis.tenant-test.svc.my.cluster.local"
- contains:
path: spec.dnsNames
content: "rfs-my-redis.tenant-test.svc.my.cluster.local"
- contains:
path: spec.dnsNames
content: "*.rfr-my-redis.tenant-test.svc.my.cluster.local"
+15
View File
@@ -127,6 +127,21 @@
"type": "boolean",
"default": false
},
"tls": {
"description": "TLS configuration. When omitted, TLS is enabled automatically when `external` is true.",
"type": "object",
"default": {},
"properties": {
"authClients": {
"description": "Maps to the Redis `tls-auth-clients` directive. One of `no`, `optional`, `yes`. Defaults to `no` — the server certificate is presented but client certificates are not validated.",
"type": "string"
},
"enabled": {
"description": "Enable TLS for Redis and Sentinel connections. When omitted, defaults to the value of `external`. Encryption is provided by the redis-operator fork that mounts the certificate Secret into both Redis and Sentinel pods at `/tls`.",
"type": "boolean"
}
}
},
"version": {
"description": "Redis major version to deploy",
"type": "string",
+11
View File
@@ -75,6 +75,17 @@ storageClass: ""
## @param {bool} external - Enable external access from outside the cluster.
external: false
##
## @section TLS parameters
##
## @typedef {struct} TLS - TLS configuration.
## @field {*bool} enabled - Enable TLS for Redis and Sentinel connections. When omitted, defaults to the value of `external`. Encryption is provided by the redis-operator fork that mounts the certificate Secret into both Redis and Sentinel pods at `/tls`.
## @field {string} [authClients] - Maps to the Redis `tls-auth-clients` directive. One of `no`, `optional`, `yes`. Defaults to `no` — the server certificate is presented but client certificates are not validated.
## @param {TLS} [tls] - TLS configuration. When omitted, TLS is enabled automatically when `external` is true.
tls: {}
## @enum {string} Version
## @value v8
## @value v7
+2 -2
View File
@@ -8,7 +8,7 @@ spec:
plural: redises
singular: redis
openAPISchema: |-
{"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of Redis replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each Redis replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"t1.nano","enum":["t1.nano","t1.micro","t1.small","t1.medium","t1.large","t1.xlarge","t1.2xlarge","t1.4xlarge","c1.nano","c1.micro","c1.small","c1.medium","c1.large","c1.xlarge","c1.2xlarge","c1.4xlarge","s1.nano","s1.micro","s1.small","s1.medium","s1.large","s1.xlarge","s1.2xlarge","s1.4xlarge","u1.nano","u1.micro","u1.small","u1.medium","u1.large","u1.xlarge","u1.2xlarge","u1.4xlarge","m1.nano","m1.micro","m1.small","m1.medium","m1.large","m1.xlarge","m1.2xlarge","m1.4xlarge","nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":"","x-kubernetes-validations":[{"rule":"self == oldSelf","message":"storageClass is immutable"}],"x-cozystack-options":{"source":"storageclass"}},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"version":{"description":"Redis major version to deploy","type":"string","default":"v8","enum":["v8","v7"]},"authEnabled":{"description":"Enable password generation.","type":"boolean","default":true}}}
{"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of Redis replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each Redis replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"t1.nano","enum":["t1.nano","t1.micro","t1.small","t1.medium","t1.large","t1.xlarge","t1.2xlarge","t1.4xlarge","c1.nano","c1.micro","c1.small","c1.medium","c1.large","c1.xlarge","c1.2xlarge","c1.4xlarge","s1.nano","s1.micro","s1.small","s1.medium","s1.large","s1.xlarge","s1.2xlarge","s1.4xlarge","u1.nano","u1.micro","u1.small","u1.medium","u1.large","u1.xlarge","u1.2xlarge","u1.4xlarge","m1.nano","m1.micro","m1.small","m1.medium","m1.large","m1.xlarge","m1.2xlarge","m1.4xlarge","nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":"","x-kubernetes-validations":[{"rule":"self == oldSelf","message":"storageClass is immutable"}]},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"tls":{"description":"TLS configuration. When omitted, TLS is enabled automatically when `external` is true.","type":"object","default":{},"properties":{"authClients":{"description":"Maps to the Redis `tls-auth-clients` directive. One of `no`, `optional`, `yes`. Defaults to `no` — the server certificate is presented but client certificates are not validated.","type":"string"},"enabled":{"description":"Enable TLS for Redis and Sentinel connections. When omitted, defaults to the value of `external`. Encryption is provided by the redis-operator fork that mounts the certificate Secret into both Redis and Sentinel pods at `/tls`.","type":"boolean"}}},"version":{"description":"Redis major version to deploy","type":"string","default":"v8","enum":["v8","v7"]},"authEnabled":{"description":"Enable password generation.","type":"boolean","default":true}}}
release:
prefix: redis-
labels:
@@ -25,7 +25,7 @@ spec:
tags:
- cache
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODNfMzIxMykiLz4KPHBhdGggZD0iTTEyMC4xNDkgOTUuNTQ5MUMxMTQuNTg2IDk4LjQ0ODUgODUuNzcwOSAxMTAuMjk2IDc5LjYzNjMgMTEzLjQ5NUM3My41MDE2IDExNi42OTMgNzAuMDkzNyAxMTYuNjYyIDY1LjI0NzIgMTE0LjM0NkM2MC40MDEyIDExMi4wMjkgMjkuNzM2NCA5OS42NDIzIDI0LjIxMjUgOTcuMDAxOUMyMS40NTE5IDk1LjY4MjcgMjAgOTQuNTY4NyAyMCA5My41MTY2VjgyLjk4MDlDMjAgODIuOTgwOSA1OS45MjIgNzQuMjkwMSA2Ni4zNjY5IDcxLjk3NzhDNzIuODExNSA2OS42NjU2IDc1LjA0NzYgNjkuNTgyMSA4MC41MzIgNzEuNTkxQzg2LjAxNzMgNzMuNjAwOCAxMTguODEyIDc5LjUxNzYgMTI0LjIzMyA4MS41MDI5TDEyNC4yMyA5MS44ODk2QzEyNC4yMzEgOTIuOTMxMSAxMjIuOTggOTQuMDczNiAxMjAuMTQ5IDk1LjU0OTFaIiBmaWxsPSIjOTEyNjI2Ii8+CjxwYXRoIGQ9Ik0xMjAuMTQ3IDg1LjA3NTJDMTE0LjU4NSA4Ny45NzM0IDg1Ljc3IDk5LjgyMTggNzkuNjM1NCAxMDMuMDJDNzMuNTAxMSAxMDYuMjE5IDcwLjA5MzIgMTA2LjE4NyA2NS4yNDcyIDEwMy44NzFDNjAuNDAwNyAxMDEuNTU1IDI5LjczNzEgODkuMTY2OCAyNC4yMTM2IDg2LjUyOEMxOC42OTAxIDgzLjg4NzYgMTguNTc0NCA4Mi4wNzA0IDI0LjAwMDMgNzkuOTQ1OEMyOS40MjYxIDc3LjgyMDUgNTkuOTIxNSA2NS44NTYxIDY2LjM2NzIgNjMuNTQzOEM3Mi44MTE4IDYxLjIzMjQgNzUuMDQ3NSA2MS4xNDgxIDgwLjUzMTkgNjMuMTU3OEM4Ni4wMTY4IDY1LjE2NjggMTE0LjY2IDc2LjU2NzYgMTIwLjA3OSA3OC41NTI1QzEyNS41MDEgODAuNTM5OSAxMjUuNzA5IDgyLjE3NjMgMTIwLjE0NyA4NS4wNzUyWiIgZmlsbD0iI0M2MzAyQiIvPgo8cGF0aCBkPSJNMTIwLjE0OSA3OC41MDJDMTE0LjU4NiA4MS40MDE4IDg1Ljc3MDkgOTMuMjQ5MyA3OS42MzYzIDk2LjQ0ODhDNzMuNTAxNiA5OS42NDYyIDcwLjA5MzcgOTkuNjE1MiA2NS4yNDcyIDk3LjI5ODVDNjAuNDAwOCA5NC45ODMgMjkuNzM2NCA4Mi41OTUyIDI0LjIxMjUgNzkuOTU0N0MyMS40NTE5IDc4LjYzNTUgMjAgNzcuNTIzMiAyMCA3Ni40NzA3VjY1LjkzMzhDMjAgNjUuOTMzOCA1OS45MjIgNTcuMjQzNCA2Ni4zNjY5IDU0LjkzMTFDNzIuODExNSA1Mi42MTg5IDc1LjA0NzYgNTIuNTM1IDgwLjUzMiA1NC41NDQzQzg2LjAxNzcgNTYuNTUzNiAxMTguODEzIDYyLjQ2OTMgMTI0LjIzMyA2NC40NTVMMTI0LjIzIDc0Ljg0MjhDMTI0LjIzMSA3NS44ODQgMTIyLjk4IDc3LjAyNjQgMTIwLjE0OSA3OC41MDJaIiBmaWxsPSIjOTEyNjI2Ii8+CjxwYXRoIGQ9Ik0xMjAuMTQ3IDY4LjAyODJDMTE0LjU4NSA3MC45MjcxIDg1Ljc3IDgyLjc3NDcgNzkuNjM1NCA4NS45NzM3QzczLjUwMTEgODkuMTcxNiA3MC4wOTMyIDg5LjE0MDIgNjUuMjQ3MiA4Ni44MjM1QzYwLjQwMDcgODQuNTA4NCAyOS43MzcxIDcyLjEyMDEgMjQuMjEzNiA2OS40ODA5QzE4LjY5MDEgNjYuODQxMyAxOC41NzQ0IDY1LjAyMzcgMjQuMDAwMyA2Mi44OTg0QzI5LjQyNjEgNjAuNzc0MiA1OS45MjE5IDQ4LjgwOSA2Ni4zNjcyIDQ2LjQ5NzJDNzIuODExOCA0NC4xODUzIDc1LjA0NzUgNDQuMTAxNCA4MC41MzE5IDQ2LjExMDhDODYuMDE2OCA0OC4xMTk3IDExNC42NiA1OS41MTk3IDEyMC4wNzkgNjEuNTA1NUMxMjUuNTAxIDYzLjQ5MjQgMTI1LjcwOSA2NS4xMjkyIDEyMC4xNDcgNjguMDI4MloiIGZpbGw9IiNDNjMwMkIiLz4KPHBhdGggZD0iTTEyMC4xNDkgNjAuODIyNEMxMTQuNTg2IDYzLjcyMTQgODUuNzcwOSA3NS41Njk4IDc5LjYzNjMgNzguNzY5MkM3My41MDE2IDgxLjk2NzEgNzAuMDkzNyA4MS45MzU3IDY1LjI0NzIgNzkuNjE5QzYwLjQwMDggNzcuMzAzNSAyOS43MzY0IDY0LjkxNTIgMjQuMjEyNSA2Mi4yNzZDMjEuNDUxOSA2MC45NTU2IDIwIDU5Ljg0MjggMjAgNTguNzkxNVY0OC4yNTQyQzIwIDQ4LjI1NDIgNTkuOTIyIDM5LjU2NDIgNjYuMzY2OSAzNy4yNTI0QzcyLjgxMTUgMzQuOTM5NyA3NS4wNDc2IDM0Ljg1NjcgODAuNTMyIDM2Ljg2NTZDODYuMDE3NyAzOC44NzQ5IDExOC44MTMgNDQuNzkwNSAxMjQuMjMzIDQ2Ljc3NjNMMTI0LjIzIDU3LjE2MzdDMTI0LjIzMSA1OC4yMDQgMTIyLjk4IDU5LjM0NjUgMTIwLjE0OSA2MC44MjI0WiIgZmlsbD0iIzkxMjYyNiIvPgo8cGF0aCBkPSJNMTIwLjE0NyA1MC4zNDlDMTE0LjU4NSA1My4yNDc5IDg1Ljc2OTggNjUuMDk2MyA3OS42MzUyIDY4LjI5NDFDNzMuNTAwOSA3MS40OTIgNzAuMDkzIDcxLjQ2MDYgNjUuMjQ2OSA2OS4xNDUxQzYwLjQwMDkgNjYuODI4MyAyOS43MzY5IDU0LjQ0MDkgMjQuMjEzOCA1MS44MDEzQzE4LjY4OTkgNDkuMTYyMSAxOC41NzQ2IDQ3LjM0NDEgMjQgNDUuMjE5MkMyOS40MjU5IDQzLjA5NDYgNTkuOTIxNyAzMS4xMzEgNjYuMzY3IDI4LjgxODRDNzIuODExNiAyNi41MDYxIDc1LjA0NzMgMjYuNDIzIDgwLjUzMTcgMjguNDMyNEM4Ni4wMTY2IDMwLjQ0MTcgMTE0LjY1OSA0MS44NDE4IDEyMC4wNzkgNDMuODI3NUMxMjUuNTAxIDQ1LjgxMjggMTI1LjcwOSA0Ny40NSAxMjAuMTQ3IDUwLjM0OVoiIGZpbGw9IiNDNjMwMkIiLz4KPHBhdGggZD0iTTg0Ljg1NDEgNDAuMDk5NEw3NS44OTI2IDQxLjAyOThMNzMuODg2NSA0NS44NTdMNzAuNjQ2MyA0MC40NzAzTDYwLjI5ODMgMzkuNTQwNEw2OC4wMTk3IDM2Ljc1NThMNjUuNzAzIDMyLjQ4MTRMNzIuOTMyMSAzNS4zMDg4TDc5Ljc0NzEgMzMuMDc3NUw3Ny45MDUyIDM3LjQ5NzJMODQuODU0MSA0MC4wOTk0Wk03My4zNTE1IDYzLjUxODRMNTYuNjI2NiA1Ni41ODE2TDgwLjU5MiA1Mi45MDI5TDczLjM1MTUgNjMuNTE4NFpNNTAuMTYzNyA0Mi43ODI2QzU3LjIzODEgNDIuNzgyNiA2Mi45NzMgNDUuMDA1NyA2Mi45NzMgNDcuNzQ3NUM2Mi45NzMgNTAuNDkwMSA1Ny4yMzgxIDUyLjcxMjggNTAuMTYzNyA1Mi43MTI4QzQzLjA4OTMgNTIuNzEyOCAzNy4zNTQ1IDUwLjQ4OTcgMzcuMzU0NSA0Ny43NDc1QzM3LjM1NDUgNDUuMDA1NyA0My4wODkzIDQyLjc4MjYgNTAuMTYzNyA0Mi43ODI2WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTk1LjQ0MzQgNDEuNDE3NEwxMDkuNjI3IDQ3LjAyMjRMOTUuNDU1NiA1Mi42MjJMOTUuNDQzNCA0MS40MTc0WiIgZmlsbD0iIzYyMUIxQyIvPgo8cGF0aCBkPSJNNzkuNzUyOSA0Ny42MjYxTDk1LjQ0NDkgNDEuNDE4OUw5NS40NTcxIDUyLjYyMzZMOTMuOTE4NCA1My4yMjU0TDc5Ljc1MjkgNDcuNjI2MVoiIGZpbGw9IiM5QTI5MjgiLz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl82ODNfMzIxMyIgeDE9IjE4OSIgeTE9IjIxMC41IiB4Mj0iMCIgeTI9IjAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0E4MDAwMCIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNGRkNGQ0YiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "version"], ["spec", "authEnabled"]]
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "tls"], ["spec", "version"], ["spec", "authEnabled"]]
secrets:
exclude: []
include: