StackPractices
intermediate Por Mathias Paulenko

Gestión de Secretos: Vault y Cloud Managers

Guía práctica de gestión de secretos: HashiCorp Vault, AWS Secrets Manager, Azure Key Vault y GCP Secret Manager con rotación, control de acceso e integración CI/CD.

Overview

Los secretos (contraseñas, claves de API, tokens, certificados) son las llaves de tu reino. Almacenarlos en código fuente, archivos de configuración o variables de entorno es una fuente común de brechas. Una gestión adecuada de secretos garantiza que las credenciales estén cifradas, rotadas, auditadas y accesibles solo para servicios y usuarios autorizados. Para conocimientos fundamentales, consulta la Guía de Secure Coding y la Guía de Cifrado Básico. A continuación, las soluciones líderes de gestión de secretos y las prácticas que las hacen útiles.

Cuándo Usar

  • Para alternativas, consulta la Guía Completa de Gestión de Secretos.

  • Tienes credenciales, claves de API o certificados para proteger

  • Necesitas compartir secretos entre equipos o servicios

  • Quieres auditar quién accedió a qué secreto y cuándo

  • Estás construyendo un pipeline CI/CD que necesita secretos en runtime

Qué No Hacer

Anti-PatrónPor Qué FallaQué Hacer en su Lugar
Hardcodear secretos en códigoLos commits a Git son para siempre; el historial filtraUsar referencias de secretos
Guardar secretos en variables de entornoVisibles en dumps de procesos, /proc y endpoints de debugUsar gestores de secretos con inyección en runtime
Compartir una contraseña entre serviciosEl radio de explosión es toda la infraestructuraCredenciales específicas por servicio
Nunca rotar secretosLas claves comprometidas permanecen válidas indefinidamenteAutomatizar rotación
Enviar secretos por Slack/emailSin encriptar, sin registro, sin controlUsar herramientas aprobadas de intercambio de secretos

HashiCorp Vault

El estándar open-source para gestión de secretos. HashiCorp Vault proporciona una API unificada para almacenar, rotar y auditar secretos en múltiples clouds. La cheat sheet de gestión de secretos de OWASP recomienda usar un almacén de secretos dedicado en lugar de variables de entorno.

Conceptos Clave

ComponentePropósito
Secrets EngineAlmacena o genera secretos (KV, database, PKI, AWS)
Auth MethodCómo usuarios/servicios se autentican (Kubernetes, OIDC, AppRole)
PolicyControl de acceso granular (ACL)
Secreto bajo demandaCredenciales de corta duración, revocadas automáticamente

Credenciales de Base de Datos Bajo Demanda

# Habilitar motor de secretos de base de datos
vault secrets enable database

# Configurar conexión PostgreSQL
vault write database/config/my-postgresql \
  plugin_name=postgresql-database-plugin \
  allowed_roles="app" \
  connection_url="postgresql://{{username}}:{{password}}@db:5432/mydb" \
  username="vaultadmin" \
  password="vaultpass"

# Crear un rol que genera leases de 1 hora
vault write database/roles/app \
  db_name=my-postgresql \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';" \
  default_ttl="1h" \
  max_ttl="24h"

Lectura de Secretos en Aplicaciones

import hvac

client = hvac.Client(url='https://vault.example.com')
client.auth.kubernetes.login(role='my-app', jwt=service_account_token)

# Leer un secreto estático
secret = client.secrets.kv.v2.read_secret_version(path='my-app/config')
api_key = secret['data']['data']['api_key']

# Generar credenciales de base de datos bajo demanda
db_creds = client.secrets.database.generate_credentials(name='app')
username = db_creds['data']['username']
password = db_creds['data']['password']

Ejemplo de Política de Vault

Vault usa políticas para controlar quién puede acceder a qué secretos. Una política de least-privilege otorga acceso de solo lectura a una ruta específica:

# Otorgar acceso de solo lectura a secretos del payment-service
path "secret/data/payment-service/*" {
  capabilities = ["read"]
}

