Docker: OpenBao - para qué sirve y cómo instalarlo

Logotipo de OpenBao, gestor de secretos de código abierto

OpenBao es un gestor de secretos y cifrado de código abierto: un único sitio seguro donde guardar contraseñas, claves de API, tokens y certificados en lugar de tenerlos repartidos por archivos de configuración y código. Nació como fork comunitario de HashiCorp Vault y hoy lo gobierna la Linux Foundation Edge, así que es una alternativa totalmente libre y sin licencias de pago. La imagen oficial openbao/openbao está en Docker Hub y permite tenerlo funcionando en un servidor o NAS en unos minutos.

¿Para qué sirve?

  • Centralizar secretos (contraseñas, tokens, claves de API, certificados) en un almacén cifrado y dejar de tenerlos en archivos .env o en el código.
  • Controlar quién accede a cada secreto mediante tokens y políticas, con registro de auditoría de cada acceso.
  • Cifrar datos y generar credenciales temporales para bases de datos y servicios en la nube.

Instalación con docker run

Para una prueba rápida, el contenedor arranca en modo desarrollo si no le pasas nada más. Este comando crea una instancia ya inicializada y desbloqueada con el token raíz que tú elijas:

docker run -d \
  --name openbao-dev \
  -p 8200:8200 \
  -e BAO_DEV_ROOT_TOKEN_ID=mi-token-de-pruebas \
  --restart unless-stopped \
  openbao/openbao:latest

Importante: el modo desarrollo guarda todo en memoria, arranca ya desbloqueado y no es seguro. Los datos desaparecen al parar el contenedor. Según la documentación oficial, nunca debes usarlo para secretos reales ni en producción; sirve solo para trastear en local.

Para un uso en serio (modo servidor con datos persistentes) necesitas un archivo de configuración, que veremos en la sección de Docker Compose, y lanzarías el contenedor así:

docker run -d \
  --name openbao \
  -p 8200:8200 \
  --cap-add IPC_LOCK \
  --memory-swappiness=0 \
  -v /path/to/openbao/config:/openbao/config \
  -v /path/to/openbao/data:/openbao/file \
  -v /path/to/openbao/logs:/openbao/logs \
  --restart unless-stopped \
  openbao/openbao:latest server

Instalación con Docker Compose

Esta es la forma más cómoda de mantenerlo. Primero crea la estructura de carpetas y el archivo de configuración config.hcl dentro de una carpeta config:

mkdir -p openbao/{config,data,logs}
cd openbao
nano config/config.hcl

Contenido de config/config.hcl:

ui = true

storage "file" {
  path = "/openbao/file"
}

listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_disable = true
}

Y este es el docker-compose.yml. Guárdalo en la misma carpeta y levanta el servicio con docker compose up -d:

services:
  openbao:
    image: openbao/openbao:latest
    container_name: openbao
    restart: unless-stopped
    ports:
      - "8200:8200"
    environment:
      - BAO_ADDR=http://127.0.0.1:8200
    volumes:
      - ./config:/openbao/config
      - ./data:/openbao/file
      - ./logs:/openbao/logs
    cap_add:
      - IPC_LOCK
    mem_swappiness: 0
    command: server

La opción IPC_LOCK permite a OpenBao bloquear la memoria para que las claves no pasen al swap del disco, y mem_swappiness: 0 refuerza esa protección, tal como recomienda la documentación oficial de seguridad.

Inicialización y claves unseal (lo más importante)

La primera vez que arrancas el modo servidor, OpenBao está precintado (sealed) y hay que inicializarlo:

docker exec -it openbao bao operator init

Este comando devuelve 5 claves de desbloqueo (unseal keys) y un token raíz (Initial Root Token). Apúntalos en un gestor de contraseñas, porque se muestran una sola vez:

  • Cada vez que el contenedor se reinicie tendrás que desbloquearlo con 3 de las 5 claves: ejecuta docker exec -it openbao bao operator unseal tres veces, introduciendo una clave distinta cada vez.
  • Si pierdes las claves de desbloqueo, pierdes todos los secretos guardados: son irrecuperables. No las guardes en el mismo servidor donde corre OpenBao.
  • El token raíz da control total sobre OpenBao. Úsalo solo para la configuración inicial, crea tokens con permisos limitados para el día a día y rota el raíz.

