Soy Òscar Mas y en el articulo anterior vimos qué es HashiCorp Vault, sus ventajas y cómo puede ayudar a proteger información sensible dentro de entornos DevOps y cloud. En esta segunda parte realizaremos una instalación práctica de Vault con Docker y veremos un poco el funcionamiento de Vault: la configuración inicial del servicio, los primeros pasos para empezar a almacenar y gestionar secretos de forma segura.
Toda la instalación de Vault se ha realizado en el mismo equipo basado en debian, pero realmente el sistema operativo no es importante, ya que todo se basa en contenedores docker.
Configuración inicial de HashiCorp Vault
Lo primero que necesitamos es pasarle a Vault la configuración para que guarde los datos de forma persistente en el sistema de archivos local (/vault/file). Indicarle que el servicio escuche por el puerto 8200 sin TLS (recuerda que esto es un lab) y habilitar la interfaz gráfica de usuario (UI). La directiva disable_mlock permite que el proceso se ejecute sin privilegios elevados de memoria, ideal para entornos de pruebas o contenedores.
root@vault:~# apt-get update && apt-get install -y jq
root@vault:~# mkdir -p /etc/vault-server/{config,file}
root@vault:~# cat <<EOF >> /etc/vault-server/config/vault.json
{
"disable_mlock": true,
"backend": {
"file": {
"path": "/vault/file"
}
},
"listener": {
"tcp":{
"address": "0.0.0.0:8200",
"tls_disable": 1
}
},
"ui": true
}
EOF
Configuración de Nginx como proxy inverso
Una vez creado el fichero de configuración de Vault, realizaremos la configuración de un servicio de Nginx para colocarlo delante como proxy inverso, para centralizar el acceso a Vault a través del puerto estándar HTTP (80), facilitando la conectividad sin tener que especificar el puerto 8200 manualmente.
root@vault:~# mkdir -p /etc/nginx/conf.d/
root@vault:~# vim /etc/nginx/conf.d/default.conf
upstream vault {
server vault:8200 max_fails=3;
}
server {
listen *:80;
server_name _;
location /healthz {
stub_status;
}
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://vault;
}
}
Despliegue de los contenedores con Docker Compose
Una vez realizadas las configuraciones de Nginx y de Vault, ahora solo nos queda crear los contenedores para que adopten esta configuración:
root@vault:~# cat <<EOF >> /etc/docker-compose/docker-compose.yaml
services:
nginx:
container_name: 'nginx'
hostname: 'nginx'
image: 'nginx:1.25.3-alpine'
depends_on:
- 'vault'
ports:
- '80:80'
volumes:
- '/etc/localtime:/etc/localtime:ro'
- '/etc/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf'
vault:
container_name: vault
hostname: vault
image: hashicorp/vault:1.17.5
restart: always
environment:
VAULT_ADDR: http://localhost:8200
ports:
- "8200:8200"
cap_add:
- 'IPC_LOCK'
volumes:
- /etc/vault-server/config/vault.json:/etc/vault-server/config/vault.json
- /etc/vault-server/file:/vault/file
- /etc/localtime:/etc/localtime:ro
command: "vault server -config=/etc/vault-server/config/vault.json"
EOF
Levantaremos los contenedores y verificaremos que todo esté correcto:
root@vault:~# docker-compose -f /etc/docker-compose/docker-compose.yaml up -d root@vault:~# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d8581e800825 nginx:1.25.3-alpine "/docker-entrypoint.…" 7 seconds ago Up 6 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp nginx fcc757fc5331 hashicorp/vault:1.17.5 "docker-entrypoint.s…" 8 seconds ago Up 7 seconds 0.0.0.0:8200->8200/tcp, :::8200->8200/tcp vault
Inicialización de Vault y generación de claves Unseal
Una vez esté todo levantado, inicializaremos el servidor de Vault, con ello conseguiremos:
- Generar las claves (Unseal Keys) necesarias para abrir Vault. Recordad que cuando el contenedor de Vault se inicia, está cifrado y bloqueado (estado sealed). Nadie puede entrar y no se puede leer ningún secreto. Para poder utilizarlo, debe "desbloquearse" (estado unseal).
- Proporcionar el Root Token. Una vez Vault está abierto (estado unseal), necesitas una forma de acceder para empezar a trabajar. Este Root Token te proporciona acceso a Vault.
root@vault:~# docker exec -it vault vault operator init Unseal Key 1: +Y8HDolAfpm/hwrZ72flgrAfj8aH1QwvlP2vf/2UyjaS Unseal Key 2: 5id1ig/8u+bgN1HnPJQW8TQvyAT+o5vinTQ2/yUrvilA Unseal Key 3: dAMRqHsU491x4bizhrIarYkmeEyqDy42uYGWHPBdlFyZ Unseal Key 4: 0PI8LW7DzkUzxhoeOoYPEcSbbcSdTTufzt2iGMbF5Rdc Unseal Key 5: i6PknfSwlOFukzmNMKKKoSGDjgLp70qhnBt3efJEh0Fs Initial Root Token: hvs.xBV3t49lOCmaDrXrLQqN4AE6
Acceso a Vault por GUI y CLI
A partir de este punto, una vez tenemos Vault inicializado y desbloqueado, disponemos de dos vías principales para acceder y gestionar nuestros secretos:
- Vía interfaz gráfica (GUI): Ideal para una gestión visual e intuitiva. Se accede directamente desde el navegador web, donde podremos introducir nuestro Root Token para curiosear y gestionarlo todo cómodamente.
Vía línea de comandos (CLI): para la cual existen dos alternativas:
- Desde nuestro propio equipo: Instalando el cliente local de Vault y conectándonos remotamente configurando la variable de entorno VAULT_ADDR.
- Desde el propio contenedor de Docker: Ejecutando los comandos directamente desde dentro de la máquina con docker exec, sin necesidad de instalar nada en nuestro ordenador.
Para poder ejecutar comandos directamente desde dentro del contenedor de Vault, primero debemos abrir una terminal dentro del contenedor.
root@vault:~# docker exec -it vault sh
Debéis tener en cuenta que a partir de aquí todos los comandos se lanzarán dentro del contenedor.
Desbloquear Vault con las Unseal Keys
Por defecto, Vault se ha inicializado con un umbral de seguridad de 3 de 5: te ha proporcionado 5 claves, pero solo necesitas 3 de cualquiera de ellas para poder abrirlo. Dentro de la consola del contenedor, ejecuta el comando de desbloqueo tres veces e introduciremos cualquiera de las claves, sin repetir ninguna:
/ # vault operator unseal
/ # vault operator unseal
/ # vault operator unseal
Una vez introducidas las tres claves, validaremos que Vault está desbloqueado (estado unseal)
/ # vault status | grep Sealed Sealed false
Ahora que Vault está desbloqueado (estado unseal), necesitas identificarte como administrador para poder empezar a crear secretos. Para ello, utilizaremos el Root Token que te ha generado previamente el sistema:
/ # vault login hvs.xBV3t49lOCmaDrXrLQqN4AE6
Si el token es correcto, recibirás un mensaje de Success!. A partir de ese momento, ya tienes el control absoluto de Vault desde la línea de comandos del contenedor.
Crear y consultar secretos en Vault
Por defecto, Vault viene completamente vacío. El siguiente comando activa un "motor de secretos" de tipo KV2 (explicado en el post anterior), que sirve para guardar pares de datos (como por ejemplo usuarios y contraseñas).
/ # vault secrets enable -description="Secrets" -version=2 -path=ansible kv
Una vez tenemos activado el "motor de secretos", ya podemos empezar a almacenar nuestros datos de forma segura:
/ # vault kv put ansible/myapp/config username='secret-username' password='secret-password'
Para consultar los datos que acabamos de guardar, utilizaremos el comando get. Además, añadiremos el parámetro -format=json, que nos devolverá la salida en un formato ideal:
/ # vault kv get -format=json ansible/myapp/config
...
"password": "secret-password",
"username": "secret-username"
...
Conclusión
Con esta instalación ya disponemos de un entorno funcional de HashiCorp Vault preparado para empezar a gestionar secretos de forma centralizada y segura. Aunque se trata de un entorno de laboratorio, los conceptos de inicialización, unseal, autenticación y almacenamiento de secretos son los mismos que encontraremos en despliegues de producción.
Espero que este artículo os haya servido de ayuda y, como mínimo, os haya sido útil para avanzar en el mundo de Vault.