tutoriales.com

Gestionando la Configuración de Entornos con Consul y Vault en Pipelines CI/CD

Este tutorial te guiará a través de la implementación de una estrategia robusta para la gestión de configuración de entornos en tus pipelines CI/CD. Aprenderás a utilizar HashiCorp Consul para el descubrimiento de servicios y el almacenamiento de configuraciones, y HashiCorp Vault para la gestión segura de secretos, asegurando que tus aplicaciones obtengan la configuración correcta y los secretos necesarios en cada entorno.

Intermedio20 min de lectura4 views
Reportar error

La gestión de configuración es un desafío común en el mundo de DevOps, especialmente cuando se trabaja con múltiples entornos (desarrollo, pruebas, pre-producción, producción) y microservicios. Las configuraciones suelen variar entre entornos, y la gestión de secretos (contraseñas de bases de datos, claves API, tokens) requiere una atención especial para garantizar la seguridad. Este tutorial explora cómo HashiCorp Consul y Vault pueden combinarse para proporcionar una solución integral y segura para este problema dentro de tus pipelines de Integración Continua y Despliegue Continuo (CI/CD).

🚀 Introducción: El Desafío de la Configuración en CI/CD

En un ciclo de vida de desarrollo de software moderno, una aplicación se mueve a través de diferentes etapas. Cada una de estas etapas (o entornos) a menudo requiere una configuración específica:

  • Entorno de Desarrollo: Puede usar bases de datos locales o de prueba, credenciales de bajo privilegio.
  • Entorno de Pruebas: Similares a desarrollo, pero con datos de prueba más realistas y quizás algunas integraciones externas.
  • Entorno de Pre-Producción: Muy cercano a producción, con configuraciones de red, bases de datos y servicios externos casi idénticos.
  • Entorno de Producción: Configuraciones de alta disponibilidad, credenciales de producción, optimizaciones de rendimiento.

Tradicionalmente, esta gestión se realizaba a menudo con archivos de configuración estáticos, lo que llevaba a problemas como:

  • Errores Manuales: Cambiar configuraciones manualmente es propenso a errores.
  • Fugas de Secretos: Almacenar secretos en repositorios de código (incluso si están encriptados) es una mala práctica de seguridad.
  • Dificultad de Escalabilidad: Mantener la coherencia en un gran número de servicios se vuelve complejo.
  • Falta de Auditoría: Es difícil saber quién accedió o modificó qué configuración.
🔥 Importante: La gestión inadecuada de la configuración y los secretos es una de las principales causas de brechas de seguridad y fallos en la producción.

¿Por qué Consul y Vault?

HashiCorp Consul es una herramienta de descubrimiento de servicios, configuración y segmentación de red. Nos proporciona:

  • Key-Value Store: Un almacén de clave-valor distribuido y consistente para almacenar configuraciones dinámicas.
  • Service Discovery: Permite que las aplicaciones encuentren otros servicios dinámicamente.
  • Salud de Servicios: Monitorea la salud de los servicios registrados.

HashiCorp Vault es una herramienta para la gestión de secretos. Nos proporciona:

  • Almacenamiento Seguro de Secretos: Guarda secretos de forma encriptada en un backend seguro.
  • Secretos Dinámicos: Genera credenciales bajo demanda con tiempos de vida limitados.
  • Auditoría: Registra cada acceso a un secreto.
  • Políticas de Acceso: Controla quién puede acceder a qué secretos.

Juntos, Consul y Vault ofrecen una solución robusta: Consul para la configuración y el descubrimiento, y Vault para la seguridad y el ciclo de vida de los secretos.

🛠️ Prerrequisitos y Configuración Inicial

Para seguir este tutorial, necesitarás:

  • Un entorno Linux (o WSL en Windows).
  • docker y docker-compose instalados.
  • Conocimientos básicos de CI/CD (GitHub Actions, GitLab CI, Jenkins, etc.).

Vamos a levantar un entorno básico con Consul y Vault usando Docker Compose.

Estructura del Proyecto

mkdir consul-vault-ci-cd
cd consul-vault-ci-cd
touch docker-compose.yml
touch vault-init.sh
touch .env

docker-compose.yml