Después entra con docker exec -it openbao bao login (pegando el token raíz) o abre la interfaz web en http://TU-IP:8200. Ten en cuenta que tls_disable = true solo vale para pruebas en tu red local: si vas a exponer el servicio fuera, configura HTTPS con un certificado.

Lo más útil del README oficial

  • Si lanzas la imagen sin argumentos, arranca en modo desarrollo, equivalente a bao server -dev -dev-root-token-id root.
  • Las variables BAO_DEV_ROOT_TOKEN_ID y BAO_DEV_LISTEN_ADDRESS controlan el token y la dirección de escucha en modo desarrollo.
  • El contenedor lee la configuración de /openbao/config y usa los volúmenes /openbao/file para los datos y /openbao/logs para los registros de auditoría.
  • Además de Docker Hub, las imágenes oficiales están en ghcr.io/openbao/openbao y quay.io/openbao/openbao. La imagen normal está basada en Alpine Linux y existe una variante openbao-ubi basada en Red Hat UBI.

Tu primer secreto

Con OpenBao desbloqueado y la sesión iniciada, crea un almacén de secretos y guarda el primero:

docker exec -it openbao bao secrets enable -path=secret kv-v2
docker exec -it openbao bao kv put secret/mi-app usuario=demo password=secreto123
docker exec -it openbao bao kv get secret/mi-app

Antes de empezar con OpenBao

Necesitas un equipo con Docker instalado y funcionando. Comprueba la versión con docker --version y la de Compose con docker compose version. Si tu usuario no está en el grupo docker, tendrás que anteponer sudo a los comandos. Mira también que el puerto 8200 esté libre con ss -tulpn | grep 8200: si otro servicio lo usa, el contenedor no arrancará y tendrás que elegir otro puerto en la parte izquierda de la asignación.

Cómo comprobar que OpenBao funciona

Después de arrancar el contenedor, ejecuta docker ps y busca openbao con estado Up. Si aparece reiniciándose, lee el motivo con docker logs -f openbao; casi siempre es una ruta mal escrita o un permiso. El comando docker exec -it openbao bao status te dirá si está inicializado y si sigue precintado (Sealed: true) a la espera de las claves de desbloqueo. Dale unos segundos en el primer arranque antes de abrir la interfaz web.

Dónde se guardan los datos

En el ejemplo se montan estas rutas: ./config:/openbao/config, ./data:/openbao/file y ./logs:/openbao/logs. La parte de la izquierda es la carpeta de tu equipo y la de la derecha es la ruta dentro del contenedor. Todo lo que quieras conservar debe estar en una carpeta montada, porque lo que queda dentro del contenedor se pierde si lo eliminas. Crea las carpetas antes de arrancar, con el usuario que vaya a usarlas, para evitar errores de permisos.

Cómo actualizar OpenBao

Para actualizar con Compose, ve a la carpeta del docker-compose.yml y ejecuta docker compose pull seguido de docker compose up -d. Docker descarga la imagen nueva y recrea el contenedor sin tocar tus carpetas montadas. Recuerda que tras el reinicio OpenBao vuelve a quedar precintado y tendrás que desbloquearlo otra vez con 3 de las 5 claves. Después puedes limpiar imágenes viejas con docker image prune.

Guía completa: cómo funciona OpenBao por dentro

Para sacarle partido de verdad conviene entender cuatro piezas: el sellado, los motores de secretos, los tokens y las políticas.

El sellado (seal) y el desbloqueo (unseal)

