Instalación y Configuración de HashiCorp Vault

HashiCorp Vault es la solución de referencia para gestión centralizada de secretos, permitiendo almacenar, generar y controlar el acceso a tokens, contraseñas, certificados y claves de cifrado con un registro de auditoría completo. Su modelo de políticas granulares y los múltiples métodos de autenticación lo hacen adecuado tanto para entornos pequeños como para grandes infraestructuras multi-tenant. Esta guía cubre la instalación de Vault en Linux, inicialización, motores de secretos y configuración de alta disponibilidad.

Requisitos Previos

  • Servidor Linux (Ubuntu 22.04/Debian 12 o CentOS 9/Rocky 9)
  • Mínimo 2 GB de RAM (4 GB para producción)
  • Almacenamiento persistente (disco SSD recomendado para Raft)
  • Certificado TLS válido para el dominio de Vault
  • Para HA: 3 nodos mínimo

Instalación de Vault

# Añadir repositorio HashiCorp (Ubuntu/Debian)
wget -O- https://apt.releases.hashicorp.com/gpg | \
  gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg

echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
  https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
  tee /etc/apt/sources.list.d/hashicorp.list

apt-get update && apt-get install -y vault

# CentOS/Rocky Linux
dnf config-manager --add-repo \
  https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
dnf install -y vault

# Verificar la instalación
vault version

# Crear directorios de datos y configuración
mkdir -p /opt/vault/data /etc/vault.d /var/log/vault
useradd -r -d /opt/vault -s /bin/false vault
chown vault:vault /opt/vault/data /var/log/vault
chmod 700 /opt/vault/data

Configuración de Almacenamiento

Vault soporta múltiples backends de almacenamiento. Para producción se recomienda Raft integrado:

cat > /etc/vault.d/vault.hcl << 'EOF'
# Dirección de escucha con TLS
ui = true

listener "tcp" {
    address       = "0.0.0.0:8200"
    tls_cert_file = "/etc/vault.d/tls/vault.crt"
    tls_key_file  = "/etc/vault.d/tls/vault.key"
    tls_min_version = "tls12"
}

# Backend de almacenamiento Raft integrado (recomendado para HA)
storage "raft" {
    path    = "/opt/vault/data"
    node_id = "vault-01"  # Único por nodo
}

# URL de la API (debe coincidir con el nombre del certificado TLS)
api_addr     = "https://vault.tudominio.com:8200"
cluster_addr = "https://10.0.1.10:8201"

# Desactivar la memoria de secretos en swap
disable_mlock = false

# Logging
log_level = "info"
log_file  = "/var/log/vault/vault.log"

# Telemetría Prometheus
telemetry {
    prometheus_retention_time = "30s"
    disable_hostname          = true
}
EOF

# Generar certificado TLS auto-firmado para pruebas
mkdir -p /etc/vault.d/tls
openssl req -x509 -nodes -newkey rsa:4096 -keyout /etc/vault.d/tls/vault.key \
  -out /etc/vault.d/tls/vault.crt -days 365 \
  -subj "/CN=vault.tudominio.com" \
  -addext "subjectAltName=DNS:vault.tudominio.com,IP:10.0.1.10"

chown vault:vault /etc/vault.d/tls/vault.key
chmod 600 /etc/vault.d/tls/vault.key

Crea el servicio systemd:

cat > /etc/systemd/system/vault.service << 'EOF'
[Unit]
Description=HashiCorp Vault - Secrets Management
Documentation=https://www.vaultproject.io/docs/
Requires=network-online.target
After=network-online.target
ConditionFileNotEmpty=/etc/vault.d/vault.hcl
StartLimitIntervalSec=60
StartLimitBurst=3

[Service]
Type=notify
User=vault
Group=vault
ProtectSystem=full
ProtectHome=read-only
PrivateTmp=yes
PrivateDevices=yes
SecureBits=keep-caps
AmbientCapabilities=CAP_IPC_LOCK
CapabilityBoundingSet=CAP_SYSLOG CAP_IPC_LOCK
NoNewPrivileges=yes
ExecStart=/usr/bin/vault server -config=/etc/vault.d/vault.hcl
ExecReload=/bin/kill --signal HUP $MAINPID
KillMode=process
KillSignal=SIGINT
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
LimitNOFILE=65536
LimitMEMLOCK=infinity

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now vault

Inicialización y Unseal

La inicialización de Vault genera las claves para el proceso de unseal y el token raíz:

# Configurar la variable de entorno de la dirección de Vault
export VAULT_ADDR="https://vault.tudominio.com:8200"
export VAULT_CACERT="/etc/vault.d/tls/vault.crt"

# Inicializar Vault (SOLO UNA VEZ en el primer nodo)
# -key-shares: número de fragmentos de la clave maestra
# -key-threshold: mínimo de fragmentos necesarios para unseal
vault operator init -key-shares=5 -key-threshold=3

# CRÍTICO: Guarda las 5 Unseal Keys y el Initial Root Token en un lugar seguro
# (gestión de claves fuera de banda: USB cifrado, HSM, o Vault Enterprise Auto-Unseal)

# Proceso de unseal (necesita 3 de las 5 claves)
vault operator unseal  # Introducir Unseal Key 1
vault operator unseal  # Introducir Unseal Key 2
vault operator unseal  # Introducir Unseal Key 3

# Verificar el estado de Vault
vault status

# Autenticarse con el root token (solo para configuración inicial)
vault login  # Introducir el Initial Root Token

# Crear un token de administrador con políticas en lugar de usar root
vault token create -policy="admin" -ttl=8h

