Cuando te adentras en el mundo del GitOps una de las primeras preocupaciones que tendrás es cómo hacer que tus secretos estén lo más seguros posibles. Existen varias herramientas para hacer esto posible pero quizás Mozilla SOPS es una de la más extendidas. Esta herramienta nos permite cifrar y descifrar archivos con soporte para YAML, JSON, .ENV e incluso binarios, además de integrarse fácilmente con diferentes KMS. En este artículo quiero hacerte una breve introducción a esta y a cómo puedes integrarla con AKS, Azure Key Vault y Flux CD.
Cómo funciona Mozilla SOPS
Para trabajar con Mozilla SOPS, lo primero que necesitas es instalarte la herramienta en tu local. Además, para que entiendas cómo funciona esta vamos a usar también otra llamada GNUPG, que nos va a facilitar la generación de claves criptográficas que usaremos para el cifrado. En el caso de MacOs puedes instalar ambas fácilmente a través de Homebrew:
brew install gnupg sops
En su repositorio de GitHub puedes encontrar las releases para los diferentes sistemas operativos.
Para ponernos en situación, imagínate que tienes el siguiente archivo plain.env con las siguientes credenciales:
username=gis
password=Passw0rd
Lo ideal sería que este contenido o bien se recupere en tiempo de ejecución del flujo que hace uso de ellas o bien mantenerlo cifrado. Para esto segundo, lo primero que necesitas hacer es generar una clave con la que cifrarlo. Para ello usamos la herramient gnugp que acabamos de instalar:
#Genereate a GPG key
gpg --batch --full-generate-key <<EOF
%no-protection
Key-Type: RSA
Key-Length: 4096
Subkey-Type: RSA
Subkey-Length: 4096
Expire-Date: 0
Name-Real: test-key
EOF
Ahora que ya tenemos una clave generada vamos a usar la misma con Mozilla SOPS para cifrar nuestro archivo plain.env de la siguiente forma:
- Recuperamos la clave pública:
KEY=$(gpg --list-keys "test-key" | grep pub -A 1 | grep -v pub)
Esta tendrá un aspecto como el siguiente:
2F080B0EB5B1A49C5BB72953CBD1E690A2C08255
2. Usamos el comando SOPS para cifrar el archivo:
#Encrypt the file
sops -pgp $KEY -e plain.env > encrypted.env
Los parámetros que recibe dicho comando son: la clave que queremos usar para el cifrado, -e significa encrypt, el nombre del archivo de origen y el de destino. El resultado del cifrado será parecido al siguiente:
username=ENC[AES256_GCM,data:gPXg,iv:6LGMSZm/SgPXg1/kOdpkPp9JjNIPZCoYLBe6delOzLI=,tag:bQI6GuTVGwQv0Hldvg8eog==,type:str]
password=ENC[AES256_GCM,data:56Q/zZL8H/o=,iv:QZGFWTwpWz7W4g4hVmubIBNH81FodCPZUmhJBzlTGBg=,tag:E5XvOiGvywTE+GwW3onM4w==,type:str]
sops_lastmodified=2021-12-31T16:00:35Z
sops_mac=ENC[AES256_GCM,data:eUZ/+NN+Fh9gaWyUnj+xJ4h93I0PFNPd4C5Tf1yaxRsNzpLUjfXYpaN38Yc3SZDoAYaB2Mxc68pghWhFxQlLIWCMJf7Za+BYB+pRP2pzilEmr5vGEaGdPGi9BeJZu6DE9V1zcZXunTm8uhWjNSiuFF8Zt/0ScYYKMXNYkXixW8s=,iv:udX6w2Zl51zSjssjOXnV9SsZqnr/5F00veanEMdn4Cc=,tag:Blmb4NETLK1G/YXNu3dm7A==,type:str]
sops_version=3.7.1
sops_pgp__list_0__map_fp=763BB095A2D76B5B9E98532BA144A9954DBF12A0
sops_pgp__list_0__map_created_at=2021-12-31T16:00:34Z
sops_pgp__list_0__map_enc=-----BEGIN PGP MESSAGE-----\n\nhQIMAwEWap6cFU8FAQ/+LdIrGcnu1m2Uk1N9cvgAoQETgr1IowN4pELVNGZHDZsU\nWimlCa3WzUfhdLPpM8OCvY3VHhTh3QYiU9m+T+v7Oe3d6uEtAFWxk3XwlDthSKpW\nkGoHKpyg9jpH52N3h3g7iCRck3NxYBPa0QBD8DhybPFa2snvJXU7Mtn9LwcRgJ8W\n9M+m78iPT071qCTy9zrEpXmjRFlLZhn91u6onx28cc8ogkxaxbU9VoomePe/89e+\nkkcbZRCulif5ASJ+twPx4jKPFd/xyFQVFIrMsGb48BM8ke+vlMKk70iNMNQx/F8m\n7/KetwMGhDIBBMTCL7JjWezxyskR0FOut5N5TN8GxY57FHvCx0m/yKxzH6WIN4FT\nwMFeyFis3qXyKIcf/1FMxbD02E5PK+1RpuB3REv8xbCLTFHJp2P8A1LHa6Iydmar\nPffimRZuuULAfRo9Jj9WxOQTbFykiXQmXB/o2F8whtLyNb6HUVWH53FL554R0fQA\n4rGtrG/8nth0fZ+0bAAFSm83/9xJOvOZXfSvJadOEdNQO0QZFWAw/bP490MgMUNY\n7lH2BFeta6EUgU28RKKztoJac9Wjb9Hd3qH1kk/NOnqlH2sIlrWLti/bTO0vf3xH\nnrgFpEvUOjWbPhV4JRKnVre+6WAoRu24g8gfmvnQMgnClxmvJWg6NazQeKeUxU7U\naAEJAhCCCASWZfvXXJJC5VSTaaMQEyxTBfsaRtJowA/3ZCDPYRaqvd1wz+u3e1pa\ny5MWLSF9oyv43eVbqSEaWRxmmASydU+AmkgGzSePJ8AAhtSALR7a2cYHFURn2j93\nbynUcv0HWNYU\n=rCz9\n-----END PGP MESSAGE-----\n
sops_unencrypted_suffix=_unencrypted
Lo guay de esta herramienta es que además podemos añadir ciertas reglas para que solo se cifre parte del archivo, y no en su totalidad, lo cual es necesario para lo que veremos después con Flux CD. Por ejemplo, en el caso de un YAML como este:
credentials:
username: 'admin'
password: 'passw0rd'
Podríamos decirle de una forma sencilla que solo queremos cifrar el campo password:
#Encrypt password only
sops -pgp $KEY -e --encrypted-regex 'password' plain.yaml > encrypted-password.yaml
y el resultado sería algo así:
credentials:
username: admin
password: ENC[AES256_GCM,data:aTnOmag=,iv:yo7MNih8s4lEbx8MzrtINpPuGmwyPQfD5+VXCf1TQus=,tag:mCSqFp0VD/hrauUJBiNkMw==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2021-12-31T16:12:00Z"
mac: ENC[AES256_GCM,data:/OlVlXji7csiTVmEnYGUpN9PJl4PgKQsUk+PIVxremxOqvP4xOkmM9MONQyE7Pxslo0rD/p3c1aEnoS2CG7jncJY76C22xaxCSy1nUTl7KFfC6sFSKnyZBSMrP9i62mWWUWlRsbDcj35iyeYFZDmZPX0kdo3SPaa9b/ML6R0X1c=,iv:bdrMvK2F6nmn5HNqgPRan1kZShLmkXN+dC5jnBhtNPs=,tag:FEasQYnZa3nqvVxJSxGYRg==,type:str]
pgp:
- created_at: "2021-12-31T16:11:59Z"
enc: |
-----BEGIN PGP MESSAGE-----
[...]
Cómo ves, súper sencillo de utilizar. De hecho, en este último ejemplo puedes ver que es posible integrarlo con varios KMS como el de Google, Amazon o Azure. Ahora vamos a ver cómo configurar esta herramienta con AKS, Flux CD y Azure Key Vault.
Configurar Flux CD en un clúster de AKS
Para poder probar este escenario, lo primero que vamos a hacer es configurar un clúster de AKS con Flux CD, como ya hice en el artículo donde te presenté esta herramienta:
#Variables for Azure
RESOURCE_GROUP="fluxcd-demo"
CLUSTER_NAME="fluxcd-aks"
KEY_VAULT_NAME="sops-keys"
LOCATION="northeurope"
#Create a resource group
az group create --name $RESOURCE_GROUP --location $LOCATION
#Create AKS cluster
az aks create --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --node-count 1 --generate-ssh-keys
#Get AKS credentials
az aks get-credentials --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME
# Check the cluster meets the requirements
flux check --pre
# Your GitHub PAT
export GITHUB_TOKEN=<YOUR_GITHUB_PAT>
export GITHUB_USER=<YOUR_GITHUB_USERNAME>
# Initialize Flux
flux bootstrap github \
--owner=$GITHUB_USER \
--repository=fluxcd-sops-demo \
--branch=main \
--path=./clusters/$CLUSTER_NAME \
--personal
# Check that the cluster is ready
flux check
# Clone the repo that Flux just created
git clone https://github.com/$GITHUB_USER/fluxcd-sops-demo.git
# Go to the repo
cd fluxcd-sops-demo
Por otro lado, para ilustrar este ejemplo con un caso práctico, voy a utilizar el entorno de WordPress que te mostré en el artículo sobre Kustomize. Lo primero que hago es crear un archivo de configuración para Flux CD, utilizando su herramienta con los siguientes parámetros:
flux create kustomization wordpress \
--namespace=flux-system \
--source=flux-system \
--path="./manifests" \
--prune=true \
--interval=1m \
--export > ./clusters/$CLUSTER_NAME/wordpress-kustomization.yaml
Nota: en este ejemplo estoy usando el mismo repositorio por simplicidad, pero podría ser otro totalmente independiente.
Después creo una carpeta llamada manifests, a la que hace mención esta configuración:
mkdir manifests
y dentro de esta creo el Namespace:
cat <<EOF > manifests/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: wordpress
EOF
El despliegue para el MySQL que necesita WordPress:
cat <<EOF > ./manifests/mysql.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress-mysql
namespace: wordpress
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
tier: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: wordpress
tier: mysql
spec:
containers:
- image: mysql:5.6
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: wp_password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-storage
emptyDir: {}
EOF
El servicio asociado a este:
cat <<EOF > ./manifests/mysql-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: wordpress-mysql
namespace: wordpress
labels:
app: wordpress
spec:
ports:
- port: 3306
selector:
app: wordpress
tier: mysql
clusterIP: None
EOF
El despliegue para el propio WordPress:
cat <<EOF > ./manifests/wordpress.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
namespace: wordpress
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
tier: frontend
replicas: 2
strategy:
type: Recreate
template:
metadata:
labels:
app: wordpress
tier: frontend
spec:
containers:
- image: wordpress:4.8-apache
name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: wordpress-mysql
- name: WORDPRESS_DB_PASSWORD
value: wp_password
ports:
- containerPort: 80
name: wordpress
volumeMounts:
- name: wordpress-storage
mountPath: /var/www/html
volumes:
- name: wordpress-storage
emptyDir: {}
EOF
Y el servicio asociado al mismo con el tipo LoadBalancer para poder acceder desde fuera a la instalación, y comprobar así que todo funciona correctamente:
cat <<EOF > ./manifests/wordpress-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: wordpress
namespace: wordpress
labels:
app: wordpress
spec:
ports:
- port: 80
selector:
app: wordpress
tier: frontend
type: LoadBalancer
EOF
Ahora haz commit de todos estos archivos y comprueba que el despliegue en tu clúster ha sido satisfactorio:
#Commit all
git add .
git commit -m "Add WordPress demo"
git push origin main
#Check the deployment
flux get kustomizations -w
kubectl get all -n wordpress
Configurar Azure AD Pod Identity y Azure Key Vault
Para que nuestro clúster pueda acceder a Azure Key Vault podemos hacerlo utilizando un Service Principal o a través de identidades manejadas. En el caso de Kubernetes podemos hacer uso de esto último a través de Azure AD Pod Identity, lo cual es mucho más cómodo. Para configurarlo puedes seguir estos pasos:
#Configure AAD Pod Identity
RESOURCE_GROUP_ID=$(az group show --name $RESOURCE_GROUP --query id -o tsv)
AKS_RESOURCE_GROUP=$(az aks show -g $RESOURCE_GROUP -n $CLUSTER_NAME -o tsv --query nodeResourceGroup)
AKS_RESOURCE_GROUP_ID=$(az group show -n $AKS_RESOURCE_GROUP -o tsv --query id)
KUBELET_CLIENT_ID=$(az aks show -g $RESOURCE_GROUP -n $CLUSTER_NAME -o tsv --query identityProfile.kubeletidentity.clientId)
# Your cluster will need the correct role assignment configuration to perform Azure-related operations
# such as assigning and un-assigning the identity on the underlying VM/VMSS.
#https://azure.github.io/aad-pod-identity/docs/getting-started/role-assignment/
az role assignment create --role "Virtual Machine Contributor" --assignee $KUBELET_CLIENT_ID --scope $AKS_RESOURCE_GROUP_ID
az role assignment create --role "Managed Identity Operator" --assignee $KUBELET_CLIENT_ID --scope $RESOURCE_GROUP_ID
#Create a managed identity
IDENTITY_NAME="fluxcd-aks-identity"
az identity create -n $IDENTITY_NAME -g $RESOURCE_GROUP -l $LOCATION
#Obtaine the client id, client secret and resource id
CLIENT_ID=$(az identity show -n $IDENTITY_NAME -g $RESOURCE_GROUP -o tsv --query "clientId")
OBJECT_ID=$(az identity show -n $IDENTITY_NAME -g $RESOURCE_GROUP -o tsv --query "principalId")
RESOURCE_ID=$(az identity show -n $IDENTITY_NAME -g $RESOURCE_GROUP -o tsv --query "id")
Con ello recuperamos los ID necesarios para asignarle al clúster los roles que necesita para poder asignar la identidad a las VMs que corren por debajo y se crea una identidad de la que recuperamos también sus valores. Ahroa creamos un recurso de Azure Key Vault:
#Create a key vault
az keyvault create --name $KEY_VAULT_NAME --resource-group $RESOURCE_GROUP --location $LOCATION
Y generamos una clave que utilizaremos más tarde para cifrar nuestros secretos, de la misma forma que lo hicimos con GPG:
#Create a key in the key vault
az keyvault key create --vault-name $KEY_VAULT_NAME --name sops-key --protection software --ops encrypt decrypt
Por último le asignamos los permisos de cifrado y descifrado a la identidad que usará el pod de kustomization-controller, para poder hacer dichas operaciones cuando se le requieran:
#Add permissions to the identity
az keyvault set-policy --name $KEY_VAULT_NAME --object-id $OBJECT_ID --key-permissions encrypt decrypt
Para seguir con la filosofía de GitOps, voy a registrar el chart de AAD Pod Identity para instalarlo en el clúster:
# Add Azure AD Pod Identity Helm chart
cat <<EOF > ./manifests/azure-ad-pod-identity.yaml
apiVersion: v1
kind: Namespace
metadata:
name: aad-pod-identity
---
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: HelmRepository
metadata:
name: aad-pod-identity
namespace: aad-pod-identity
spec:
url: https://raw.githubusercontent.com/Azure/aad-pod-identity/master/charts
interval: 10m
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: aad-pod-identity
namespace: aad-pod-identity
spec:
interval: 5m
chart:
spec:
chart: aad-pod-identity
version: 4.0.0
sourceRef:
kind: HelmRepository
name: aad-pod-identity
namespace: aad-pod-identity
interval: 1m
values:
nmi:
allowNetworkPluginKubenet: true
EOF
Configuro la identidad para aquel pod que tenga el selector sops-akv-decryptor:
#Configure in-cluster secrets decryption
cat > ./clusters/$CLUSTER_NAME/sops-identity.yaml <<EOF
---
apiVersion: aadpodidentity.k8s.io/v1
kind: AzureIdentity
metadata:
name: sops-akv-decryptor
namespace: flux-system
spec:
clientID: $CLIENT_ID
resourceID: $RESOURCE_ID
type: 0 # user-managed identity
---
apiVersion: aadpodidentity.k8s.io/v1
kind: AzureIdentityBinding
metadata:
name: sops-akv-decryptor-binding
namespace: flux-system
spec:
azureIdentity: sops-akv-decryptor
selector: sops-akv-decryptor # kustomize-controller label will match this name
EOF
Creo un patch para el despliegue de kustomize-controller:
#Add a file to patch the Flux system kustomize controller
cat > ./clusters/$CLUSTER_NAME/flux-system/sops-kustomize-patch.yaml <<EOF
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kustomize-controller
namespace: flux-system
spec:
template:
metadata:
labels:
aadpodidbinding: sops-akv-decryptor # match the AzureIdentityBinding selector
spec:
containers:
- name: manager
env:
- name: AZURE_AUTH_METHOD
value: msi
EOF
Y por último modifico el archivo kustomization.yaml de flux-system para añadir este patch:
#Update kustomization for flux-system
cat > ./clusters/$CLUSTER_NAME/flux-system/kustomization.yaml <<EOF
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- gotk-components.yaml
- gotk-sync.yaml
patchesStrategicMerge:
- sops-kustomize-patch.yaml
EOF
Guardo los cambios en el repo y espero a que se apliquen en el clúster:
#Commit all
git add .
git commit -m "Add Azure AD Pod Identity Helm chart"
git push origin main
#Check the deployment
flux get helmreleases -A -w
kubectl get pod -n aad-pod-identity
Ahora ya tenemos nuestro clúster y Flux CD correctamente configurados para desplegar secretos que están previamente cifrados con Azure Key Vault y poder descifrarlos antes de su despliegue por Flux CD.
Desplegar un Secret cifrado con Azure Key Vault
Lo úlltimo que nos queda es pasar a la acción con una demo que nos permita validar que todo funciona como esperamos. Antes de ello necesitamos dar permisos sobre el usuario logado a través de Azure CLI:
# Assign permissions to my user
SIGNED_USER=$(az ad signed-in-user show --query objectId -o tsv)
az keyvault set-policy --name $KEY_VAULT_NAME --object-id $SIGNED_USER --key-permissions list encrypt decrypt get
Ahora seremos capaces de cifrar y descifrar con el recurso de Azure Key Vault que generamos previamente. Un dato que es importante tener en cuenta es que Flux CD no soporta el cifrado total del secreto, sino que debemos cifrar solamente el apartado data o stringData, tal y como se advierte en su documentación. Podríamos hacer uso de expresiones regulares, junto con el comando sops, cada vez que quisieramos cifrar un nuevo secreto o, mejor todavía, podemos configurar sops a través del archivo .sops.yaml de la siguiente manera:
#Create SOPS configuration
cat > .sops.yaml <<EOF
creation_rules:
- path_regex: .*.yaml
encrypted_regex: ^(data|stringData)$
azure_keyvault: $(az keyvault key show --vault-name $KEY_VAULT_NAME --name sops-key --query key.kid -o tsv)
EOF
De esta forma le estamos diciendo a qué tipos de archivos debe aplicar esta regla, qué propiedades son las que debe cifrar, y cuál es la clave en cuestión que queremos usar. Fácil ¿no?
Con la configuración en su sitio creamos un secreto como el siguiente:
# Create a secret
cat > ./secret.yaml <<EOF
---
apiVersion: v1
kind: Secret
metadata:
name: wordpress-credentials
namespace: wordpress
type: Opaque
stringData:
host: wordpress-mysql
password: passw0rd
EOF
Y ahora, de la misma forma que hicimos al inicio de este artículo (pero con menos parámetros), ciframos el archivo y eliminamos el que tiene las credenciales en plano, para no subirlo al repositorio, que es el objetivo de todo esto 😉:
# Encrypt secret
sops --encrypt secret.yaml > ./manifests/secret.enc.yaml
# Delete plaintext secret
rm secret.yaml
Si ahora comprobaramos el resultado tendríamos algo como lo siguiente:
apiVersion: v1
kind: Secret
metadata:
name: wordpress-credentials
namespace: wordpress
type: Opaque
stringData:
host: ENC[AES256_GCM,data:aCQX6O3sZxlHS5up4yCY,iv:tTRPROZTTeo4ffMpLq7UpffiCEB/vdYVWGPQWPpvI7g=,tag:fOixFKqoPvSvHflW3fSNcQ==,type:str]
password: ENC[AES256_GCM,data:tVOSzJkqQc4=,iv:rQzE8/XKXB2TOr420BCwl9snWwhddHIWZ8dTPwb4DXY=,tag:WbmK4RrJJjSE5jTsC5NqqQ==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv:
- vault_url: https://sops-keys.vault.azure.net
name: sops-key
version: 91094efdfd414b23a0921748438c9d6a
created_at: "2022-01-04T18:08:30Z"
enc: A_SjqMpgDc6nfcCl95req_5H-uiM9DmuBqgpAZzZhib6qEyHJV8QqTkHfNBMRx_cSfNJrOqciptyOok0c2nhtMBcCwddHGhx3riOJd3aw3428e9lk2CmTKZUVnOqj3_KthFmj9zdEPmYdm8qvdVam8dp6PQN6HSA5aU1ZDGg_NJtj5eZ8t8m9Uo65f-o8V8DR_imVK_SfrHtAspjpnjy7aJ--2yC0u2OCCrICBfuRqPs_DvZmT2G4zA-wrPcAKA9UvCqh55YiD1vd736HZVG6In4qFH8UZisjqUE8a4Bqdd0Oe-58B7aU2JMqVIZ5FWg1_O7jBFjDNvV0b8odJrHig
hc_vault: []
age: []
lastmodified: "2022-01-04T18:08:30Z"
mac: ENC[AES256_GCM,data:xcfDepit828BnjMY/5ThRFsw/k+0Or1RIXUumvjCpqlSHP1UcyMO9g7Ua7hYQWngnofU03eoPAf7aPfGDcrJqeCm3ojK0Ys51FJaFKkLOxUg/0nZ5YmSNlGErpiBfWyPu21oa7Agmff80s5z9a7Fre7zAVa/FKP7nM4CEpO5UPw=,iv:RHUCPe2k8Ups7dr12XuQmtdcVobrstM7CWOEGtRwQa8=,tag:dD+AN6gvQ2IbWxptW+311A==,type:str]
pgp: []
encrypted_regex: ^(data|stringData)$
version: 3.7.1
Haz commit de estos cambios:
# Commit changes
git add .
git commit -m "Add encrypted secret"
git push origin main
Sin embargo, llegados a este punto te darás cuenta de que el proceso todavía no funcionará, lo cual puedes comprobarlo viendo el resultado de este comando:
flux get kustomizations --watch
Aparecerá algo como que no es posible descifrar el Secreto porque está cifrado con SOPS y falta configuración:

Para solucionarlo, debemos modificar la configuración del archivo wordpress-kustomization.yaml indicándole como proveedor SOPS:
flux create kustomization wordpress \
--namespace=flux-system \
--source=flux-system \
--path="./manifests" \
--prune=true \
--interval=1m \
--decryption-provider=sops \
--export > ./clusters/$CLUSTER_NAME/wordpress-kustomization.yaml
Vuelve a aplicar los cambios en el repo y verás que ahora todo ha funcionado correctamente y el secreto está en su sitio con el contenido descifrado por Flux CD:
# Check the deployment
flux get kustomizations --watch
# Check if the secret is there
kubectl get secret -n wordpress
#See secret in plaintext
kubectl get secret wordpress-credentials -n wordpress --template={{.data.password}} | base64 --decode
¡Perfecto! Pues ya tenemos todo correctamente funcionado, vamos a hacer la comprobación final, que es integrarlo con el despliegue de WordPress.
Usar el secreto cifrado para el despliegue con WordPress
Para cerrar el ciclo, lo único que nos queda es generar un par de patches: uno para el despliegue de MySQL, para la variable de entorno que define la contraseña de la base de datos:
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress-mysql
namespace: wordpress
spec:
template:
spec:
containers:
- name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: ""
valueFrom:
secretKeyRef:
name: wordpress-credentials
key: password
y este otro para el despliegue de WordPress, donde se hace mención a esa misma contraseña y al nombre del host:
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
namespace: wordpress
spec:
template:
spec:
containers:
- name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: ""
valueFrom:
secretKeyRef:
name: wordpress-credentials
key: host
- name: WORDPRESS_DB_PASSWORD
value: ""
valueFrom:
secretKeyRef:
name: wordpress-credentials
key: password
Lo único que hago es «vaciar» el contenido de value, que es lo que se usaba inicialmente, para que tome como valor el referenciado en mi secreto wordpress-credentials. Si Flux CD lo ha descifrado correctamente podré integrarlo sin problemas en ambos despliegues.
Para que estos cambios sean aplicados correctamente, en la carpeta manifests añado un nuevo archivo kustomization.yaml para indicar cuáles son recursos y cuáles son mis patches dentro de este directorio:
#Use the secret in the wordpress kustomization
cat > ./manifests/kustomization.yaml <<EOF
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- secret.enc.yaml
- mysql.yaml
- mysql-svc.yaml
- wordpress.yaml
- wordpress-svc.yaml
- azure-ad-pod-identity.yaml
patchesStrategicMerge:
- mysql-patch.yaml
- wordpress-patch.yaml
EOF
Hago commit de los cambios:
# Commit changes
git add .
git commit -m "Add patches and kustomization.yaml"
git push origin main
y una vez finalice podré comprobar que mi WordPress está funcionando correctamente con un secreto cifrado en mi repositorio con Azure Key Vault y que Flux CD es capaz de descifrar.
¡Saludos!