Todo lo que guarda OpenBao está cifrado con una clave de cifrado que vive junto a los datos. Esa clave está cifrada a su vez con la clave raíz, y la clave raíz está cifrada con la clave de desbloqueo. Mientras el servidor está sellado no sabe descifrar nada: no se puede iniciar sesión ni leer secretos, solo consultar el estado y desbloquear. Por eso el arranque siempre pasa por el unseal que vimos en la sección de inicialización.

  • Shamir: la clave de desbloqueo no se entrega entera a una sola persona: se trocea con el algoritmo de Shamir (por defecto 5 partes y hacen falta 3). Cada parte puede estar en una máquina distinta, y se introducen una a una hasta llegar al umbral.
  • Cada nodo se desbloquea por separado: si montas varios servidores, hay que hacer el unseal en cada uno; no se reparte entre ellos.
  • Sellar a propósito: un operador con privilegios de raíz puede ejecutar bao operator seal para tirar la clave raíz de memoria y bloquear el acceso al instante, por ejemplo si detectas una intrusión.
  • Auto-unseal: en producción se puede delegar el desbloqueo en un servicio de confianza (un KMS en la nube, un HSM, etc.). En ese caso la inicialización devuelve claves de recuperación en lugar de claves unseal. Ojo: si ese servicio desaparece, el clúster no se puede recuperar, ni siquiera desde copias de seguridad.

Motores de secretos (secrets engines)

Los motores de secretos son los componentes que guardan, generan o cifran datos. Cada uno se activa en una ruta, y todo lo que cuelga de esa ruta lo gestiona ese motor, como si fuera un sistema de archivos. El que usamos en "Tu primer secreto" es kv-v2 (parejas clave-valor), pero hay muchos más: pki para emitir certificados, transit para cifrado como servicio, database para credenciales dinámicas de bases de datos (lo veremos abajo), TOTP, y más.

docker exec -it openbao bao secrets enable -path=secret kv-v2
docker exec -it openbao bao secrets list

Cosas a tener en cuenta según la documentación oficial:

  • Las rutas distinguen mayúsculas y minúsculas: kv/ y KV/ son dos motores distintos.
  • Desactivar un motor (bao secrets disable) revoca sus secretos y borra todos sus datos.
  • Cada motor está aislado del resto: ni un motor malicioso puede leer los datos de otro.

Tokens

El token es la forma central de autenticarse en OpenBao: todo acaba convirtiéndose en un token, incluso cuando inicias sesión con usuario y contraseña de LDAP. Cada token lleva asociadas una o varias políticas (qué puede hacer), una caducidad y metadatos que quedan en el registro de auditoría. Por el prefijo sabes de qué tipo es: s. para los de servicio, b. para los batch (ligeros, para trabajos masivos) y r. para los de recuperación.

  • Los tokens forman un árbol: si revocas un token padre, todos sus hijos y sus credenciales asociadas mueren con él.
  • El token raíz lo puede todo y es el único que puede no caducar. La recomendación oficial es usarlo solo para la configuración inicial, revocarlo después y, si algún día hace falta otro, generarlo al momento con bao operator generate-root (que exige el visto bueno de los poseedores de las claves unseal).
  • Cada token tiene un accessor, una referencia que permite consultarlo, renovarlo o revocarlo sin conocer el token en sí.

Políticas

Las políticas definen qué rutas puede tocar cada token y con qué permisos (create, read, update, delete, list...). Por defecto todo está denegado. Se escriben en HCL y se asignan a tokens o a usuarios de un método de autenticación. Ejemplo: una política de solo lectura sobre los secretos de una aplicación:

path "secret/data/mi-app/*" {
  capabilities = ["read", "list"]
}

Se guarda y se aplica a un token nuevo así:

docker exec -it openbao bao policy write app-solo-lectura /openbao/config/app.hcl
docker exec -it openbao bao token create -policy=app-solo-lectura

(El archivo app.hcl hay que dejarlo en la carpeta ./config para que el contenedor lo vea.)

La interfaz web (UI): qué permite y cómo asegurarla