version: '3.8'
services:
  consul:
    image: hashicorp/consul:1.15.2
    container_name: consul
    command: agent -server -bootstrap-expect=1 -client=0.0.0.0 -ui -data-dir=/consul/data
    ports:
      - "8500:8500"
      - "8600:8600/udp"
    environment:
      CONSUL_BIND_INTERFACE: eth0

  vault:
    image: hashicorp/vault:1.12.3
    container_name: vault
    ports:
      - "8200:8200"
    environment:
      VAULT_ADDR: http://127.0.0.1:8200
      VAULT_API_ADDR: http://127.0.0.1:8200
      VAULT_LOCAL_CONFIG: '{"storage": {"file": {"path": "/vault/file"}}, "listener": {"tcp":{"address": "0.0.0.0:8200", "tls_disable": 1}}, "default_lease_ttl": "168h", "max_lease_ttl": "720h"}'
    cap_add:
      - IPC_LOCK # Required for Vault
    volumes:
      - ./vault-data:/vault/file
    depends_on:
      - consul

  # Una aplicación de ejemplo que usará Consul y Vault
  app-example:
    build: .
    container_name: app-example
    environment:
      CONSUL_ADDR: consul:8500
      VAULT_ADDR: http://vault:8200
    depends_on:
      - consul
      - vault
    ports:
      - "8080:8080"

Dockerfile para la aplicación de ejemplo

Crea un Dockerfile en la raíz del proyecto para simular una aplicación que consume configuraciones y secretos. Usaremos un simple servidor Nginx para demostrar la inyección de variables de entorno.

FROM alpine/git:latest as builder
RUN apk add --no-cache curl bash

FROM nginx:alpine
COPY --from=builder /usr/bin/curl /usr/bin/bash /usr/bin/

# Simular la obtención de configuración y secretos
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

entrypoint.sh para la aplicación de ejemplo

#!/bin/bash

# Este script simula cómo una aplicación podría obtener configuración y secretos
# En un entorno real, usarías clientes de Consul y Vault dentro de tu aplicación.

# Esperar a que Vault y Consul estén listos
ATTEMPTS=0
while [ $ATTEMPTS -lt 30 ]; do
    if curl -s ${VAULT_ADDR}/v1/sys/health | grep '"initialized":true' > /dev/null && \
       curl -s ${CONSUL_ADDR}/v1/status/leader | grep '.' > /dev/null;
    then
        echo "Vault and Consul are ready."
        break
    fi
    echo "Waiting for Vault and Consul..."
    sleep 2
    ATTEMPTS=$((ATTEMPTS+1))
done

if [ $ATTEMPTS -eq 30 ]; then
    echo "Timeout waiting for Vault and Consul. Exiting."
    exit 1
fi

# Simular obtener configuraciones de Consul Key-Value Store
# En un caso real, esto se haría después de que Vault esté configurado y Vault token esté disponible
# para interactuar con Consul si se usa ACLs

# Simular obtener secretos de Vault
# Para este ejemplo, estamos asumiendo que ya hay un token de Vault disponible
# En un pipeline CI/CD, este token se obtendría de forma segura (e.g., AppRole, Kubernetes auth)

