Flux CD Flux CD

Gestiona secretos en Git con SOPS y age

Cifra los Secrets de Kubernetes antes de hacer commit y deja que Flux los descifre en el clúster.

12 min Intermedio

GitOps pone la configuración de tu clúster en Git, y eso incluye los Secrets. Hacer commit de un Secret de Kubernetes en texto plano expone sus valores a cualquiera que pueda leer el repositorio, porque los datos de un Secret solo están codificados en base64. El kustomize-controller de Flux puede descifrar archivos cifrados con Mozilla SOPS, así que puedes hacer commit de Secrets cifrados y mantener todo el sistema en Git. Esta guía usa claves de age, la opción más simple.

Instala las herramientas y crea una clave

Instala age y sops (por ejemplo brew install age sops) y luego genera un par de claves:

age-keygen -o age.agekey

El archivo de salida contiene la clave privada, y el comando imprime la clave pública (empieza por age1). Mantén la clave privada fuera de Git. Haz una copia de seguridad en un lugar seguro, porque si la pierdes no podrás descifrar tus secretos. Flux 2.9 también añade soporte para el cifrado post-cuántico de age, si tus políticas lo requieren.

Dale la clave privada al clúster

Guarda la clave privada como un Secret en el mismo namespace que la Kustomization de Flux que la usará:

kubectl create secret generic sops-age \
  --namespace=flux-system \
  --from-file=age.agekey=/dev/stdin < age.agekey

La clave del Secret debe terminar en .agekey. Elimina el archivo local age.agekey o muévelo a un gestor de contraseñas una vez que esté guardado de forma segura en otro lugar.

Configura SOPS en el repositorio

Crea .sops.yaml en la raíz de tu repositorio para que todos cifren de la misma manera. Reemplaza la clave por tu clave pública:

creation_rules:
  - path_regex: .*\.yaml
    encrypted_regex: ^(data|stringData)$
    age: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

encrypted_regex cifra solo los campos data y stringData, así que todo lo demás del manifiesto permanece legible para la revisión y para que Flux lo procese. Puedes listar varios destinatarios age (separados por comas) para que los compañeros de equipo y la clave del clúster puedan descifrar.

Cifra un Secret

Escribe el manifiesto del Secret en local, por ejemplo apps/webapp/db-credentials.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
  namespace: webapp
stringData:
  username: webapp
  password: s3cr3t-value

Cífralo en el mismo lugar:

sops --encrypt --in-place apps/webapp/db-credentials.yaml

Abre el archivo: los valores de username y password ahora son texto cifrado y se ha añadido un bloque sops: con metadatos. Es seguro hacer commit. Para editarlo más adelante, ejecuta sops apps/webapp/db-credentials.yaml, que descifra en tu editor y vuelve a cifrar al guardar. Para comprobar lo que vas a subir, asegúrate de que los valores ya no son legibles.

Dile a Flux que descifre

Añade un bloque decryption a la Kustomization de Flux que aplica la carpeta:

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: webapp
  namespace: flux-system
spec:
  interval: 10m
  sourceRef:
    kind: GitRepository
    name: flux-system
  path: ./apps/webapp
  prune: true
  decryption:
    provider: sops
    secretRef:
      name: sops-age

Haz commit y push. Durante la reconciliación, kustomize-controller descifra el archivo en memoria y aplica un Secret normal al clúster. Verifícalo:

flux reconcile kustomization webapp --with-source
kubectl get secret db-credentials -n webapp

Solución de problemas y buenas prácticas

Si la Kustomization informa de un error de descifrado, comprueba que el Secret sops-age existe en el mismo namespace que la Kustomization, que el nombre de su clave termina en .agekey y que el archivo se cifró con la clave pública correspondiente. kubectl describe kustomization webapp -n flux-system muestra el error.

  • Usa una clave distinta por entorno para que una clave de dev no pueda leer los secretos de producción.
  • Rota las claves añadiendo el nuevo destinatario, volviendo a cifrar (sops updatekeys) y luego eliminando el antiguo.
  • Las claves de KMS en la nube (AWS KMS, Azure Key Vault, Google Cloud KMS) y HashiCorp Vault u OpenBao también funcionan, y evitan distribuir archivos de claves. Configúralos con workload identity y omite secretRef donde la plataforma proporcione las credenciales.
  • Si prefieres mantener los secretos completamente fuera de Git, usa el External Secrets Operator para sincronizarlos desde una bóveda, y deja que Flux gestione solo los objetos ExternalSecret.

Guías populares