OpenBao trae una interfaz web completa: permite desbloquear el servidor, iniciar sesión, crear, leer, editar y borrar secretos, activar motores y gestionar políticas sin tocar la terminal. No viene activada por defecto; en esta guía ya la activamos con la línea ui = true del config.hcl.

  • Se sirve en el mismo puerto que la API: con el compose de esta guía la tienes en http://TU-IP:8200/ui/.
  • Como escucha en 0.0.0.0, cualquier equipo de tu red puede abrirla. Si solo la vas a usar desde el propio servidor, cambia el listener a address = "127.0.0.1:8200" y no saldrá de la máquina.
  • Si activas TLS (recomendado), el certificado tiene que ser válido para la IP o el nombre DNS que uses para entrar; con un certificado autofirmado tendrás que instalar la CA raíz en cada navegador o verás el aviso de "sitio no seguro".
  • No la expongas a Internet con tls_disable = true: cualquiera podría intentar entrar y tus claves viajarían sin cifrar.

Rotación de credenciales y secretos dinámicos

Aquí es donde OpenBao brilla frente a un simple almacén de contraseñas: en lugar de guardar credenciales fijas, puede generarlas al momento y revocarlas solas cuando caducan. El ejemplo estrella es el motor de bases de datos (funciona con PostgreSQL, MySQL/MariaDB, Cassandra, InfluxDB y Valkey, entre otras).

La idea: creas en tu base de datos un usuario exclusivo para OpenBao, y a partir de ahí cada servicio que necesite acceso recibe un usuario y contraseña únicos y temporales. Si algo raro aparece en los registros de la base de datos, sabes exactamente qué servicio lo hizo, y al caducar el "lease" la credencial se revoca automáticamente.

docker exec -it openbao bao secrets enable database

docker exec -it openbao bao write database/config/mi-postgres \
  plugin_name="postgresql-database-plugin" \
  allowed_roles="lectura-app" \
  connection_url="postgresql://{{username}}:{{password}}@IP-DE-LA-BBDD:5432/midb" \
  username="openbao" \
  password="contraseña-del-usuario-openbao" \
  password_authentication="scram-sha-256"

docker exec -it openbao bao write -force database/rotate-root/mi-postgres

docker exec -it openbao bao write database/roles/lectura-app \
  db_name="mi-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"

A partir de ahí, cualquier servicio con permiso pide sus credenciales y recibe unas recién creadas que caducan en 1 hora:

docker exec -it openbao bao read database/creds/lectura-app
  • Rotación del usuario raíz: el comando rotate-root cambia la contraseña del usuario que OpenBao usa contra la base de datos, de modo que esa contraseña deja de ser conocida por nadie fuera de OpenBao. Hazlo justo después de configurar la conexión.
  • Roles estáticos: para usuarios ya existentes en la base de datos, OpenBao también puede guardar y rotar su contraseña automáticamente cada cierto tiempo. No uses un rol estático sobre el mismo usuario raíz que pusiste en database/config/: al rotarlo, OpenBao dejaría de poder gestionar el resto de usuarios.
  • Rotar las claves unseal: también se pueden cambiar (o cambiar cuántas partes y qué umbral hacen falta) con docker exec -it openbao bao operator rotate-keys, una operación que autorizan los poseedores de las claves actuales.

Integración con Active Directory / LDAP

Si tu organización usa Active Directory o un servidor LDAP, no hace falta crear usuarios a mano: el método de autenticación ldap permite entrar con las credenciales del dominio, y los grupos del directorio se mapean a políticas de OpenBao. En la documentación aparece listado como plugin incorporado (ldap auth ... +builtin.bao), así que funciona sin instalar nada extra.

docker exec -it openbao bao auth enable ldap

docker exec -it openbao bao write auth/ldap/config \
  url="ldaps://dc.tudominio.local:636" \
  userattr="sAMAccountName" \
  userdn="ou=Usuarios,dc=tudominio,dc=local" \
  groupdn="ou=Grupos,dc=tudominio,dc=local" \
  groupfilter="(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={{.UserDN}}))" \
  binddn="cn=openbao,ou=Servicios,dc=tudominio,dc=local" \
  bindpass="contraseña-de-la-cuenta-de-servicio" \
  certificate=@ca-del-dominio.pem \
  insecure_tls=false

docker exec -it openbao bao write auth/ldap/groups/Administradores policies="admin"