# Generar una página HTML con información de las variables de entorno
cat <<EOF > /usr/share/nginx/html/index.html
<!DOCTYPE html>
<html>
<head>
    <title>App Example</title>
    <style>
        body { font-family: sans-serif; background-color: #f4f4f4; color: #333; margin: 2em; }
        h1 { color: #0056b3; }
        pre { background-color: #eee; padding: 1em; border-radius: 5px; overflow-x: auto; }
        .badge { display: inline-block; padding: 0.25em 0.6em; font-size: 75%; font-weight: 700; line-height: 1; text-align: center; white-space: nowrap; vertical-align: baseline; border-radius: 0.25rem; margin-right: 5px; }
        .green { background-color: #28a745; color: white; }
        .blue { background-color: #007bff; color: white; }
        .red { background-color: #dc3545; color: white; }
    </style>
</head>
<body>
    <h1>Aplicación de Ejemplo con Configuración Dinámica</h1>
    <p><span class="badge green">Entorno:</span> ${APP_ENV:-Desconocido}</p>
    <p><span class="badge blue">Configuración de Consul (ejemplo):</span> ${CONSUL_CONFIG_ITEM:-No disponible}</p>
    <p><span class="badge red">Secreto de Vault (ejemplo):</span> ${VAULT_SECRET_ITEM:-No disponible}</p>
    <h2>Variables de Entorno Detectadas:</h2>
    <pre>
$(env)
    </pre>
</body>
</html>
EOF

exec "$@"

vault-init.sh para inicializar Vault

#!/bin/bash

export VAULT_ADDR='http://127.0.0.1:8200'

echo "Esperando a que Vault esté listo..."
ATTEMPTS=0
while [ $ATTEMPTS -lt 30 ]; do
    if curl -s ${VAULT_ADDR}/v1/sys/health | grep '"initialized":false' > /dev/null;
    then
        echo "Vault está activo pero no inicializado. Iniciando..."
        break
    elif curl -s ${VAULT_ADDR}/v1/sys/health | grep '"initialized":true' > /dev/null;
    then
        echo "Vault ya está inicializado. Saltando inicialización."
        exit 0
    fi
    sleep 2
    ATTEMPTS=$((ATTEMPTS+1))
done

if [ $ATTEMPTS -eq 30 ]; then
    echo "Tiempo de espera agotado esperando que Vault esté listo para inicialización. Saliendo."
    exit 1
fi

# Inicializar Vault
VAULT_INIT_RESPONSE=$(vault operator init -key-shares=1 -key-threshold=1 -format=json)
ROOT_TOKEN=$(echo $VAULT_INIT_RESPONSE | jq -r '.root_token')
UNSEAL_KEY=$(echo $VAULT_INIT_RESPONSE | jq -r '.unseal_keys_b64[0]')

if [ -z "$ROOT_TOKEN" ] || [ -z "$UNSEAL_KEY" ]; then
    echo "Error al inicializar Vault. Saliendo."
    exit 1
fi

export VAULT_TOKEN="$ROOT_TOKEN"

# Desellar Vault
vault operator unseal $UNSEAL_KEY

echo "Vault inicializado y desellado."

# Habilitar el motor de secretos KV v2 en 'secret/'
vault secrets enable -path=secret kv-v2

# Escribir un secreto de ejemplo
vault kv put secret/production/database username=produser password=supersecureprodpass
vault kv put secret/staging/database username=staginguser password=stagingpass

# Crear una política para un entorno específico (ej: production)
vault policy write production-policy - <<EOF
path "secret/data/production/*" {
  capabilities = ["read"]
}
EOF

vault policy write staging-policy - <<EOF
path "secret/data/staging/*" {
  capabilities = ["read"]
}
EOF

# Habilitar el método de autenticación AppRole
vault auth enable approle

# Crear un AppRole para el entorno de producción
vault write auth/approle/role/production-app token_num_uses=10 token_ttl=5m token_max_ttl=10m policies="production-policy"

# Leer Role ID y Secret ID (para demostración, en CI/CD serían variables de entorno o secretadas)
PRODUCTION_ROLE_ID=$(vault read -field=role_id auth/approle/role/production-app/role-id)
PRODUCTION_SECRET_ID=$(vault write -f -field=secret_id auth/approle/role/production-app/secret-id)

# Imprimir Role ID y Secret ID (CUIDADO: NO HACER EN PROD, solo para demo)
echo "--------------------------------------------------"
echo "Vault Root Token (¡CUIDADO! SOLO PARA DESARROLLO): $ROOT_TOKEN"
echo "Production AppRole Role ID: $PRODUCTION_ROLE_ID"
echo "Production AppRole Secret ID: $PRODUCTION_SECRET_ID"
echo "--------------------------------------------------"

# Configurar Consul Key-Value Store (ejemplo de configuración)
CONSUL_HTTP_ADDR="http://127.0.0.1:8500"

curl -X PUT -d '{"database_url": "jdbc:postgresql://prod-db:5432/myapp_prod"}' ${CONSUL_HTTP_ADDR}/v1/kv/production/config/database
curl -X PUT -d '{"api_key": "prod-api-key-123", "log_level": "INFO"}' ${CONSUL_HTTP_ADDR}/v1/kv/production/config/application

curl -X PUT -d '{"database_url": "jdbc:postgresql://staging-db:5432/myapp_staging"}' ${CONSUL_HTTP_ADDR}/v1/kv/staging/config/database
curl -X PUT -d '{"api_key": "staging-api-key-abc", "log_level": "DEBUG"}' ${CONSUL_HTTP_ADDR}/v1/kv/staging/config/application

echo "Consul KV store configurado."

# Mantener el script en ejecución para ver los logs si es necesario
wait

Levantar los Contenedores

docker-compose up -d

Luego de unos segundos, ejecuta el script de inicialización de Vault:

./vault-init.sh

Una vez que Vault esté inicializado y desellado, y Consul tenga la configuración, podrás acceder a la aplicación de ejemplo en http://localhost:8080.

💡 Consejo: El script `vault-init.sh` muestra cómo se inicializaría Vault y se configurarían algunos secretos y políticas. En un entorno real, la inicialización de Vault es un proceso muy sensible que debe ser manejado con extrema precaución y automatización robusta.

🔐 Vault: Gestión Segura de Secretos en CI/CD

Vault es la pieza clave para la seguridad. En un pipeline CI/CD, la forma más común y segura de autenticarse con Vault es usando métodos de autenticación específicos para máquinas, como AppRole o la autenticación de Kubernetes.

Flujo de Autenticación con AppRole en CI/CD

  1. Creación de Rol: Un administrador de Vault crea un AppRole para el pipeline o la aplicación, definiendo las políticas de acceso que tendrá (e.g., solo lectura a secret/data/production/*).
vault write auth/approle/role/ci-cd-prod token_num_uses=1 token_ttl=5m policies="production-policy"
  1. Generación de Role ID y Secret ID: El Role ID es público y se asocia al rol. El Secret ID es un secreto que se genera para cada instancia de AppRole.
# Obtener Role ID (puede ser público)
vault read -field=role_id auth/approle/role/ci-cd-prod/role-id

# Generar Secret ID (debe ser secreto)
vault write -f -field=secret_id auth/approle/role/ci-cd-prod/secret-id
  1. Almacenamiento Seguro: El Role ID se puede almacenar como una variable de entorno de CI/CD. El Secret ID DEBE ser tratado como un secreto y almacenado de forma segura en el sistema de secretos del proveedor de CI/CD (GitHub Secrets, GitLab CI/CD Variables, Jenkins Credentials Store).
  2. Autenticación en el Pipeline: Dentro del pipeline, la aplicación o script usa el Role ID y Secret ID para autenticarse con Vault y obtener un token de Vault de corta duración.
# Ejemplo de autenticación en un script de pipeline
ROLE_ID="your_role_id"
SECRET_ID="your_secret_id"
VAULT_TOKEN_RESPONSE=$(curl -s -X POST \
-d '{"role_id": "'$ROLE_ID'", "secret_id": "'$SECRET_ID'"}' \
$VAULT_ADDR/v1/auth/approle/login)

VAULT_TOKEN=$(echo $VAULT_TOKEN_RESPONSE | jq -r '.auth.client_token')
export VAULT_TOKEN
  1. Acceso a Secretos: Con el VAULT_TOKEN exportado, el pipeline puede ahora leer los secretos necesarios.
# Ejemplo de lectura de secreto
DATABASE_PASSWORD=$(vault kv get -field=password secret/production/database)
export DATABASE_PASSWORD
Autenticación AppRole en CI/CD 1. Admin crea AppRole (Genera Role ID y Secret ID) Almacén Seguro (GitHub Secrets/GitLab) 2. CI/CD Pipeline Obtiene Role ID y Secret ID 3. HashiCorp Vault Valida credenciales AppRole Auth Request 4. Token Devuelto 5. Uso del Token Acceso a secretos de la aplicación Pipeline usa Token
⚠️ Advertencia: NUNCA, bajo ninguna circunstancia, imprimas el `Secret ID` o el `VAULT_TOKEN` en los logs del pipeline. Asegúrate de que tus scripts los manejen de forma segura.

⚙️ Consul: Gestión Dinámica de Configuración

Consul, con su Key-Value Store (KV Store), nos permite almacenar configuraciones que pueden ser accedidas por las aplicaciones en tiempo de ejecución o inyectadas en los pipelines. Las configuraciones se pueden estructurar por entorno y por aplicación.

Estructura de Claves en Consul KV

Una buena práctica es organizar las claves jerárquicamente:

  • /production/my-app/database/connection-string
  • /production/my-app/api/base-url
  • /staging/my-app/database/connection-string
  • /development/my-app/log-level

Inyectando Configuración en el Pipeline

Durante el proceso de despliegue en un entorno específico, el pipeline puede consultar Consul para obtener la configuración relevante y pasarla a la aplicación como variables de entorno o archivos de configuración.

# Ejemplo de cómo un pipeline obtendría configuración de Consul para producción
ENVIRONMENT="production"
APP_NAME="my-app"
CONSUL_ADDR="consul:8500"

# Obtener la conexión a la base de datos para el entorno de producción
DB_CONNECTION_STRING=$(curl -s ${CONSUL_ADDR}/v1/kv/${ENVIRONMENT}/${APP_NAME}/database/connection-string?raw)
export DATABASE_URL="$DB_CONNECTION_STRING"

# Obtener el nivel de log
LOG_LEVEL=$(curl -s ${CONSUL_ADDR}/v1/kv/${ENVIRONMENT}/${APP_NAME}/log-level?raw)
export APP_LOG_LEVEL="$LOG_LEVEL"

echo "Configuración para $ENVIRONMENT cargada:"
echo "DATABASE_URL=$DATABASE_URL"
echo "APP_LOG_LEVEL=$APP_LOG_LEVEL"

# Ahora, tu script de despliegue puede usar estas variables para configurar la aplicación.
📌 Nota: Para entornos de producción, se recomienda usar el agente de Consul en los hosts de la aplicación para hacer la consulta de KV localmente y potencialmente usar un sistema de plantilla como `consul-template` para mantener los archivos de configuración actualizados automáticamente.

Consul-Template para Sincronización Automática

consul-template es una herramienta muy útil que consulta Consul (y Vault) y actualiza archivos en el sistema de archivos basados en plantillas. Cuando los valores en Consul o Vault cambian, consul-template detecta el cambio y regenera el archivo, y opcionalmente ejecuta un comando (como recargar un servidor web).

Ejemplo de plantilla (app_config.ctmpl):

database.url="{{ key "production/my-app/database/connection-string" }}"
api.key="{{ vault "secret/data/production/api-keys/my-app" "key" }}"
log.level="{{ key "production/my-app/log-level" }}"

Ejecutar consul-template:

consul-template \
  -consul-addr=$CONSUL_ADDR \
  -vault-addr=$VAULT_ADDR \
  -vault-token=$VAULT_TOKEN \
  -template "app_config.ctmpl:app_config.env:service restart"

Esto es ideal para aplicaciones que necesitan archivos de configuración en lugar de solo variables de entorno.


➡️ Integrando Consul y Vault en un Pipeline CI/CD Real

Ahora uniremos todo en un escenario de pipeline de ejemplo. Usaremos un pipeline genérico, pero los conceptos son aplicables a GitHub Actions, GitLab CI, Jenkins, Azure DevOps, etc.

Diagrama del Flujo de un Pipeline CI/CD

1. Push de Código 2. CI/CD Pipeline Activado 3. Build (Compilar) 4. Pruebas Unitarias 5. Autenticación (AppRole) VAULT 6. Vault devuelve Token 7. Pipeline lee Secretos 8. Lectura Config Consul CONSUL 9. Empaquetar Aplicación 10. Desplegar a Entorno

Pasos en el Pipeline

  1. Checkout del Código: El pipeline comienza clonando el repositorio de la aplicación.

  2. Configurar Variables de Entorno de Vault:

    • VAULT_ADDR: La URL de tu servidor Vault.
    • VAULT_ROLE_ID_<ENV>: El Role ID para el entorno actual (ej. VAULT_ROLE_ID_PRODUCTION).
    • VAULT_SECRET_ID_<ENV>: El Secret ID para el entorno actual. Este debe almacenarse como un secreto en tu sistema CI/CD.
  3. Configurar Variables de Entorno de Consul:

    • CONSUL_ADDR: La URL de tu servidor Consul.
  4. Autenticación con Vault (usando AppRole): El primer paso significativo es que el pipeline se autentique con Vault para obtener un token de corta duración.

# En un script de CI/CD
ENVIRONMENT="${CI_ENVIRONMENT_NAME}" # Variable de CI/CD que indica el entorno (production, staging, etc.)
ROLE_ID_VAR="VAULT_ROLE_ID_${ENVIRONMENT^^}" # Convertir a mayúsculas
SECRET_ID_VAR="VAULT_SECRET_ID_${ENVIRONMENT^^}"

ROLE_ID=$(eval echo "$$ROLE_ID_VAR")
SECRET_ID=$(eval echo "$$SECRET_ID_VAR")

# Autenticación
AUTH_RESPONSE=$(curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"role_id": "'$ROLE_ID'", "secret_id": "'$SECRET_ID'"}' \
"$VAULT_ADDR/v1/auth/approle/login")

VAULT_TOKEN=$(echo $AUTH_RESPONSE | jq -r '.auth.client_token')

if [ -z "$VAULT_TOKEN" ] || [ "$VAULT_TOKEN" == "null" ]; then
echo "Error al obtener el token de Vault."
exit 1
fi

export VAULT_TOKEN # Exportar para pasos posteriores
  1. Obtener Secretos de Vault: Con el VAULT_TOKEN disponible, el pipeline puede ahora leer los secretos específicos del entorno.
# En un script de CI/CD
DB_USER=$(vault kv get -field=username secret/${ENVIRONMENT}/database)
DB_PASS=$(vault kv get -field=password secret/${ENVIRONMENT}/database)

export DB_USER
export DB_PASS

# Si usas GitLab CI, puedes pasar estas variables como CI/CD variables a jobs posteriores
# echo "DB_USER=$DB_USER" >> build.env
# echo "DB_PASS=$DB_PASS" >> build.env
  1. Obtener Configuración de Consul: De manera similar, se puede consultar Consul para obtener configuraciones.
# En un script de CI/CD
CONSUL_HTTP_ADDR="$CONSUL_ADDR"

APP_DB_URL=$(curl -s ${CONSUL_HTTP_ADDR}/v1/kv/${ENVIRONMENT}/config/database/database_url?raw)
APP_LOG_LEVEL=$(curl -s ${CONSUL_HTTP_ADDR}/v1/kv/${ENVIRONMENT}/config/application/log_level?raw)

export APP_DB_URL
export APP_LOG_LEVEL
  1. Empaquetar y Desplegar: La aplicación se empaqueta (ej. imagen Docker) con estas variables de entorno, o estas variables se inyectan en el entorno de ejecución del contenedor/servidor durante el despliegue.

    90% Completado
    Ejemplo de un job de GitLab CI/CD
stages:
- build
- deploy

variables:
VAULT_ADDR: "http://vault.example.com:8200"
CONSUL_ADDR: "http://consul.example.com:8500"
VAULT_ROLE_ID_PRODUCTION: "<your_prod_role_id>" # Configurar como variable de CI/CD en GitLab
VAULT_ROLE_ID_STAGING: "<your_staging_role_id>" # Configurar como variable de CI/CD en GitLab
# VAULT_SECRET_ID_PRODUCTION y VAULT_SECRET_ID_STAGING DEBEN ser variables secretas de CI/CD

build_and_deploy_production:
stage: deploy
image: curlimages/curl:latest # Imagen ligera con curl y jq
environment: production
script:
- | # Autenticar con Vault
ENVIRONMENT="production"
ROLE_ID_VAR="VAULT_ROLE_ID_${ENVIRONMENT^^}"
SECRET_ID_VAR="VAULT_SECRET_ID_${ENVIRONMENT^^}"

ROLE_ID=$(eval echo "$$ROLE_ID_VAR")
SECRET_ID="$VAULT_SECRET_ID_PRODUCTION" # Obtener de variable secreta de GitLab

AUTH_RESPONSE=$(curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"role_id": "'$ROLE_ID'", "secret_id": "'$SECRET_ID'"}' \
"$VAULT_ADDR/v1/auth/approle/login")

VAULT_TOKEN=$(echo $AUTH_RESPONSE | jq -r '.auth.client_token')

if [ -z "$VAULT_TOKEN" ] || [ "$VAULT_TOKEN" == "null" ]; then
echo "Error al obtener el token de Vault."
exit 1
fi

export VAULT_TOKEN

- | # Obtener secretos de Vault
DB_USER=$(curl -s -H "X-Vault-Token: $VAULT_TOKEN" "$VAULT_ADDR/v1/secret/data/production/database" | jq -r '.data.data.username')
DB_PASS=$(curl -s -H "X-Vault-Token: $VAULT_TOKEN" "$VAULT_ADDR/v1/secret/data/production/database" | jq -r '.data.data.password')

export DB_USER
export DB_PASS

- | # Obtener configuración de Consul
APP_DB_URL=$(curl -s "$CONSUL_ADDR/v1/kv/production/config/database/database_url?raw")
APP_LOG_LEVEL=$(curl -s "$CONSUL_ADDR/v1/kv/production/config/application/log_level?raw")

export APP_DB_URL
export APP_LOG_LEVEL

- | # Simular despliegue
echo "Iniciando despliegue en PROD con la siguiente configuración:"
echo "Database User: $DB_USER"
echo "Database URL: $APP_DB_URL"
echo "Log Level: $APP_LOG_LEVEL"
echo "Secreto de base de datos se obtuvo correctamente y no se expuso en logs."

# Comando real de despliegue (ej. kubectl apply -f deployment.yaml)
# ...
</details>

✅ Buenas Prácticas y Consideraciones Adicionales

🔒 Seguridad

  • Rotación de Secret ID: Los Secret ID de AppRole pueden tener un número limitado de usos (token_num_uses) y un TTL (token_ttl). Rota estos IDs regularmente, especialmente si se filtran.
  • Políticas de Vault Mínimo Privilegio: Asegúrate de que las políticas de Vault solo permitan acceso a los secretos y caminos de configuración estrictamente necesarios para cada aplicación/entorno.
  • Vault en Alta Disponibilidad: Para entornos de producción, Vault debe configurarse en modo de alta disponibilidad con un backend de almacenamiento persistente y seguro (ej., S3, Google Cloud Storage, Raft).
  • TLS/SSL: Tanto Consul como Vault deben configurarse para usar TLS para todas las comunicaciones, especialmente si están expuestos a la red.
  • Auditoría: Habilita los logs de auditoría en Vault para rastrear cada acceso a secretos.

📈 Escalabilidad y Rendimiento

  • Agentes de Consul: Para aplicaciones que necesitan acceder a Consul KV frecuentemente, considera ejecutar un agente de Consul en cada host. Esto proporciona un acceso local y evita sobrecargar el servidor de Consul.
  • Caché: Si la configuración no cambia con frecuencia, puedes implementar capas de caché para las configuraciones obtenidas de Consul.

📝 Organización y Mantenimiento

  • GitOps para Configuración: Considera almacenar la estructura de claves y valores de Consul KV en un repositorio Git y usar herramientas como consul-cli o consul-template para aplicar los cambios, siguiendo los principios de GitOps.
  • Consul-Template: Es muy poderoso para inyectar configuraciones dinámicamente en archivos en los servidores o contenedores de la aplicación.
Paso 1: Definir políticas de Vault de mínimo privilegio.
Paso 2: Configurar AppRoles con rotación de Secret ID.
Paso 3: Estructurar Consul KV de forma jerárquica por entorno.
Paso 4: Automatizar la inyección de secretos y configuración en el pipeline.
Paso 5: Implementar monitoreo y auditoría en Vault y Consul.

Limpiar el Entorno

Para detener y eliminar los contenedores y los datos generados:

docker-compose down -v
rm -rf vault-data
rm vault-init.sh
rm Dockerfile
rm entrypoint.sh
rm .env # Si lo creaste

💡 Conclusión

La combinación de HashiCorp Consul y Vault ofrece una solución potente y segura para la gestión de configuración y secretos en entornos CI/CD. Al desacoplar la configuración y los secretos del código fuente y centralizarlos en estos sistemas dedicados, las organizaciones pueden mejorar significativamente la seguridad, la auditabilidad y la escalabilidad de sus despliegues. Adoptar estas herramientas es un paso crucial hacia una infraestructura DevOps más madura y resiliente.

Esperamos que este tutorial te haya proporcionado una base sólida para integrar Consul y Vault en tus propios pipelines.

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!