# Otorgar acceso para generar credenciales de base de datos
path "database/creds/payment-app" {
  capabilities = ["read"]
}

Evita políticas wildcard como path "secret/data/*" en producción. Cada servicio debe tener su propia política scoped a sus secretos. Audita cambios de política con vault audit enable file para registrar cada decisión de acceso.

AWS Secrets Manager

Rotación de secretos gestionada completamente para cargas de trabajo AWS. La documentación de AWS Secrets Manager cubre la rotación automática con funciones Lambda. Secrets Manager se integra nativamente con RDS, Redshift y DocumentDB, y soporta rotación personalizada para otros servicios vía Lambda.

Cómo Funciona la Rotación

Cuando configuras la rotación, Secrets Manager llama a una función Lambda según un calendario. La función Lambda:

  1. Genera una nueva contraseña.
  2. Actualiza la base de datos o servicio con las nuevas credenciales.
  3. Actualiza el secreto en Secrets Manager.
  4. Opcionalmente notifica a las aplicaciones para refrescar las credenciales en caché.

Para RDS, AWS tiene plantillas de rotación pre-construidas. Para servicios personalizados, escribes una Lambda que usa el protocolo de rotación de cuatro pasos.

# Crear un secreto
aws secretsmanager create-secret \
  --name prod/database/password \
  --secret-string '{"username":"admin","password":"supersecret"}'

# Recuperar un secreto
aws secretsmanager get-secret-value --secret-id prod/database/password

# Configurar rotación automática
aws secretsmanager rotate-secret \
  --secret-id prod/database/password \
  --rotation-lambda-arn arn:aws:lambda:...:function:rotation \
  --automatically-after-days 30

Política IAM para Acceso

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["secretsmanager:GetSecretValue"],
      "Resource": "arn:aws:secretsmanager:*:*:secret:prod/*",
      "Condition": {
        "StringEquals": {
          "aws:SourceVpc": "vpc-12345"
        }
      }
    }
  ]
}

Azure Key Vault

Integrado con Azure AD y ecosistemas Microsoft. Key Vault almacena secretos, certificados y claves con respaldo de hardware security module (HSM) para tiers premium. La ventaja principal sobre otros gestores es la integración nativa con autenticación Azure AD: los servicios se autentican con Managed Identity, eliminando la necesidad de almacenar credenciales para acceder al vault.

Managed Identity vs Service Principal

Managed Identity es el enfoque recomendado para cargas de trabajo Azure. Elimina la necesidad de almacenar client secrets: la identidad se asigna al recurso de cómputo (VM, App Service, pod de AKS) y Azure AD maneja la adquisición de tokens automáticamente. Los Service Principals requieren almacenar un client secret, lo que crea un problema de huevo-y-gallina.

# Crear un Key Vault
az keyvault create --name myvault --resource-group mygroup --location eastus

# Almacenar un secreto
az keyvault secret set --vault-name myvault --name db-password --value secret123

# Recuperar un secreto
az keyvault secret show --vault-name myvault --name db-password

Acceso con Managed Identity

from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient

credential = DefaultAzureCredential()
client = SecretClient(vault_url="https://myvault.vault.azure.net/", credential=credential)

secret = client.get_secret("db-password")
print(secret.value)

GCP Secret Manager

Integración nativa con IAM de GCP y Cloud Run. Secret Manager almacena versiones de secretos, por lo que puedes volver a una versión anterior si una rotación falla. El acceso se controla vía roles IAM: roles/secretmanager.secretAccessor para lectura, roles/secretmanager.secretAdmin para gestión.

# Crear un secreto
echo -n "supersecret" | gcloud secrets create db-password --data-file=-

# Agregar una versión
echo -n "newsecret" | gcloud secrets versions add db-password --data-file=-

# Acceder desde Cloud Run (sin cambios de código)
gcloud run deploy my-app --set-secrets=DB_PASSWORD=db-password:latest

Control de Acceso IAM

Otorga a una service account acceso a un secreto específico:

# Otorgar acceso a un secreto específico
gcloud secrets add-iam-policy-binding db-password \
  --member="serviceAccount:my-app@my-project.iam.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor"

Usa secretAccessor para el runtime de aplicaciones, secretAdmin para pipelines CI/CD que gestionan secretos. Evita otorgar secretAdmin a cargas de trabajo de producción.

Integración CI/CD

GitHub Actions con OIDC

jobs:
  deploy:
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789:role/GitHubActionsRole
          aws-region: us-east-1
      - run: |
          DB_PASSWORD=$(aws secretsmanager get-secret-value --secret-id db-password --query SecretString --output text)
          echo "DB_PASSWORD=$DB_PASSWORD" >> $GITHUB_ENV

Escaneo de Secretos en Pipelines

# Detectar secretos antes del merge
 trufflehog filesystem --directory=.
 gitleaks detect --source .
 detect-secrets scan

Estrategias de Rotación

EstrategiaMejor ParaComplejidad
ManualAd-hoc, equipos pequeñosBaja
Lambda/FunctionAWS RDS, bases de datos estándarMedia
Vault Bajo DemandaMicroservicios, multi-cloudAlta
Certificado AutoCertificados TLS (Let’s Encrypt, ACM)Baja

Cuándo Usar Cada Estrategia

Manual funciona para equipos con menos de 10 secretos y sin requisitos de compliance. Documenta el proceso de rotación y configura recordatorios de calendario. El riesgo es el error humano: rotaciones olvidadas dejan credenciales obsoletas.

Lambda/Function es el punto intermedio ideal para cargas de trabajo AWS. AWS tiene plantillas de rotación pre-construidas para RDS, Redshift y DocumentDB. Para servicios personalizados, escribes una Lambda que use el protocolo de cuatro pasos (generar, actualizar, verificar, finalizar). Configura intervalos de rotación entre 30-90 días.

Vault Bajo Demanda elimina la rotación por completo. En lugar de rotar una contraseña estática, Vault genera credenciales de corta duración en cada solicitud. Las credenciales expiran tras un TTL (típicamente 1 hora). Es el enfoque más seguro pero requiere infraestructura Vault y cambios en la aplicación.

Certificado Auto aplica a certificados TLS. Let’s Encrypt y AWS ACM manejan la rotación automáticamente. El desafío es asegurar que el certificado renovado se despliegue a todos los endpoints antes de que el viejo expire.

Flujo de Rotación Dual-Secret

El patrón de doble secreto permite rotar secretos sin downtime. El secreto nuevo se despliega mientras el viejo sigue activo, y luego se revoca el viejo tras la verificación:

flowchart diagram: Crear Secreto Nuevo

Errores Comunes

  • Usar un secreto para todos los ambientes: separa secretos de prod, staging y dev
  • Sin logging de auditoría: no puedes investigar brechas sin logs de acceso
  • Políticas demasiado permisivas: un token CI/CD comprometido no debería acceder a secretos de producción
  • Ignorar la proliferación de secretos: claves viejas de API en variables de entorno, logs y backups
  • Sin plan de revocación: cuando un secreto filtra, ¿qué tan rápido puedes rotarlo?
  • Guardar secretos en archivos .env commiteados a Git: incluso un .env.example con valores reales filtra. Usa .env.example solo con valores placeholder
  • Hardcodear secretos en imágenes Docker: docker history expone cada capa. Usa inyección en runtime vía Vault o cloud secret managers
  • Compartir secretos por Slack o email: estos canales no están cifrados, ni registrados, ni son auditables. Usa una herramienta de intercambio de secretos como OnionShare o la función de sharing de tu gestor de secretos

Temas Avanzados

Escenario: Gestión de Secretos para Microservicios

Sistema: 10 microservicios en K8s, AWS
Stack: AWS Secrets Manager + External Secrets Operator

