HashiCorp Vault resuelve uno de los problemas más persistentes de la infraestructura moderna: ¿dónde se almacenan y distribuyen los secretos de forma segura? Las credenciales codificadas en archivos de configuración, las variables de entorno confirmadas en git y las hojas de cálculo de contraseñas compartidas son responsables de una proporción desproporcionada de brechas de seguridad. HashiCorp Vault proporciona una API unificada para la gestión de secretos, la generación dinámica de credenciales, el cifrado como servicio y el control de acceso granular — todo ello con una pista de auditoría completa. En esta guía aprenderás cómo funciona Vault, cómo desplegarlo y cómo integrarlo con Kubernetes y Terraform en un flujo de trabajo real de producción.

Requisitos Previos

  • Host con Linux o macOS (o un clúster de Kubernetes para la ruta nativa en la nube)
  • Familiaridad básica con la línea de comandos y la configuración YAML
  • Docker (opcional, para un servidor de desarrollo rápido)
  • Un clúster de Kubernetes con acceso a kubectl (para la sección de integración con Kubernetes)
  • Terraform 1.x instalado (para la sección del proveedor de Terraform)
  • Es útil comprender los certificados TLS, aunque no es obligatorio

Cómo Funciona HashiCorp Vault

En esencia, Vault es un proceso que expone una API HTTP. Todo —leer secretos, autenticarse, gestionar políticas— pasa por esa API. Vault almacena sus datos en un backend de almacenamiento (el almacenamiento integrado basado en Raft es el predeterminado recomendado) y cifra todo en reposo usando una clave maestra que nunca sale de la memoria.

Cuando Vault arranca, está sellado: contiene los datos cifrados pero no puede descifrarlos porque la clave maestra está dividida en múltiples fragmentos de clave de desellado mediante el esquema de secreto compartido de Shamir. Vault solo se vuelve operativo después de que se proporcione el quórum mínimo de fragmentos de clave. Este diseño significa que incluso si alguien roba el backend de almacenamiento, no puede leer ningún secreto sin las claves de desellado.

Conceptos clave

  • Motores de secretos — plugins que generan o almacenan secretos. El motor KV almacena pares clave/valor estáticos. El motor Database genera credenciales dinámicas. El motor PKI emite certificados X.509.
  • Métodos de autenticación — cómo los clientes prueban su identidad a Vault. Las opciones incluyen AppRole (para máquinas), cuentas de servicio de Kubernetes, AWS IAM, LDAP, GitHub y OIDC.
  • Políticas — archivos HCL que conceden acceso de lectura, escritura o administración a rutas específicas en Vault.
  • Arrendamientos y TTLs — cada secreto tiene un arrendamiento; cuando expira, Vault lo revoca. Las aplicaciones deben renovar o volver a solicitar las credenciales antes de que expiren.
  • Dispositivos de auditoría — Vault puede escribir cada solicitud y respuesta en un archivo de registro, syslog o socket. La auditoría es a prueba de manipulaciones y está verificada criptográficamente.

Instalación e Inicialización de Vault

Para un despliegue de nivel productivo, HashiCorp recomienda ejecutar Vault en modo Alta Disponibilidad (HA) con almacenamiento integrado en tres o cinco nodos. Para aprendizaje, un único servidor de desarrollo es suficiente.

Servidor de desarrollo rápido (no apto para producción):

vault server -dev

Esto inicia un Vault en memoria, lo desella automáticamente e imprime un token raíz. Los datos se pierden cuando el proceso termina.

Nodo único en producción con almacenamiento integrado:

Crea /etc/vault.d/vault.hcl:

ui = true

storage "raft" {
  path    = "/opt/vault/data"
  node_id = "vault-node-1"
}

listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_cert_file = "/opt/vault/tls/vault.crt"
  tls_key_file  = "/opt/vault/tls/vault.key"
}

api_addr     = "https://vault.example.com:8200"
cluster_addr = "https://vault.example.com:8201"

Inicia el servicio y luego inicialízalo:

vault operator init -key-shares=5 -key-threshold=3