docker exec -it openbao bao login -method=ldap username=tu-usuario
  • userattr="sAMAccountName" y la resolución de grupos por memberOf o por el filtro 1.2.840.113556.1.4.1941 (grupos anidados) son lo típico en Active Directory; en LDAP estándar suele bastar el filtro de grupos por defecto.
  • Con upndomain="tudominio.local" los usuarios también pueden entrar con el formato usuario@tudominio.local (UPN).
  • Usa ldaps:// o starttls=true con el certificado de tu CA: la contraseña del dominio viaja en cada login. La opción deny_null_bind viene activada por defecto e impide entrar con contraseña vacía.
  • El archivo ca-del-dominio.pem debe estar accesible dentro del contenedor (por ejemplo en la carpeta ./config, referenciada como @/openbao/config/ca-del-dominio.pem).

Auditoría: quién tocó qué y cuándo

OpenBao puede registrar cada petición y cada respuesta que recibe la API (casi todo lo que pasa en OpenBao es una llamada a la API). Cada línea del registro es un JSON, y los valores sensibles se guardan mezclados con HMAC-SHA256: no se ven en claro, pero puedes comprobar si un valor concreto aparece. Para activarlo:

docker exec -it openbao bao audit enable file file_path=/openbao/logs/audit.log
  • El archivo queda en tu carpeta ./logs gracias al volumen del compose.
  • Desde la versión 2.3.2 hay que añadir unsafe_allow_api_audit_creation = true al config.hcl para poder activar dispositivos de auditoría por API o CLI; si el comando te da error, es por eso.
  • La documentación recomienda activar varios dispositivos de auditoría: si OpenBao no consigue escribir en ninguno, deja de responder peticiones a propósito (prefiere pararse antes que trabajar sin registrar).

Copias de seguridad

Los datos en el backend de almacenamiento ya están cifrados, pero una copia sigue siendo imprescindible:

  • Con el backend file de esta guía: para el contenedor (docker compose stop) y copia las carpetas ./data, ./config y ./logs. La documentación recomienda copias con el servicio parado cuando el backend no admite snapshots atómicos, como es el caso.
  • Haz copia antes de cada actualización y antes de cambios grandes: no siempre se puede volver a una versión anterior con los mismos datos.
  • Las claves unseal no están en la copia ni se pueden reconstruir: guárdalas aparte, en otro sitio seguro.
  • Si usas Integrated Storage (raft) hay snapshots atómicos en caliente: bao operator raft snapshot save copia.snap.
  • Copias y alta disponibilidad se complementan: la HA protege contra la caída de un servidor; la copia, contra el desastre total o un borrado accidental.

Alta disponibilidad y TLS para producción

Para algo más que un uso casero, los dos siguientes pasos naturales son:

  • Alta disponibilidad (HA): varios servidores OpenBao sobre un almacenamiento compartido. Uno coge el bloqueo y actúa como activo; los demás quedan en espera y reenvían las peticiones. El backend recomendado es Integrated Storage (raft), que viene integrado y no necesita servicios extra. Ojo: la HA da tolerancia a caídas, no más velocidad, y exige configurar api_addr y cluster_addr.
  • TLS: cambia el listener por algo así y monta una carpeta con tus certificados:
listener "tcp" {
  address         = "0.0.0.0:8200"
  tls_cert_file   = "/openbao/certs/servidor.pem"
  tls_key_file    = "/openbao/certs/servidor.key"
  tls_min_version = "tls12"
}

Con eso la API y la interfaz web pasan a https://. OpenBao recarga el certificado con SIGHUP, o automáticamente si activas tls_auto_reload = true (útil si un gestor de certificados los renueva solo).

Fuentes: documentación oficial de OpenBao · README en Docker Hub · Seal/Unseal · Policies · Tokens · Secrets engines · OpenBao UI · Database secrets · LDAP auth · Audit devices · High Availability · Storage y backups

Comentarios

Entradas populares de este blog

Cómo instalar Hermes Agent en Docker y conectarlo con tu suscripción de Antigravity

Cómo funciona Docker Compose