Gestión de Configuración en Kubernetes: ConfigMaps y Secrets para Aplicaciones Robustas ⚙️
Este tutorial profundiza en el uso de ConfigMaps y Secrets en Kubernetes, herramientas esenciales para la gestión de la configuración y la protección de información sensible. Exploraremos cómo definirlos, desplegarlos y utilizarlos en tus pods, asegurando un despliegue seguro y flexible de tus aplicaciones.
Kubernetes se ha consolidado como la plataforma líder para la orquestación de contenedores, y una de sus fortalezas es la forma en que maneja la configuración de las aplicaciones. Desplegar una aplicación implica no solo sus contenedores, sino también cómo se configura para diferentes entornos (desarrollo, staging, producción) y cómo se manejan datos sensibles como contraseñas y claves API. Aquí es donde entran en juego los ConfigMaps y Secrets.
Estas dos herramientas son fundamentales para desacoplar la configuración del código de la aplicación y la imagen del contenedor, lo que facilita la reutilización, el mantenimiento y, crucialmente, la seguridad.
¿Por Qué Necesitamos ConfigMaps y Secrets? 🤔
Antes de sumergirnos en los detalles, entendamos por qué estas características son tan importantes:
- Desacoplamiento: Separan la configuración de la aplicación de su código. Esto significa que puedes usar la misma imagen de Docker para diferentes entornos, simplemente cambiando la configuración. Es una aplicación del principio de Twelve-Factor App.
- Flexibilidad: Permite cambiar la configuración de una aplicación sin tener que reconstruir su imagen de contenedor o reiniciar todos sus pods (aunque algunos cambios pueden requerir un reinicio para que surtan efecto).
- Seguridad: Los Secrets proporcionan un mecanismo seguro para manejar datos sensibles, evitando que se almacenen directamente en el código fuente, en imágenes de Docker o en ficheros de configuración visibles.
- Auditoría y control: La gestión centralizada de la configuración facilita la auditoría y el control de versiones.
ConfigMaps: Gestión de la Configuración General 🛠️
Un ConfigMap es un objeto API de Kubernetes que se utiliza para almacenar datos de configuración no confidenciales como pares clave-valor. Está diseñado para inyectar datos de configuración en los contenedores de tus pods.
Formas de Crear un ConfigMap ✨
Hay varias maneras de crear un ConfigMap:
1. Desde literales
Puedes especificar los datos directamente usando --from-literal.
kubectl create configmap app-config --from-literal=database.host=mydb.example.com --from-literal=app.port=8080
2. Desde un archivo
Ideal para cuando ya tienes archivos de configuración existentes.
Supongamos que tienes un archivo application.properties:
database.host=production-db.example.com
app.port=80
api.key=xyz123abc
Para crearlo:
kubectl create configmap app-settings --from-file=application.properties
Cada línea o sección del archivo se convierte en una entrada del ConfigMap. Si quieres que el contenido del archivo se guarde como una sola clave, puedes especificar el nombre de la clave:
kubectl create configmap app-settings-single-file --from-file=my-app-config=application.properties
3. Desde un directorio
Si tienes múltiples archivos de configuración en un directorio:
mkdir config-files
echo "host=localhost" > config-files/db.properties
echo "port=8080" > config-files/server.properties
kubectl create configmap app-multi-config --from-file=config-files
Esto creará un ConfigMap con dos entradas: db.properties y server.properties, donde los valores son el contenido de cada archivo.
4. Usando un manifiesto YAML (Recomendado) ✅
Esta es la forma más común y recomendable para gestionar ConfigMaps en un entorno de CI/CD, ya que permite el control de versiones.
my-configmap.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: my-app-config
data:
# Clave-valor directamente
app_environment: production
log_level: INFO
# Contenido multilínea como un string
database.properties: |
db.host=prod-db
db.port=5432
db.user=admin
Para aplicar el manifiesto:
kubectl apply -f my-configmap.yaml
Consumir ConfigMaps en Pods 📖
Una vez creado, un ConfigMap puede ser consumido por un pod de varias maneras.
1. Como variables de entorno
La forma más sencilla para inyectar valores individuales.
pod-with-env-configmap.yaml:
apiVersion: v1
kind: Pod
metadata:
name: my-app-env
spec:
containers:
- name: my-app-container
image: nginx:latest
env:
- name: APP_ENV
valueFrom:
configMapKeyRef:
name: my-app-config # Nombre del ConfigMap
key: app_environment # Clave dentro del ConfigMap
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: my-app-config
key: log_level
kubectl apply -f pod-with-env-configmap.yaml
kubectl exec -it my-app-env -- env | grep APP_ENV
kubectl exec -it my-app-env -- env | grep LOG_LEVEL
pod-with-envFrom-configmap.yaml:
apiVersion: v1
kind: Pod
metadata:
name: my-app-envfrom
spec:
containers:
- name: my-app-container
image: alpine/git
command: ["sh", "-c", "env; sleep 3600"]
envFrom:
- configMapRef:
name: my-app-config # Nombre del ConfigMap
kubectl apply -f pod-with-envFrom-configmap.yaml
k exec -it my-app-envfrom -- env | grep -E 'APP_ENV|LOG_LEVEL|database.properties'
2. Como archivos en un volumen
Esto es útil cuando la aplicación espera archivos de configuración en una ruta específica. Cada clave del ConfigMap se convierte en un archivo dentro del volumen.
pod-with-volume-configmap.yaml:
apiVersion: v1
kind: Pod
metadata:
name: my-app-volume
spec:
containers:
- name: my-app-container
image: nginx:latest
volumeMounts:
- name: config-volume
mountPath: /etc/config # Ruta dentro del contenedor
volumes:
- name: config-volume
configMap:
name: my-app-config # Nombre del ConfigMap
kubectl apply -f pod-with-volume-configmap.yaml
k exec -it my-app-volume -- ls /etc/config
k exec -it my-app-volume -- cat /etc/config/app_environment
Aquí, cada clave de my-app-config (como app_environment o log_level) se materializará como un archivo en /etc/config dentro del contenedor.
Secrets: Protegiendo la Información Sensible 🔒
Los Secrets son similares a los ConfigMaps, pero están diseñados específicamente para almacenar y gestionar datos sensibles como contraseñas, tokens de autenticación, claves API y claves TLS. Kubernetes proporciona un mecanismo para mantener estos datos seguros y desacoplados de la imagen de la aplicación.
Formas de Crear un Secret 🔑
1. Desde literales
Similar a ConfigMaps, pero los valores son automáticamente codificados en Base64.
kubectl create secret generic my-db-secret --from-literal=username=dbadmin --from-literal=password=SuperSecretPassword123!
2. Desde archivos
echo -n 'dbadmin' > ./username.txt
echo -n 'SuperSecretPassword123!' > ./password.txt
kubectl create secret generic my-db-secret-file --from-file=./username.txt --from-file=./password.txt
3. Usando un manifiesto YAML (Recomendado) ✅
Los valores en el YAML deben estar codificados en Base64. Puedes usar una herramienta como base64 para esto.
echo -n 'dbadmin' | base64
# ZGJhZG1pbg==
echo -n 'SuperSecretPassword123!' | base64
# U3VwZXJTZWNyZXRQYXNzd29yZDEyMyE=
my-secret.yaml:
apiVersion: v1
kind: Secret
metadata:
name: my-app-secret
type: Opaque # Tipo general de Secret
data:
username: ZGJhZG1pbg== # 'dbadmin' en Base64
password: U3VwZXJTZWNyZXRQYXNzd29yZDEyMyE= # 'SuperSecretPassword123!' en Base64
kubectl apply -f my-secret.yaml
Para ver un Secret (con cuidado):
kubectl get secret my-app-secret -o yaml
Los valores estarán codificados en Base64. Para decodificarlos temporalmente:
kubectl get secret my-app-secret -o jsonpath="{.data.username}" | base64 --decode
kubectl get secret my-app-secret -o jsonpath="{.data.password}" | base64 --decode
Consumir Secrets en Pods 📖
La forma de consumir Secrets es muy similar a ConfigMaps, pero con implicaciones de seguridad adicionales.
1. Como variables de entorno
pod-with-secret-env.yaml:
apiVersion: v1
kind: Pod
metadata:
name: my-app-secret-env
spec:
containers:
- name: my-app-container
image: alpine/git
command: ["sh", "-c", "env; sleep 3600"]
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: my-app-secret # Nombre del Secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-app-secret
key: password
kubectl apply -f pod-with-secret-env.yaml
k exec -it my-app-secret-env -- env | grep DB_USERNAME
k exec -it my-app-secret-env -- env | grep DB_PASSWORD
2. Como archivos en un volumen
Esta es la forma recomendada para consumir Secrets, ya que el archivo se monta en un tmpfs (sistema de archivos en memoria) y se puede controlar más finamente los permisos.
pod-with-secret-volume.yaml:
apiVersion: v1
kind: Pod
metadata:
name: my-app-secret-volume
spec:
containers:
- name: my-app-container
image: nginx:latest
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets # Ruta dentro del contenedor
readOnly: true # ¡Muy importante!
volumes:
- name: secret-volume
secret:
secretName: my-app-secret # Nombre del Secret
# Por defecto, los archivos se crean con permisos 0644. Puedes ajustarlos:
# defaultMode: 0400 # rw------- para el owner
kubectl apply -f pod-with-secret-volume.yaml
k exec -it my-app-secret-volume -- ls -l /etc/secrets
k exec -it my-app-secret-volume -- cat /etc/secrets/username
Dentro del contenedor, verás archivos username y password con los valores decodificados del Secret.
Tipos de Secrets 💡
Además del tipo Opaque general, Kubernetes tiene tipos de Secrets predefinidos que añaden validación o comportamientos específicos:
kubernetes.io/service-account-token: Para tokens de Service Account.kubernetes.io/dockercfgokubernetes.io/dockerconfigjson: Para credenciales de registro de imágenes (Docker Hub, GCR, ACR, ECR, etc.).kubernetes.io/tls: Para certificados TLS y claves privadas.
Por ejemplo, un Secret TLS:
apiVersion: v1
kind: Secret
metadata:
name: my-tls-secret
type: kubernetes.io/tls
data:
tls.crt: <base64 encoded cert>
tls.key: <base64 encoded key>
Diferencias Clave y Cuándo Usar Cada Uno 🎯
Aunque ConfigMaps y Secrets comparten la forma en que se consumen, su propósito y tratamiento de seguridad son muy diferentes.
| Característica | ConfigMap | Secret |
|---|---|---|
| Propósito | Datos de configuración no sensibles | Datos sensibles (contraseñas, API keys) |
| Almacenamiento | Texto plano (en etcd) | Codificado en Base64 (en etcd) |
| Seguridad por defecto | Baja (texto plano) | Media (Base64 no es cifrado) |
| Casos de uso | URLs de DB, niveles de log, flags | Contraseñas de DB, tokens, certificados TLS |
| Inmutabilidad | Por defecto (configurable) | Sí |
| Tipo | Opaque (implícito) | Opaque, kubernetes.io/tls, etc. |
Actualización de ConfigMaps y Secrets 🔄
Un punto crucial a entender es cómo los cambios en ConfigMaps y Secrets afectan a los pods en ejecución.
-
Variables de entorno: Los cambios en un ConfigMap o Secret no se reflejan automáticamente en las variables de entorno de los pods en ejecución. Para que los cambios surtan efecto, debes reiniciar los pods (por ejemplo, con un
rollout restartde tu Deployment). -
Volúmenes montados: Los ConfigMaps y Secrets montados como volúmenes se actualizan automáticamente en el sistema de archivos del pod. Sin embargo, esto puede tardar unos segundos o minutos (dependiendo de la configuración de Kubelet, típicamente de 60 a 300 segundos). La aplicación debe estar diseñada para detectar y recargar la configuración desde los archivos cuando estos cambian.
¿Cómo forzar un reinicio de Deployment tras un cambio de ConfigMap/Secret?
Una técnica común es usar un hash del ConfigMap o Secret en la plantilla del pod del Deployment. Cuando el ConfigMap/Secret cambia, el hash también cambia, lo que provoca que el Deployment detecte un cambio en la plantilla del pod y realice un rollout.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-deployment
spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
spec:
containers:
- name: my-app
image: my-app:latest
envFrom:
- configMapRef:
name: my-app-config
- secretRef:
name: my-app-secret
Esta técnica se usa a menudo con herramientas como Helm, donde {{ include ... | sha256sum }} es una función de plantilla. Para YAML plano, tendrías que generar el sha256sum manualmente o usar un operador de Kubernetes (como el Reloader de Stakater).
Buenas Prácticas y Consideraciones de Seguridad 🛡️
- Principio de mínimo privilegio: Otorga a los pods solo los Secrets y ConfigMaps que realmente necesitan. Usa RBAC para controlar quién puede leer o modificar estos objetos.
- No guardar Secrets en Git sin cifrar: Aunque los Secrets de Kubernetes están codificados en Base64, esto no es cifrado. Nunca almacenes manifiestos de Secrets con valores codificados directamente en un repositorio Git público. Utiliza herramientas como
kubeseal(Sealed Secrets) o soluciones de terceros como HashiCorp Vault para cifrar Secrets en reposo en Git. - Rotación de credenciales: Implementa una política de rotación regular para las credenciales almacenadas en Secrets. Kubernetes no lo hace automáticamente, pero puede integrarse con soluciones de gestión de identidades y accesos (IAM) o herramientas externas.
- Auditoría: Monitorea los accesos a Secrets y ConfigMaps a través de los logs de auditoría de Kubernetes.
- Secrets para Service Accounts: Los Service Accounts en Kubernetes usan Secrets para autenticar los pods con la API de Kubernetes. Entiende cómo funcionan para asegurar que tus pods tengan los permisos adecuados.
Escenarios Avanzados y Herramientas Complementarias 🚀
La gestión de configuración y secretos en Kubernetes va más allá de lo básico, especialmente en entornos de producción con alta exigencia.
Sealed Secrets (por Bitnami)
Intermedio
Sealed Secrets es una herramienta muy popular que resuelve el problema de almacenar Secrets cifrados en Git. Permite cifrar un Secret en un formato que puede ser almacenado de forma segura en un repositorio público, y solo el controlador de Sealed Secrets que se ejecuta en el clúster puede descifrarlo.
Esto es ideal para flujos de trabajo de GitOps.
HashiCorp Vault con Kubernetes
Avanzado
Para necesidades de seguridad más rigurosas y gestión de secretos a nivel empresarial, integrar HashiCorp Vault con Kubernetes es una solución robusta. Vault ofrece:
- Cifrado en reposo y en tránsito.
- Generación dinámica de credenciales: Vault puede generar credenciales de bases de datos, claves API, etc., justo a tiempo para que las aplicaciones las usen, con políticas de tiempo de vida (TTL).
- Auditoría completa.
- Integración con sistemas de autenticación: LDAP, GitHub, etc.
La integración con Kubernetes se realiza a menudo mediante el Vault Agent Injector o el Vault Kubernetes Auth Method. Esto permite que los pods se autentiquen con Vault y recuperen secretos sin necesidad de que estos sean almacenados en un Secret de Kubernetes, aumentando significativamente la seguridad.
Operadores de Configuración y Secretos
Algunos ecosistemas y herramientas ofrecen sus propios operadores para gestionar la configuración o los secretos, como por ejemplo:
- External Secrets Operator: Permite integrar Secrets de proveedores externos (AWS Secrets Manager, Azure Key Vault, Google Secret Manager) directamente en Kubernetes, creando Secrets de K8s a partir de ellos.
- Kubernetes Configuration Operator: (Menos común, pero existen soluciones personalizadas) Operadores que monitorizan ConfigMaps o Secrets y realizan acciones específicas, como reiniciar pods o ejecutar scripts, cuando estos cambian.
Conclusión ✨
La gestión de la configuración y los secretos es un pilar fundamental en la construcción de aplicaciones modernas en Kubernetes. Los ConfigMaps y Secrets son herramientas nativas y poderosas que, cuando se utilizan correctamente, mejoran la flexibilidad, la reutilización y, lo más importante, la seguridad de tus despliegues.
Desde inyectar simples variables de entorno hasta montar volúmenes de archivos sensibles, Kubernetes ofrece las primitivas necesarias para satisfacer una amplia gama de requisitos. Al combinar estas herramientas con buenas prácticas de seguridad y, cuando sea necesario, soluciones avanzadas como Sealed Secrets o HashiCorp Vault, puedes construir una infraestructura verdaderamente robusta y preparada para la producción.
Dominar estos conceptos te permitirá manejar de manera eficiente y segura las complejidades de la configuración de aplicaciones en un entorno de orquestación de contenedores.
Tutoriales relacionados
Comentarios (0)
Aún no hay comentarios. ¡Sé el primero!