Esto genera cinco claves de desellado y un token raíz. Guárdalos en ubicaciones seguras y separadas de inmediato — perder suficientes fragmentos de clave significa perder el acceso a todos tus datos de forma permanente. Desella con tres de las cinco claves:

vault operator unseal <clave-1>
vault operator unseal <clave-2>
vault operator unseal <clave-3>

Secretos Dinámicos: La Ventaja Principal

Las credenciales estáticas (una contraseña de base de datos que nunca cambia) son un riesgo. Si se filtran, la ventana de exposición es indefinida. Los secretos dinámicos cierran esa ventana.

Habilita el motor de secretos de base de datos y configúralo para PostgreSQL:

vault secrets enable database

vault write database/config/myapp-db \
  plugin_name=postgresql-database-plugin \
  allowed_roles="myapp-role" \
  connection_url="postgresql://{{username}}:{{password}}@db.example.com:5432/myapp" \
  username="vault" \
  password="vault-superuser-password"

vault write database/roles/myapp-role \
  db_name=myapp-db \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
  default_ttl="1h" \
  max_ttl="24h"

Ahora cualquier aplicación o trabajo de CI con la política de Vault correcta puede ejecutar:

vault read database/creds/myapp-role

Vault se conecta a PostgreSQL, crea un usuario con nombre único y devuelve credenciales que expiran en una hora. Cuando el arrendamiento vence (o la aplicación llama a vault lease revoke), Vault elimina el usuario de la base de datos. La aplicación nunca retiene una contraseña de larga duración.

Motor de Secretos PKI para Certificados Internos

La gestión manual de certificados TLS es propensa a errores y raramente auditada. El motor de secretos PKI de Vault actúa como una Autoridad Certificadora interna, emitiendo certificados de corta duración bajo demanda.

vault secrets enable pki
vault secrets tune -max-lease-ttl=87600h pki

# Generar CA raíz (guarda el certificado externamente, mantenlo offline si es posible)
vault write -field=certificate pki/root/generate/internal \
  common_name="example.com" \
  ttl=87600h > CA_cert.crt

# Configurar URLs de CRL y emisión
vault write pki/config/urls \
  issuing_certificates="https://vault.example.com:8200/v1/pki/ca" \
  crl_distribution_points="https://vault.example.com:8200/v1/pki/crl"

# Habilitar CA intermedia (mejor práctica para producción)
vault secrets enable -path=pki_int pki
vault write -format=json pki_int/intermediate/generate/internal \
  common_name="example.com Intermediate Authority" | jq -r '.data.csr' > pki_int.csr

vault write -format=json pki/root/sign-intermediate csr=@pki_int.csr \
  format=pem_bundle ttl="43800h" | jq -r '.data.certificate' > intermediate.cert.pem

vault write pki_int/intermediate/set-signed certificate=@intermediate.cert.pem

# Crear un rol para emitir certificados de servidor
vault write pki_int/roles/example-dot-com \
  allowed_domains="example.com" \
  allow_subdomains=true \
  max_ttl="72h"

Cualquier servicio que necesite un certificado TLS lo solicita con:

vault write pki_int/issue/example-dot-com common_name="api.example.com" ttl="24h"

Los certificados válidos por 24 horas eliminan el riesgo de rotaciones de certificados olvidadas.

Integración con Kubernetes mediante Vault Agent Injector

Los Kubernetes Secrets están codificados en base64 y almacenados en etcd. Sin controles adicionales, cualquier usuario con acceso a kubectl get secret puede leerlos. El Agent Injector de Vault mantiene los secretos completamente fuera de Kubernetes.

Instala con Helm:

helm repo add hashicorp https://helm.releases.hashicorp.com
helm install vault hashicorp/vault \
  --set "injector.enabled=true" \
  --set "server.dev.enabled=false"

Habilita y configura la autenticación de Kubernetes en Vault:

vault auth enable kubernetes

vault write auth/kubernetes/config \
  kubernetes_host="https://kubernetes.default.svc" \
  kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

Crea una política y un rol:

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

vault write auth/kubernetes/role/myapp \
  bound_service_account_names=myapp \
  bound_service_account_namespaces=production \
  policies=myapp \
  ttl=1h