Motores de Secretos

Vault organiza los secretos en "motores" montados en rutas:

# Motor KV versión 2 (secretos estáticos con historial de versiones)
vault secrets enable -path=secret kv-v2

# Guardar y leer secretos
vault kv put secret/webapp/database \
  url="postgresql://db:5432/webapp" \
  username="webapp_user" \
  password="$(openssl rand -base64 32)"

vault kv get secret/webapp/database
vault kv get -field=password secret/webapp/database

# Ver versiones anteriores
vault kv history secret/webapp/database
vault kv get -version=1 secret/webapp/database

# Motor de credenciales dinámicas para bases de datos
vault secrets enable database

# Configurar conexión a PostgreSQL
vault write database/config/webapp-postgres \
  plugin_name=postgresql-database-plugin \
  allowed_roles="webapp-readonly,webapp-readwrite" \
  connection_url="postgresql://{{username}}:{{password}}@10.0.3.10:5432/webapp" \
  username="vault_admin" \
  password="password_vault_admin"

# Crear rol con privilegios limitados
vault write database/roles/webapp-readonly \
  db_name=webapp-postgres \
  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"

# Generar credenciales temporales
vault read database/creds/webapp-readonly
# Las credenciales expiran automáticamente tras 1 hora

# Motor PKI para emisión de certificados TLS
vault secrets enable pki
vault secrets tune -max-lease-ttl=87600h pki

vault write pki/root/generate/internal \
  common_name="Empresa CA" \
  ttl=87600h

vault write pki/roles/servidor \
  allowed_domains="empresa.local" \
  allow_subdomains=true \
  max_ttl=720h

# Emitir un certificado
vault write pki/issue/servidor \
  common_name="web.empresa.local"

Métodos de Autenticación

# Autenticación con AppRole (para aplicaciones y automatización)
vault auth enable approle

vault write auth/approle/role/webapp \
  secret_id_ttl=24h \
  token_num_uses=0 \
  token_ttl=1h \
  token_max_ttl=4h \
  policies="webapp-policy"

# Obtener el Role ID y Secret ID para la aplicación
vault read auth/approle/role/webapp/role-id
vault write -f auth/approle/role/webapp/secret-id

# Autenticar con AppRole
vault write auth/approle/login \
  role_id="<role-id>" \
  secret_id="<secret-id>"

# Autenticación con Kubernetes ServiceAccounts
vault auth enable kubernetes
vault write auth/kubernetes/config \
  kubernetes_host="https://10.0.0.1:6443" \
  kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
  token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"

# Autenticación LDAP/AD
vault auth enable ldap
vault write auth/ldap/config \
  url="ldaps://ldap.empresa.local:636" \
  userdn="ou=users,dc=empresa,dc=local" \
  groupdn="ou=groups,dc=empresa,dc=local" \
  binddn="cn=vault-reader,ou=service-accounts,dc=empresa,dc=local" \
  bindpass="password_cuenta_servicio"

Políticas de Acceso

# Crear política para la aplicación webapp
cat > /tmp/webapp-policy.hcl << 'EOF'
# Leer secretos de la aplicación webapp
path "secret/data/webapp/*" {
    capabilities = ["read", "list"]
}

# Generar credenciales dinámicas de base de datos
path "database/creds/webapp-readonly" {
    capabilities = ["read"]
}

# Renovar tokens propios
path "auth/token/renew-self" {
    capabilities = ["update"]
}
EOF

vault policy write webapp-policy /tmp/webapp-policy.hcl

# Política de administración del sistema
cat > /tmp/admin-policy.hcl << 'EOF'
path "*" {
    capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
EOF

vault policy write admin /tmp/admin-policy.hcl

Alta Disponibilidad con Raft

# En el segundo y tercer nodo, después de instalar y configurar vault.hcl
# (ajustar node_id y cluster_addr por nodo)
# Unirse al clúster existente
export VAULT_ADDR="https://10.0.1.11:8200"
vault operator raft join https://vault.tudominio.com:8200

# Hacer unseal del nuevo nodo con 3 de las 5 claves
vault operator unseal
vault operator unseal
vault operator unseal

# Ver los peers del clúster Raft (desde cualquier nodo con el token root o admin)
vault operator raft list-peers

# Ver el estado de HA
vault status | grep -E "HA|Leader"

Solución de Problemas

# Ver logs del servicio
journalctl -u vault -f

# Estado detallado de Vault
vault status

# Verificar si el token actual tiene acceso a una ruta
vault token capabilities secret/data/webapp/database

# Debug de políticas
vault write sys/capabilities-self paths="secret/data/webapp/database"

# Ver el registro de auditoría (activar primero)
vault audit enable file file_path=/var/log/vault/audit.log
tail -f /var/log/vault/audit.log | python3 -m json.tool

# Vault sellado por reinicio del sistema: ejecutar unseal automático con Autounseal
# (configurar con AWS KMS, Azure Key Vault, GCP KMS o Transit engine)
# En vault.hcl:
# seal "awskms" {
#   region     = "us-east-1"
#   kms_key_id = "alias/vault-unseal-key"
# }

Conclusión

HashiCorp Vault transforma la gestión de secretos de un problema disperso y difícil de auditar en un sistema centralizado, con control de acceso granular y registro completo de operaciones. Las credenciales dinámicas con TTL corto y la revocación automática reducen drásticamente la superficie de ataque respecto a secretos estáticos en archivos de configuración, haciendo de Vault una pieza fundamental en cualquier estrategia de seguridad para infraestructuras modernas.