Kubernetes Kubernetes

Configuración: ConfigMaps y Secrets

Mantén los ajustes y las credenciales fuera de tus imágenes, inyéctalos en los Pods y evita las trampas más comunes.

14 min Intermedio

Si una URL de base de datos o un nivel de log está incrustado en la imagen de tu contenedor, cambiarlo significa reconstruir, subir y volver a desplegar la imagen. Kubernetes separa la configuración de las imágenes con dos objetos: los ConfigMaps para ajustes normales y los Secrets para valores sensibles. Esta guía muestra cómo crear ambos, cómo hacerlos llegar a un Pod y qué protegen y qué no protegen los Secrets.

Crea un ConfigMap

Un ConfigMap es un conjunto de pares clave-valor. Los valores pueden ser cadenas cortas o archivos enteros:

apiVersion: v1
kind: ConfigMap
metadata:
  name: web-config
data:
  LOG_LEVEL: info
  API_URL: http://api.internal:8080
  motd.txt: |
    Welcome to the demo environment

También puedes crear uno desde la línea de comandos, lo que resulta práctico para archivos:

kubectl create configmap web-config \
  --from-literal=LOG_LEVEL=info \
  --from-file=motd.txt
kubectl describe configmap web-config

Los ConfigMaps son para datos pequeños y no sensibles (el límite es 1 MiB) y pertenecen a un namespace. Un Pod solo puede usar ConfigMaps de su propio namespace.

Úsalo como variable de entorno o como archivo

El mismo Pod puede consumir un ConfigMap de ambas maneras:

apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
    - name: web
      image: nginx:1.25
      env:
        - name: LOG_LEVEL
          valueFrom:
            configMapKeyRef:
              name: web-config
              key: LOG_LEVEL
      volumeMounts:
        - name: config
          mountPath: /usr/share/nginx/html/motd.txt
          subPath: motd.txt
  volumes:
    - name: config
      configMap:
        name: web-config

Aquí ocurren dos cosas. La entrada env copia una clave en una variable de entorno. (envFrom puede importar todas las claves de una vez, aunque las claves que no son nombres de variable válidos se omiten.) volumes y volumeMounts montan el ConfigMap como archivos, un archivo por clave.

Si montas el ConfigMap completo en un directorio como este, el directorio se reemplaza por los archivos montados:

      volumeMounts:
        - name: config
          mountPath: /etc/web

Eso está bien para un directorio que es tuyo, pero oculta lo que ya hubiera en esa ruta. Montar sobre un directorio de configuración existente, como /etc/nginx, puede romper la aplicación, y el contenedor puede entrar en crash-loop con un error de “file not found”. Para eso sirve subPath, como en el primer ejemplo: monta una sola clave como un solo archivo y deja intacto el resto del directorio. La contrapartida es que los archivos montados con subPath no reciben las actualizaciones posteriores del ConfigMap.

Verifica lo que llegó al contenedor:

kubectl exec web -- ls /usr/share/nginx/html
kubectl exec web -- env | grep LOG_LEVEL

Guarda credenciales en un Secret

Un Secret se parece a un ConfigMap pero está pensado para contraseñas, tokens y claves:

kubectl create secret generic db-credentials \
  --from-literal=username=app \
  --from-literal=password='S3cr3t-value'

En YAML, usa stringData para escribir texto plano y dejar que Kubernetes lo codifique:

apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
type: Opaque
stringData:
  username: app
  password: S3cr3t-value

Si escribes tú mismo el campo codificado data, codifica con echo -n 'value' | base64. Sin -n, el salto de línea final pasa a formar parte de la contraseña y la autenticación falla de formas confusas. Consume un Secret de la misma manera que un ConfigMap:

      env:
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-credentials
              key: password

Evita subir a Git manifiestos de Secret con valores reales. Herramientas como Sealed Secrets, External Secrets Operator y SOPS existen para que puedas mantener secretos cifrados o referenciados en un repositorio.

Sabe qué protegen y qué no protegen los Secrets

Base64 es una codificación, no un cifrado. Cualquiera que pueda leer el Secret a través de la API puede decodificarlo:

kubectl get secret db-credentials -o jsonpath='{.data.password}' | base64 -d

Por defecto, los Secrets también se almacenan sin cifrar en etcd. Para protegerlos de verdad:

  • Restringe quién puede leer Secrets con RBAC, y recuerda que cualquiera que pueda crear un Pod en un namespace puede montar sus Secrets.
  • Habilita el cifrado en reposo de etcd, o usa la gestión de claves de un proveedor de nube.
  • Considera un gestor de secretos externo si tus requisitos son estrictos.

Las variables de entorno son cómodas pero fáciles de filtrar, ya que aparecen en kubectl exec ... env, en volcados de fallos y a veces en logs. Montar un Secret como archivo suele ser una mejor opción para valores sensibles.

Actualiza la configuración a propósito

Las variables de entorno se leen una sola vez, cuando arranca el contenedor, así que un ConfigMap o Secret modificado no llega a los Pods en ejecución. Reinícialos para recoger el cambio:

kubectl rollout restart deployment/web

Los archivos de un montaje de directorio completo sí se actualizan con el tiempo, pero muchas aplicaciones solo leen su configuración al arrancar de todos modos. Para configuraciones automatizadas, haz que la plantilla del Pod cambie siempre que cambie la configuración. Para eso sirven las técnicas de hash de configuración de la guía de Helm y Kustomize de Argo CD.

Guías populares