Anota tu pod para inyectar secretos en tiempo de ejecución:

annotations:
  vault.hashicorp.com/agent-inject: "true"
  vault.hashicorp.com/role: "myapp"
  vault.hashicorp.com/agent-inject-secret-config.env: "secret/data/myapp/config"
  vault.hashicorp.com/agent-inject-template-config.env: |
    {{- with secret "secret/data/myapp/config" -}}
    export DB_PASSWORD="{{ .Data.data.db_password }}"
    {{- end }}

El sidecar Vault Agent se autentica, obtiene el secreto, lo escribe en un volumen en memoria compartido y lo renueva antes de que expire. La aplicación lee un archivo — nunca realiza una llamada a la API de Vault.

Comparativa: Vault vs. Alternativas de Gestión de Secretos

CaracterísticaHashiCorp VaultAWS Secrets ManagerAzure Key VaultKubernetes Secrets
Secretos dinámicosSí (base de datos, nube, PKI)Limitado (solo RDS)NoNo
Multi-nubeSolo AWSSolo AzureSí (con CSI)
PKI / CACA completa con CRLNoSí (limitado)No
AuditoríaIntegrada, a prueba de manipulacionesCloudTrailAzure MonitorRequiere complemento
AutoalojadoNoNo
CosteGratuito (Community)Por secreto + llamada APIPor operaciónGratuito
Nativo en KubernetesAgent Injector / VSOControlador CSIControlador CSINativo
Curva de aprendizajeAltaBajaBajaMuy baja

Vault es la elección correcta cuando necesitas una gestión de secretos auditable y neutral en cuanto a proveedor, con generación dinámica de credenciales en múltiples plataformas. AWS Secrets Manager gana cuando eres 100% nativo de AWS y la simplicidad es la prioridad.

Escenario del Mundo Real: Protección de una Aplicación Multi-Capa

Tienes un clúster de Kubernetes en producción que ejecuta una API de Node.js, una base de datos PostgreSQL y una caché Redis. Tu configuración actual almacena la contraseña de la base de datos como un Kubernetes Secret y la contraseña de Redis en un ConfigMap. Una auditoría interna reciente marcó ambos como riesgos de cumplimiento.

Esta es la ruta de migración:

  1. Despliega Vault en modo HA (3 nodos) junto al clúster usando Helm. Usa almacenamiento integrado con quórum Raft.
  2. Habilita secretos dinámicos para PostgreSQL. Elimina la variable de entorno estática PGPASSWORD. El Vault Agent Injector escribe un archivo de credenciales nuevo cada 55 minutos (antes de que expire el TTL de 1 hora).
  3. Almacena la contraseña de Redis en Vault KV v2 en secret/data/production/redis. El Agent Injector la inyecta como /vault/secrets/redis.env que el script de entrada de la aplicación consume.
  4. Habilita PKI para el TLS interno entre la API y la base de datos. Los certificados rotan cada 24 horas de forma automática.
  5. Configura el registro de auditoría para escribir en un destino syslog reenviado a tu SIEM. Cada acceso a secretos queda registrado con la identidad del cliente, la IP de origen y la marca de tiempo.
  6. Integra con Terraform usando el proveedor de Vault para gestionar políticas y roles como código, con control de versiones en tu repositorio de infraestructura.

Resultado: ningún secreto en el etcd de Kubernetes, sin credenciales estáticas, pista de auditoría completa y rotación automática — todo sin modificar una sola línea del código de la aplicación.

Errores Comunes y Casos Especiales

Sellado tras reinicio. Vault se sella a sí mismo en cada reinicio del proceso. Necesitas un mecanismo de desellado automático en producción. Las opciones son el propio Auto Unseal de HashiCorp (usando AWS KMS, GCP Cloud KMS o Azure Key Vault como fuente de clave) o la integración con un Vault HSM. Planifica esto antes de desplegar en producción.

Explosión de arrendamientos. Si generas secretos dinámicos para miles de trabajos de CI de corta duración y nunca los revokas explícitamente, el almacén de arrendamientos de Vault crece sin límite y eventualmente degrada el rendimiento. Siempre llama a vault lease revoke al final de un trabajo, o usa Vault Agent, que gestiona la renovación y revocación automáticamente.

