[bitnami/redis-cluster] Add TLS support for cluster (#2760)

* [bitnami/redis-cluster] Add TLS support to Redis-Cluster

Signed-off-by: joancafom <jcarmona@bitnami.com>

* [bitnami/redis-cluster] Update components versions

Signed-off-by: Bitnami Containers <containers@bitnami.com>

Co-authored-by: Carlos Rodríguez Hernández <carlosrh@vmware.com>
Co-authored-by: Bitnami Containers <containers@bitnami.com>
This commit is contained in:
Jose Antonio Carmona
2020-06-10 14:13:23 +02:00
committed by GitHub
co-authored by Carlos Rodríguez Hernández Bitnami Containers
parent bc8581861f
commit faed1b1c27
11 changed files with 888 additions and 187 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
apiVersion: v1
name: redis-cluster
version: 2.2.4
version: 2.3.0
appVersion: 6.0.5
description: Open source, advanced key-value store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets and sorted sets.
keywords:
+37
View File
@@ -130,6 +130,13 @@ The following table lists the configurable parameters of the Redis chart and the
| `podLabels` | Additional labels for Redis pod | {} |
| `podAnnotations` | Additional annotations for Redis pod | {} |
| `redisPort` | Redis port. | `6379` |
| `tls.enabled` | Enable TLS support for replication traffic | `false` |
| `tls.authClients` | Require clients to authenticate or not | `true` |
| `tls.certificatesSecret` | Name of the secret that contains the certificates | `nil` |
| `tls.certFilename` | Certificate filename | `nil` |
| `tls.certKeyFilename` | Certificate key filename | `nil` |
| `tls.certCAFilename` | CA Certificate filename | `nil` |
| `tls.dhParamsFilename` | DH params (in order to support DH based ciphers) | `nil` |
| `command` | Redis entrypoint string. The command `redis-server` is executed if this is not provided. | `nil` |
| `args` | Arguments for the provided command if needed | `nil` |
| `configmap` | Additional Redis configuration for the nodes (this value is evaluated as a template) | `nil` |
@@ -365,6 +372,36 @@ existingSecret=redis-password-secret
metrics.enabled=true
```
### Securing traffic using TLS
TLS support can be enabled in the chart by specifying the `tls.` parameters while creating a release. The following parameters should be configured to properly enable the TLS support in the cluster:
- `tls.enabled`: Enable TLS support. Defaults to `false`
- `tls.certificatesSecret`: Name of the secret that contains the certificates. No defaults.
- `tls.certFilename`: Certificate filename. No defaults.
- `tls.certKeyFilename`: Certificate key filename. No defaults.
- `tls.certCAFilename`: CA Certificate filename. No defaults.
For example:
First, create the secret with the cetificates files:
```console
kubectl create secret generic certificates-tls-secret --from-file=./cert.pem --from-file=./cert.key --from-file=./ca.pem
```
Then, use the following parameters:
```console
tls.enabled="true"
tls.certificatesSecret="certificates-tls-secret"
tls.certFilename="cert.pem"
tls.certKeyFilename="cert.key"
tls.certCAFilename="ca.pem"
```
> **Note TLS and Prometheus Metrics**: Current version of Redis Metrics Exporter (v1.6.1 at the time of writing) does not fully support the use of TLS. By enabling both features, the metric reporting pod may not work as expected. See Redis Metrics Exporter issue [387](https://github.com/oliver006/redis_exporter/issues/387) for more information.
### Sidecars and Init Containers
If you have a need for additional containers to run within the same pod as Redis (e.g. an additional metrics or logging exporter), you can do so via the `sidecars` config parameter. Simply define your container according to the Kubernetes container spec.
+18 -2
View File
@@ -29,7 +29,7 @@ To connect to your Redis server from outside the cluster check the following inf
To connect to your database from outside the cluster execute the following commands:
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "redis-cluster.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
redis-cli -c -h $SERVICE_IP -p {{ .Values.service.port }} {{- if .Values.usePassword }} -a $REDIS_PASSWORD{{ end }}
redis-cli -c -h $SERVICE_IP -p {{ .Values.service.port }} {{- if .Values.usePassword }} -a $REDIS_PASSWORD{{ end }}{{ if .Values.tls.enabled }} --tls --cert /tmp/client.cert --key /tmp/client.key --cacert /tmp/CA.cert{{ end }}
{{- end }}
{{- else }}
@@ -44,14 +44,30 @@ To connect to your Redis cluster:
1. Run a Redis pod that you can use as a client:
{{- if .Values.tls.enabled }}
kubectl run --namespace {{ .Release.Namespace }} {{ template "redis-cluster.fullname" . }}-client --restart='Never' --env REDIS_PASSWORD=$REDIS_PASSWORD --image {{ template "redis-cluster.image" . }} --command -- sleep infinity
Copy your TLS certificates to the pod:
kubectl cp --namespace {{ .Release.Namespace }} /path/to/client.cert {{ template "redis-cluster.fullname" . }}-client:/tmp/client.cert
kubectl cp --namespace {{ .Release.Namespace }} /path/to/client.key {{ template "redis-cluster.fullname" . }}-client:/tmp/client.key
kubectl cp --namespace {{ .Release.Namespace }} /path/to/CA.cert {{ template "redis-cluster.fullname" . }}-client:/tmp/CA.cert
Use the following command to attach to the pod:
kubectl exec --tty -i {{ template "redis-cluster.fullname" . }}-client \
{{- if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }}--labels="{{ template "redis-cluster.fullname" . }}-client=true" \{{- end }}
--namespace {{ .Release.Namespace }} -- bash
{{- else }}
kubectl run --namespace {{ .Release.Namespace }} {{ template "redis-cluster.fullname" . }}-client --rm --tty -i --restart='Never' \
{{ if .Values.usePassword }} --env REDIS_PASSWORD=$REDIS_PASSWORD \{{ end }}
{{- if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }}--labels="{{ template "redis-cluster.fullname" . }}-client=true" \{{- end }}
--image {{ template "redis-cluster.image" . }} -- bash
{{- end }}
2. Connect using the Redis CLI:
redis-cli -c -h {{ template "redis-cluster.fullname" . }}{{ if .Values.usePassword }} -a $REDIS_PASSWORD{{ end }}
redis-cli -c -h {{ template "redis-cluster.fullname" . }}{{ if .Values.usePassword }} -a $REDIS_PASSWORD{{ end }}{{ if .Values.tls.enabled }} --tls --cert /tmp/client.cert --key /tmp/client.key --cacert /tmp/CA.cert{{ end }}
{{ if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }}
Note: Since NetworkPolicy is enabled, only pods with label
@@ -133,6 +133,36 @@ Also, we can't use a single if because lazy evaluation is not an option
{{- end -}}
{{- end -}}
{{/*
Return the path to the cert file.
*/}}
{{- define "redis-cluster.tlsCert" -}}
{{- required "Certificate filename is required when TLS in enabled" .Values.tls.certFilename | printf "/opt/bitnami/redis/certs/%s" -}}
{{- end -}}
{{/*
Return the path to the cert key file.
*/}}
{{- define "redis-cluster.tlsCertKey" -}}
{{- required "Certificate Key filename is required when TLS in enabled" .Values.tls.certKeyFilename | printf "/opt/bitnami/redis/certs/%s" -}}
{{- end -}}
{{/*
Return the path to the CA cert file.
*/}}
{{- define "redis-cluster.tlsCACert" -}}
{{- required "Certificate CA filename is required when TLS in enabled" .Values.tls.certCAFilename | printf "/opt/bitnami/redis/certs/%s" -}}
{{- end -}}
{{/*
Return the path to the DH params file.
*/}}
{{- define "redis-cluster.tlsDHParams" -}}
{{- if .Values.tls.dhParamsFilename -}}
{{- printf "/opt/bitnami/redis/certs/%s" .Values.tls.dhParamsFilename -}}
{{- end -}}
{{- end -}}
{{/*
Create the name of the service account to use
*/}}
File diff suppressed because it is too large Load Diff
@@ -27,11 +27,35 @@ spec:
/entrypoint.sh /run.sh
{{- end }}
env:
- name: REDIS_TLS_ENABLED
value: {{ ternary "yes" "no" .Values.tls.enabled | quote }}
{{- if .Values.tls.enabled }}
- name: REDIS_TLS_AUTH_CLIENTS
value: {{ ternary "yes" "no" .Values.tls.authClients | quote }}
- name: REDIS_TLS_CERT_FILE
value: {{ template "redis-cluster.tlsCert" . }}
- name: REDIS_TLS_KEY_FILE
value: {{ template "redis-cluster.tlsCertKey" . }}
- name: REDIS_TLS_CA_FILE
value: {{ template "redis-cluster.tlsCACert" . }}
{{- if .Values.tls.dhParamsFilename }}
- name: REDIS_TLS_DH_PARAMS_FILE
value: {{ template "redis-cluster.tlsDHParams" . }}
{{- end }}
{{- end }}
{{- if .Values.cluster.externalAccess.enabled }}
- name: REDIS_PORT
value: {{ .Values.cluster.externalAccess.service.port | quote }}
{{- if .Values.tls.enabled }}
- name: REDIS_TLS_PORT
{{- else }}
- name: REDIS_PORT
{{- end }}
value: {{ .Values.cluster.externalAccess.service.port | quote }}
{{- else }}
{{- if .Values.tls.enabled }}
- name: REDIS_TLS_PORT
{{- else }}
- name: REDIS_PORT
{{- end }}
value: {{ .Values.redisPort | quote }}
- name: REDIS_NODES
value: "{{ $count := .Values.cluster.nodes | int }}{{ range $i, $v := until $count }}{{ include "redis-cluster.fullname" $ }}-{{ $i }}.{{ template "redis-cluster.fullname" $ }}-headless {{ end }}"
@@ -47,5 +71,17 @@ spec:
value: "yes"
- name: REDIS_CLUSTER_REPLICAS
value: {{ .Values.cluster.replicas | quote }}
{{- if .Values.tls.enabled }}
volumeMounts:
- name: redis-certificates
mountPath: /opt/bitnami/redis/certs
readOnly: true
{{- end }}
restartPolicy: OnFailure
{{- if .Values.tls.enabled }}
volumes:
- name: redis-certificates
secret:
secretName: {{ required "A secret containing the certificates for the TLS traffic is required when TLS in enabled" .Values.tls.certificatesSecret }}
{{- end }}
{{- end }}
@@ -123,8 +123,27 @@ spec:
{{- end }}
- name: REDIS_AOF_ENABLED
value: {{ .Values.useAOFPersistence | quote }}
- name: REDIS_TLS_ENABLED
value: {{ ternary "yes" "no" .Values.tls.enabled | quote }}
{{- if .Values.tls.enabled }}
- name: REDIS_TLS_PORT
value: {{ .Values.redisPort | quote }}
- name: REDIS_TLS_AUTH_CLIENTS
value: {{ ternary "yes" "no" .Values.tls.authClients | quote }}
- name: REDIS_TLS_CERT_FILE
value: {{ template "redis-cluster.tlsCert" . }}
- name: REDIS_TLS_KEY_FILE
value: {{ template "redis-cluster.tlsCertKey" . }}
- name: REDIS_TLS_CA_FILE
value: {{ template "redis-cluster.tlsCACert" . }}
{{- if .Values.tls.dhParamsFilename }}
- name: REDIS_TLS_DH_PARAMS_FILE
value: {{ template "redis-cluster.tlsDHParams" . }}
{{- end }}
{{- else }}
- name: REDIS_PORT
value: {{ .Values.redisPort | quote }}
{{- end }}
{{- if .Values.extraEnvVars }}
{{- include "common.tplvalues.render" ( dict "value" .Values.extraEnvVars "context" $ ) | nindent 8 }}
{{- end }}
@@ -189,6 +208,11 @@ spec:
subPath: redis-default.conf
- name: redis-tmp-conf
mountPath: /opt/bitnami/redis/etc/
{{- if .Values.tls.enabled }}
- name: redis-certificates
mountPath: /opt/bitnami/redis/certs
readOnly: true
{{- end }}
{{- if .Values.extraVolumeMounts }}
{{- include "common.tplvalues.render" ( dict "value" .Values.extraVolumeMounts "context" $ ) | nindent 8 }}
{{- end }}
@@ -218,11 +242,22 @@ spec:
- name: REDIS_PASSWORD_FILE
value: "/opt/bitnami/redis/secrets/redis-password"
{{- end }}
{{- if .Values.tls.enabled }}
- name: REDIS_EXPORTER_TLS_CLIENT_KEY_FILE
value: {{ template "redis-cluster.tlsCertKey" . }}
- name: REDIS_EXPORTER_TLS_CLIENT_CERT_FILE
value: {{ template "redis-cluster.tlsCert" . }}
{{- end }}
volumeMounts:
{{- if .Values.usePasswordFile }}
- name: redis-password
mountPath: /opt/bitnami/redis/secrets/
{{- end }}
{{- if .Values.tls.enabled }}
- name: redis-certificates
mountPath: /opt/bitnami/redis/certs
readOnly: true
{{- end }}
ports:
- name: http-metrics
containerPort: 9121
@@ -300,6 +335,12 @@ spec:
{{- if .Values.extraVolumes }}
{{- include "common.tplvalues.render" ( dict "value" .Values.extraVolumes "context" $ ) | nindent 6 }}
{{- end }}
{{- if .Values.tls.enabled }}
- name: redis-certificates
secret:
secretName: {{ required "A secret containing the certificates for the TLS traffic is required when TLS in enabled" .Values.tls.certificatesSecret }}
defaultMode: 256
{{- end }}
{{- if .Values.persistence.enabled }}
volumeClaimTemplates:
- metadata:
@@ -15,7 +15,15 @@ data:
timeout -s 9 $1 \
redis-cli \
-h localhost \
{{- if .Values.tls.enabled }}
-p $REDIS_TLS_PORT \
--tls \
--cert {{ template "redis-cluster.tlsCert" . }} \
--key {{ template "redis-cluster.tlsCertKey" . }} \
--cacert {{ template "redis-cluster.tlsCACert" . }} \
{{- else }}
-p $REDIS_PORT \
{{- end }}
ping
)
if [ "$response" != "PONG" ]; then
@@ -33,7 +41,15 @@ data:
timeout -s 9 $1 \
redis-cli \
-h localhost \
{{- if .Values.tls.enabled }}
-p $REDIS_TLS_PORT \
--tls \
--cert {{ template "redis-cluster.tlsCert" . }} \
--key {{ template "redis-cluster.tlsCertKey" . }} \
--cacert {{ template "redis-cluster.tlsCACert" . }} \
{{- else }}
-p $REDIS_PORT \
{{- end }}
ping
)
if [ "$response" != "PONG" ] && [ "$response" != "LOADING Redis is loading the dataset in memory" ]; then
@@ -25,30 +25,54 @@ spec:
. /opt/bitnami/scripts/libos.sh
{{- if .Values.cluster.externalAccess.enabled }}
for nodeIp in $(echo "{{ .Values.cluster.update.newExternalIPs }}" | cut -d [ -f2 | cut -d ] -f 1 ); do
{{- if .Values.tls.enabled }}
while [[ $(redis-cli -h "$nodeIp" -p "$REDIS_TLS_PORT" --tls --cert ${REDIS_TLS_CERT_FILE} --key ${REDIS_TLS_KEY_FILE} --cacert ${REDIS_TLS_CA_FILE} ping) != 'PONG' ]]; do
{{- else }}
while [[ $(redis-cli -h "$nodeIp" -p "$REDIS_PORT" ping) != 'PONG' ]]; do
{{- end }}
echo "Node $nodeIp not ready, waiting for all the nodes to be ready..."
sleep 5
done
{{- if .Values.tls.enabled }}
redis-cli --cluster --tls --cert ${REDIS_TLS_CERT_FILE} --key ${REDIS_TLS_KEY_FILE} --cacert ${REDIS_TLS_CA_FILE} add-node "${nodeIp}:${REDIS_TLS_PORT}" "{{ index .Values.cluster.externalAccess.service.loadBalancerIP 0 }}:${REDIS_TLS_PORT}"
{{- else }}
redis-cli --cluster add-node "${nodeIp}:${REDIS_PORT}" "{{ index .Values.cluster.externalAccess.service.loadBalancerIP 0 }}:${REDIS_PORT}"
{{- end }}
done
{{- else }}
for node in $(seq $((1+{{ .Values.cluster.update.currentNumberOfNodes }})) {{ .Values.cluster.nodes }}); do
new_node_index="$(($node - 1))"
new_node_ip=$(wait_for_dns_lookup {{ template "redis-cluster.fullname" . }}-"$new_node_index".{{ template "redis-cluster.fullname" . }}-headless 120 5)
{{- if .Values.tls.enabled }}
while [[ $(redis-cli -h "$new_node_ip" -p "$REDIS_TLS_PORT" --tls --cert ${REDIS_TLS_CERT_FILE} --key ${REDIS_TLS_KEY_FILE} --cacert ${REDIS_TLS_CA_FILE} ping) != 'PONG' ]]; do
{{- else }}
while [[ $(redis-cli -h "$new_node_ip" -p "$REDIS_PORT" ping) != 'PONG' ]]; do
{{- end }}
echo "Node $new_node_ip not ready, waiting for all the nodes to be ready..."
sleep 5
done
firstNodeIp=$(wait_for_dns_lookup {{ template "redis-cluster.fullname" . }}-0.{{ template "redis-cluster.fullname" . }}-headless 120 5)
{{- if .Values.tls.enabled }}
redis-cli --cluster add-node --tls --cert ${REDIS_TLS_CERT_FILE} --key ${REDIS_TLS_KEY_FILE} --cacert ${REDIS_TLS_CA_FILE} "${new_node_ip}:${REDIS_TLS_PORT}" "${firstNodeIp}:${REDIS_TLS_PORT}"
{{- else }}
redis-cli --cluster add-node "${new_node_ip}:${REDIS_PORT}" "${firstNodeIp}:${REDIS_PORT}"
{{- end }}
done
{{- end }}
env:
{{- if .Values.cluster.externalAccess.enabled }}
- name: REDIS_PORT
value: {{ .Values.cluster.externalAccess.service.port | quote }}
{{- if .Values.tls.enabled }}
- name: REDIS_TLS_PORT
{{- else }}
- name: REDIS_PORT
{{- end }}
value: {{ .Values.cluster.externalAccess.service.port | quote }}
{{- else }}
{{- if .Values.tls.enabled }}
- name: REDIS_TLS_PORT
{{- else }}
- name: REDIS_PORT
{{- end }}
value: {{ .Values.redisPort | quote }}
{{- end }}
{{- if .Values.usePassword }}
@@ -58,5 +82,15 @@ spec:
name: {{ template "redis-cluster.secretName" . }}
key: {{ template "redis-cluster.secretPasswordKey" . }}
{{- end }}
volumeMounts:
- name: redis-certificates
mountPath: /opt/bitnami/redis/certs
readOnly: true
restartPolicy: OnFailure
{{- if .Values.tls.enabled }}
volumes:
- name: redis-certificates
secret:
secretName: {{ required "A secret containing the certificates for the TLS traffic is required when TLS in enabled" .Values.tls.certificatesSecret }}
{{- end }}
{{- end }}
+26 -1
View File
@@ -18,7 +18,7 @@ image:
## Bitnami Redis image tag
## ref: https://github.com/bitnami/bitnami-docker-redis#supported-tags-and-respective-dockerfile-links
##
tag: 6.0.5-debian-10-r0
tag: 6.0.5-debian-10-r1
## Specify a imagePullPolicy
## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent'
## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images
@@ -199,6 +199,31 @@ useAOFPersistence: "yes"
# Redis port
redisPort: 6379
##
## TLS configuration
##
tls:
# Enable TLS traffic
enabled: false
#
# Whether to require clients to authenticate or not.
authClients: true
#
# Name of the Secret that contains the certificates
certificatesSecret:
#
# Certificate filename
certFilename:
#
# Certificate Key filename
certKeyFilename:
#
# CA Certificate filename
certCAFilename:
#
# File containing DH params (in order to support DH based ciphers)
# dhParamsFilename:
##
## Redis parameters
##
+26 -1
View File
@@ -18,7 +18,7 @@ image:
## Bitnami Redis image tag
## ref: https://github.com/bitnami/bitnami-docker-redis#supported-tags-and-respective-dockerfile-links
##
tag: 6.0.5-debian-10-r0
tag: 6.0.5-debian-10-r1
## Specify a imagePullPolicy
## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent'
## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images
@@ -199,6 +199,31 @@ useAOFPersistence: "yes"
# Redis port
redisPort: 6379
##
## TLS configuration
##
tls:
# Enable TLS traffic
enabled: false
#
# Whether to require clients to authenticate or not.
authClients: true
#
# Name of the Secret that contains the certificates
certificatesSecret:
#
# Certificate filename
certFilename:
#
# Certificate Key filename
certKeyFilename:
#
# CA Certificate filename
certCAFilename:
#
# File containing DH params (in order to support DH based ciphers)
# dhParamsFilename:
##
## Redis parameters
##