Arquitectura:
  Developer -> GitHub (secreto en repo: NUNCA)
  Developer -> AWS Secrets Manager (manual o CLI)
  Secrets Manager -> External Secrets Operator (K8s)
  ESO -> crea Kubernetes Secret
  Pod -> monta Secret como env var o volumen

Reglas de secretos:
  | Regla | Razón |
  |-------|-------|
  | Nunca en código | El historial de Git es permanente |
  | Nunca en .env en prod | Archivo plano en disco |
  | Nunca en logs | Los logs son accesibles |
  | Nunca en mensajes de error | Expone al cliente |
  | Rotación automática | Minimiza impacto de fuga |
  | Least privilege | Cada servicio solo accede sus secretos |
  | Audit log | Quién accedió qué secreto y cuándo |
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: payment-service-secrets
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secretsmanager
    kind: ClusterSecretStore
  target:
    name: payment-service-secrets
    creationPolicy: Owner
  data:
    - secretKey: DATABASE_URL
      remoteRef:
        key: production/payment-service/database-url
    - secretKey: STRIPE_SECRET_KEY
      remoteRef:
        key: production/payment-service/stripe-key
    - secretKey: JWT_PRIVATE_KEY
      remoteRef:
        key: production/payment-service/jwt-private

Rotación automática (Secrets Manager):

  • Base de datos: rotación cada 30 días (función Lambda)
  • Stripe: rotación manual (la API no soporta auto-rotación)
  • JWT: rotación cada 90 días (desplegar nueva clave, mantener la vieja 7 días)
  • Claves de API: rotación cada 60 días

Detección de fugas:

  • git-secrets: pre-commit hook bloquea commits con patrones
  • TruffleHog: escanea el historial de git
  • GitHub Secret Scanning: alertas automáticas
  • AWS CloudTrail: log de auditoría de acceso a Secrets Manager

Lecciones:

  • External Secrets Operator sincroniza secretos sin K8s manuales
  • La rotación automática minimiza el impacto de fugas
  • git-secrets en pre-commit es la primera línea de defensa
  • Cada servicio debe tener sus propios secretos (sin compartir)
  • El log de auditoría de acceso a secretos es obligatorio para SOC2

¿Cómo roto secretos sin downtime?

Usa el patrón de doble secreto: configura el nuevo secreto mientras el viejo sigue activo. Despliega la app con el nuevo secreto. Verifica que funciona. Después de confirmar, invalida el viejo. Para JWT, acepta ambas claves durante un periodo de transición (7 días). Para DB, rota la contraseña vía Secrets Manager con una función Lambda que actualice el password y refresque los pods.

See Also

Preguntas frecuentes

¿Debería usar Vault o un gestor nativo de cloud?

Usa Vault para multi-cloud, flujos complejos o secretos bajo demanda. Usa gestores nativos (AWS, Azure, GCP) para simplicidad e integración directa con ese cloud.

¿Con qué frecuencia debería rotar secretos?
  • Credenciales de base de datos: 30-90 días
  • Claves de API: 90 días o al momento de desvinculación de empleado
  • Certificados TLS: antes del vencimiento (típicamente anual)
  • Emergencia: inmediatamente ante sospecha de compromiso
¿Puedo evitar que desarrolladores vean secretos?

Sí. Otorga read pero no list ni update. Usa credenciales bajo demanda para que los desarrolladores obtengan permisos temporales y limitados sin ver la contraseña raíz.

¿Cómo empiezo con esto en un proyecto existente?

Empieza con una parte pequeña y aislada de tu codebase. Aplica los conceptos de esta guía a un módulo o servicio. Mide el impacto, luego expande a otras áreas.

¿Qué herramientas necesito?

Las herramientas mencionadas a lo largo de esta guía se listan en cada sección. La mayoría son open-source y ampliamente adoptadas. Consulta los recursos relacionados para instrucciones de configuración.

¿Cómo mido el éxito después de implementar esto?

Define métricas claras antes de empezar: indicadores de rendimiento, tasas de error o métricas de mantenibilidad. Compara antes y después. Itera basándote en datos, no en suposiciones.