El token raíz debe revocarse. El token raíz generado durante vault operator init tiene acceso irrestricto. Tras la configuración inicial, genera un token raíz de tiempo limitado para uso de emergencia y revoca el original: vault token revoke <root-token>.

Rendimiento del backend de almacenamiento. El almacenamiento integrado (Raft) funciona bien para la mayoría de las cargas de trabajo, pero es sensible a la latencia de E/S del disco. En VMs en la nube, usa volúmenes respaldados por SSD. Evita NFS o almacenamiento conectado en red para el directorio de datos de Raft.

Confusión con los espacios de nombres. Los espacios de nombres de Vault Enterprise son unidades de aislamiento lógico (como instancias de Vault separadas). Vault Community Edition no tiene espacios de nombres. Si pruebas con Enterprise y despliegas Community, las rutas que funcionaban antes no existirán.

Desfase de reloj. Varios métodos de autenticación (AWS IAM, Kubernetes, JWT) validan tokens firmados con marca de tiempo. Si los relojes del servidor se desvían más de unos pocos segundos, la autenticación falla silenciosamente. Asegúrate de que NTP está configurado en todos los nodos de Vault.

Solución de Problemas

“Error initializing: Post https://127.0.0.1:8200/v1/sys/init: x509: certificate signed by unknown authority” Establece VAULT_SKIP_VERIFY=true solo para pruebas, o añade tu certificado de CA al almacén de confianza del sistema y establece VAULT_CACERT=/ruta/a/ca.crt.

“Error making API request: Code: 503. Errors: Vault is sealed.” Vault se ha reiniciado y está esperando las claves de desellado. Ejecuta vault operator unseal con el número requerido de fragmentos de clave, o verifica tu configuración de Auto Unseal.

Vault Agent falla al autenticarse en Kubernetes con “permission denied” Verifica que el nombre del ServiceAccount del pod y el espacio de nombres coincidan exactamente con bound_service_account_names y bound_service_account_namespaces en el rol de Kubernetes de Vault. Verifica también que la política de Vault concede acceso a las rutas solicitadas.

“context deadline exceeded” cuando Vault lee de la base de datos El plugin de base de datos no puede alcanzar el host de la base de datos. Comprueba la connection_url en database/config/<nombre>, verifica la conectividad de red y las reglas del cortafuegos entre Vault y la base de datos, y asegúrate de que el superusuario de Vault tiene privilegios de CREATEROLE.

Los secretos no se actualizan en un pod en ejecución tras la renovación del Vault Agent Por defecto, Vault Agent renderiza las plantillas en archivos. La aplicación debe vigilar el archivo en busca de cambios o reiniciarse para recoger las nuevas credenciales. Usa el bloque command en la estanza de plantilla del Vault Agent para lanzar una señal kill -HUP o similar.

Resumen

  • HashiCorp Vault es el estándar de la industria para la gestión de secretos auditable y neutral en cuanto a proveedor, tanto en entornos en la nube como en instalaciones locales.
  • El motor KV v2 gestiona secretos estáticos; los motores Database y PKI generan credenciales dinámicas de corta duración y certificados que se revocan automáticamente.
  • Vault Agent desacopla tu aplicación de la API de Vault — se encarga de la autenticación, la obtención de secretos, el renderizado de plantillas, la renovación y la revocación.
  • La integración con Kubernetes mediante el Agent Injector o Vault Secrets Operator elimina los Kubernetes Secrets estáticos y la exposición en etcd.
  • Cada operación a través de Vault queda capturada en registros de auditoría, proporcionando un registro completo a prueba de manipulaciones para el cumplimiento normativo.
  • Planifica el Auto Unseal desde el primer día para evitar interrupciones operativas cuando los nodos de Vault se reinicien.
  • Los secretos dinámicos reducen drásticamente el radio de impacto de una filtración de credenciales — una credencial de base de datos válida durante una hora es mucho menos peligrosa que una contraseña vigente durante tres años.

Artículos Relacionados