OpenBao es la bifurcación de HashiCorp Vault que conserva la licencia MPL 2.0, y con Docker se instala como un contenedor con almacenamiento Raft en un volumen. Esta guía levanta OpenBao 2.6.2 con Docker Compose, lo inicializa, guarda un secreto, da acceso a una aplicación con AppRole y hace copias con snapshots de Raft. También migra una instalación con el backend file, que OpenBao 2.7 ya no arranca. Lo probé todo el 16 de septiembre de 2026 en una máquina arm64 de 18 núcleos con Docker Engine 29.5.2, y cuento los errores que me encontré por el camino.

Puntos clave

  • La imagen openbao/openbao:2.6.2 ocupa 75,2 MB comprimida para arm64, y el contenedor en reposo usó 39,7 MiB de memoria según docker stats.
  • Monta el volumen de Raft en /openbao/file. En una ruta nueva como /openbao/data, el servidor falla con permission denied, porque la imagen se ejecuta con el usuario sin privilegios openbao.
  • La opción --memory-swappiness=0 que recomienda la documentación se descarta en hosts con cgroup v2. Poner memswap_limit igual que mem_limit sí deja el swap del contenedor en 0.
  • OpenBao 2.7.0 elimina el backend file: la beta del 9 de septiembre de 2026 se detiene con unknown storage type file. Migra antes con bao operator migrate.
  • Un snapshot de Raft solo sirve con las claves de desellado originales. Restaurarlo en otro servidor exige -force, un reinicio y las claves del servidor de origen.

Qué es OpenBao y qué relación tiene con HashiCorp Vault

OpenBao es un gestor de secretos con la API de Vault, publicado con licencia MPL 2.0 y gobernado por la Linux Foundation. Nació cuando HashiCorp cambió la licencia de Vault. El 10 de agosto de 2023, Armon Dadgar lo anunció así en el blog de HashiCorp[1]:

"HashiCorp is changing its source code license from Mozilla Public License v2.0 (MPL 2.0) to the Business Source License (BSL, also known as BUSL) v1.1 on all future releases of HashiCorp products."

Los ficheros de licencia del repositorio de Vault[2] marcan la frontera versión a versión. Las etiquetas 1.14.0, 1.14.1, 1.14.2 y 1.14.8 llevan MPL 2.0. La 1.15.0, del 26 de septiembre de 2023, ya lleva BUSL 1.1, y la rama 1.14 cambió a partir de la 1.14.9, del 30 de enero de 2024. La versión actual del fichero nombra a IBM como licenciante y prevé que cada versión pase a MPL 2.0 cuatro años después de publicarse.

OpenBao se bifurcó desde la rama 1.14 con MPL. Según la página de noticias de OpenBao[3], el proyecto arrancó en octubre de 2023 dentro de LF Edge. La 2.0.0 estable salió en julio de 2024, y en junio de 2025 el proyecto pasó a la OpenSSF. Su portada lo resume así: "an open source, community-driven secrets manager and fork of Vault managed by the Linux Foundation’s OpenSSF."

Si buscas un Vault para guardar los secretos de tus servicios en tu propio servidor, las diferencias prácticas están en la tabla siguiente. Los conceptos comunes (motores de secretos, políticas, auditoría) están en el artículo sobre Vault de HashiCorp para gestión de secretos.

Punto OpenBao 2.6.2 Vault
Licencia MPL 2.0 BUSL 1.1 desde la 1.15.0
Binario y variable de dirección bao y BAO_ADDR; acepta VAULT_ADDR vault y VAULT_ADDR
Prefijo de los tokens nuevos s. hvs.
Namespaces Incluidos desde la 2.3.1 (junio de 2025) Solo con licencia Enterprise
Cabecera del token en la API HTTP X-Vault-Token o Authorization: Bearer La misma

Los datos de Vault salen de su licencia, de la documentación de namespaces de Vault[4], de su referencia de la API y de la guía de migración de OpenBao. La imagen de OpenBao incluye además un enlace vault que apunta a bao, así que los scripts que llaman a vault siguen funcionando dentro del contenedor.

Qué necesitas antes de empezar

La instalación ocupa un contenedor y dos volúmenes. Necesitas:

  • Docker Engine con el plugin de Compose (probado con Docker 29.5.2 y Compose v2.40.3)
  • 512 MiB de memoria libres para el contenedor
  • Un lugar fuera del servidor para guardar las claves de desellado, repartidas entre personas o sitios distintos

Si hoy tus contraseñas viven en un fichero .env, lee antes el artículo sobre variables de entorno y secretos en Docker Compose. Explica qué resuelven los secretos de Compose y qué les falta: rotación, auditoría y caducidad, justo lo que añade OpenBao.

Paso 1: escribe la configuración con almacenamiento Raft

OpenBao lee su configuración de /openbao/config dentro del contenedor. Crea un directorio openbao/ con un subdirectorio config/ y guarda esto en config/openbao.hcl:

ui = true

storage "raft" {
  path    = "/openbao/file"
  node_id = "bao-1"
}

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

audit "file" "fichero" {
  options {
    file_path = "/openbao/logs/audit.log"
  }
}

api_addr     = "http://127.0.0.1:8200"
cluster_addr = "http://127.0.0.1:8201"

El bloque storage "raft" activa el almacenamiento integrado: OpenBao escribe sus datos cifrados en su propio disco y los replica con el algoritmo de consenso Raft cuando añades nodos. La documentación del backend Raft[5] exige cluster_addr aunque tengas un solo nodo. El bloque audit declara un registro de auditoría en fichero, y tiene que ir aquí: si intentas crearlo con bao audit enable, OpenBao responde cannot enable audit device via API; use declarative, config-based audit device management instead.

La línea tls_disable = true solo es aceptable porque el paso siguiente limita el puerto a 127.0.0.1. Para servir OpenBao a otras máquinas, cámbiala por tls_cert_file y tls_key_file. Lo probé con un certificado autofirmado y BAO_CACERT apuntando a él: las peticiones HTTPS respondieron 200 y una petición HTTP sin cifrar recibió un 400.

Paso 2: levanta el contenedor con Docker Compose

El fichero de Compose fija la versión, monta la configuración en solo lectura y guarda los datos y la auditoría en volúmenes con nombre. Guárdalo como compose.yaml junto a config/:

services:
  openbao:
    image: openbao/openbao:2.6.2
    command: server
    ports:
      - "127.0.0.1:8200:8200"
    environment:
      BAO_ADDR: "http://127.0.0.1:8200"
    volumes:
      - ./config:/openbao/config:ro
      - bao-datos:/openbao/file
      - bao-logs:/openbao/logs
    mem_limit: 512m
    memswap_limit: 512m
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider",
             "http://127.0.0.1:8200/v1/sys/health"]
      interval: 30s
      timeout: 5s
      retries: 3
    restart: unless-stopped

volumes:
  bao-datos:
  bao-logs:

Cada línea tiene un motivo, y tres de ellos los descubrí al fallar:

  • command: server: sin esta línea la imagen arranca server -dev, un servidor de desarrollo que guarda todo en memoria y lo pierde al parar.
  • bao-datos:/openbao/file: mi primer intento montó el volumen en /openbao/data y el servidor entró en bucle con failed to open bolt file: open /openbao/data/vault.db: permission denied. La imagen corre con el usuario openbao (UID 100), y Docker solo copia ese propietario a un volumen nuevo cuando la ruta ya existe en la imagen, como /openbao/file.
  • bao-logs:/openbao/logs: la 2.6.2 declara esa ruta como volumen anónimo, pero la 2.7.0 elimina todas las instrucciones VOLUME de la imagen, así que sin un volumen con nombre perderías la auditoría al recrear el contenedor.
  • mem_limit y memswap_limit: la guía de instalación de OpenBao[6] pide --memory-swappiness=0 para que los secretos no acaben en el swap. En este host, con cgroup v2, Docker respondió Memory swappiness discarded y memory.swap.max siguió en max; con los dos límites iguales pasó a 0.
  • BAO_ADDR: sin ella, bao apunta a https://127.0.0.1:8200 y falla con server gave HTTP response to HTTPS client.
  • healthcheck: /v1/sys/health devuelve 501 sin inicializar, 503 sellado y 200 en servicio, así que el contenedor aparece como unhealthy si nadie lo ha desellado. Tras un reinicio lo marcó así a los 90 s. El artículo sobre healthchecks y políticas de reinicio en Compose explica cómo encadenar otros servicios a ese estado.

Arranca el servicio y revisa el registro:

docker compose up -d
docker compose logs openbao | grep -v chown

Las líneas chown: /openbao/config: Read-only file system que filtra el grep son inofensivas: el script de entrada intenta cambiar el propietario de la configuración y no puede porque la montaste en solo lectura. Lo que importa es Storage: raft (HA available) y security barrier not initialized. Si quieres entender por qué un volumen con nombre y no un directorio del host, está explicado en volúmenes y bind mounts en Docker.

Paso 3: inicializa y desella OpenBao

Al arrancar, OpenBao está sellado: tiene los datos cifrados y no puede leerlos hasta reconstruir la clave raíz a partir de tres de las cinco claves de desellado, con el esquema de Shamir. La inicialización genera esas claves y el token raíz, y solo se hace una vez:

docker compose exec openbao bao operator init

La salida lista cinco claves y un token. Estos son los valores sustituidos por marcadores, junto al aviso que imprime la 2.6.2 (todavía dice Vault):

Unseal Key 1: clave_de_desellado_1
Unseal Key 2: clave_de_desellado_2
Unseal Key 3: clave_de_desellado_3
Unseal Key 4: clave_de_desellado_4
Unseal Key 5: clave_de_desellado_5

Initial Root Token: token_raiz_inicial

Vault initialized with 5 key shares and a key threshold of 3.
...
Vault does not store the generated root key. Without at least 3 keys
to reconstruct the root key, Vault will remain permanently sealed!

Copia las claves fuera del servidor ahora, porque OpenBao no las vuelve a mostrar. Después desella con tres de ellas y comprueba el estado:

docker compose exec openbao bao operator unseal
docker compose exec openbao bao operator unseal
docker compose exec openbao bao operator unseal
docker compose exec openbao bao status

Cada unseal pide la clave con Unseal Key (will be hidden):, así que no queda en el historial del intérprete. Si intentas pasarla por una tubería, falla con file descriptor 0 is not a terminal. Tras la tercera clave, bao status muestra Sealed false, Storage Type raft y HA Mode active, y sale con código 0; mientras está sellado sale con código 2, algo útil para tus scripts de supervisión.

Para los pasos siguientes necesitas el token raíz en una variable, sin escribirlo en la línea de órdenes:

read -rs BAO_TOKEN && export BAO_TOKEN

Paso 4: guarda el primer secreto en KV v2

El motor KV v2 guarda pares clave y valor con historial de versiones, y es el sitio natural para las credenciales de tus servicios. Actívalo en la ruta secret/ y escribe un secreto; -e BAO_TOKEN pasa la variable de tu terminal al contenedor:

docker compose exec -e BAO_TOKEN openbao \
  bao secrets enable -path=secret kv-v2
read -rs CLAVE_BD
printf '%s' "$CLAVE_BD" | docker compose exec -T -e BAO_TOKEN openbao \
  bao kv put -mount=secret app/db usuario=app password=-
docker compose exec -e BAO_TOKEN openbao \
  bao kv get -mount=secret app/db

Con password=-, bao lee el valor de la entrada estándar, así que la contraseña tampoco queda en el historial.

En una de mis instalaciones, el kv put lanzado justo después de activar el motor falló con Upgrading from non-versioned to versioned data. This backend will be unavailable for a brief period and will resume service shortly. Espera un segundo y repítelo: en el segundo intento funcionó.

Con ui = true, la interfaz web está en http://127.0.0.1:8200/ui/. Allí puedes navegar hasta el secreto, que aparece con los valores ocultos hasta que pulsas el icono del ojo:

Interfaz web de OpenBao 2.6.2 con el secreto app/db del motor KV v2 abierto, versión 1, y los valores de usuario y contraseña ocultos tras puntos.

Paso 5: da acceso a una aplicación con AppRole

AppRole es el método de autenticación pensado para máquinas: la aplicación presenta un role_id y un secret_id y recibe un token con las políticas del rol. Empieza por una política que solo permite leer la ruta de la aplicación, en app-lectura.hcl:

path "secret/data/app/*" {
  capabilities = ["read"]
}

En KV v2 la ruta de lectura lleva el segmento data/, aunque en la línea de órdenes escribas secret/app/db. Carga la política, activa AppRole, crea el rol y extrae sus dos identificadores a ficheros:

B="docker compose exec -T -e BAO_TOKEN openbao bao"
$B policy write app-lectura - < app-lectura.hcl
$B auth enable approle
$B write auth/approle/role/mi-app token_policies=app-lectura \
  token_ttl=1h token_max_ttl=4h secret_id_ttl=24h
$B read -field=role_id auth/approle/role/mi-app/role-id > role_id
$B write -f -field=secret_id \
  auth/approle/role/mi-app/secret-id > secret_id

Con -field, los dos ficheros contienen el identificador de 36 caracteres sin salto de línea final. El token que obtiene la aplicación dura 1 hora, renovable hasta 4, y después tiene que volver a iniciar sesión. Como el secret_id caduca a las 24 horas, tu proceso de despliegue debe entregar uno nuevo antes; con secret_id_ttl=0 no caduca, y entonces tienes que protegerlo como una contraseña.

La aplicación recibe los dos ficheros como secretos de Compose, que aparecen en /run/secrets/. Guarda este servicio en app.yaml:

services:
  app:
    image: alpine:3
    command: sh -c "apk add -q curl jq && /leer-secreto.sh"
    volumes:
      - ./leer-secreto.sh:/leer-secreto.sh:ro
    secrets:
      - role_id
      - secret_id
    depends_on:
      openbao:
        condition: service_healthy

secrets:
  role_id:
    file: ./role_id
  secret_id:
    file: ./secret_id

El script leer-secreto.sh inicia sesión por la API HTTP y lee la contraseña. Es el mismo intercambio que haría tu aplicación con su biblioteca cliente:

#!/bin/sh
set -eu
BAO=http://openbao:8200
LOGIN=$(jq -n --rawfile r /run/secrets/role_id \
  --rawfile s /run/secrets/secret_id '{role_id: $r, secret_id: $s}')
TOKEN=$(curl -sf -X POST -d "$LOGIN" "$BAO/v1/auth/approle/login" \
  | jq -r .auth.client_token)
curl -sf -H "X-Vault-Token: $TOKEN" "$BAO/v1/secret/data/app/db" \
  | jq -r .data.data.password

Con docker compose -f compose.yaml -f app.yaml run --rm app, el script imprimió la contraseña de prueba. Con ese mismo token, leer secret/data/otra/cosa devolvió 403 y escribir en secret/data/app/db también, que es justo lo que pide la política.

Qué hacer con el token raíz cuando termines

El token raíz no caduca y lo puede todo, así que no debe quedarse circulando. Antes de revocarlo, ten otra vía para regenerarlo: en la 2.6.2, bao operator generate-root usa los endpoints autenticados sys/generate-root-token, y los antiguos sin autenticar están desactivados por defecto desde la 2.5.3. Lo comprobé: tras revocar el único token raíz, bao operator generate-root -init respondió 403 permission denied.

La salida es una identidad de rescate con una política que solo cubre esa ruta. Guárdala como rescate-raiz.hcl:

path "sys/generate-root-token/*" {
  capabilities = ["create", "read", "update", "delete", "sudo"]
}

Cárgala y asígnala a un usuario del método userpass, con la variable B del paso anterior:

$B policy write rescate-raiz - < rescate-raiz.hcl
$B auth enable userpass
read -rs CLAVE_RESCATE
printf '%s' "$CLAVE_RESCATE" | $B write auth/userpass/users/rescate \
  token_policies=rescate-raiz password=-

Probé primero con un token huérfano de esa política: con él y tres claves de desellado generé un token raíz nuevo (-init, tres llamadas con -nonce y -decode con la contraseña de un solo uso). El problema es que ese token caduca a las 768 horas, el máximo por defecto, y el usuario de userpass no: tras bao login -method=userpass, su sesión también pudo iniciar generate-root -init. Cuando lo tengas, revoca el token raíz con bao token revoke -self.

Cómo hacer copias de seguridad con snapshots de Raft

Un snapshot de Raft es una copia consistente de todos los datos, tomada con el servidor en marcha. Guárdalo dentro del contenedor y cópialo fuera con docker compose cp:

docker compose exec -e BAO_TOKEN openbao \
  bao operator raft snapshot save /tmp/bao.snap
docker compose cp openbao:/tmp/bao.snap ./bao-$(date +%F).snap
docker compose exec openbao rm /tmp/bao.snap

En mis pruebas, el fichero pesó entre 25 KB y 30 KB: un tar.gz con meta.json, state.bin, SHA256SUMS y SHA256SUMS.sealed. Los datos de state.bin siguen cifrados con la clave de OpenBao, así que puedes mandarlo a un almacenamiento externo con restic sin exponer los secretos. La interfaz web muestra el mismo menú en la página de Raft:

Página Raft Storage de la interfaz web de OpenBao con un único nodo, líder y votante, y el menú Snapshots arriba a la derecha.

Para restaurar, pasa el fichero por la entrada estándar. Con docker compose cp el fichero conserva tu UID, el usuario openbao no puede leerlo y el comando falla con Error opening policy file: open /tmp/copia.snap: permission denied (sí, dice policy aunque sea un snapshot):

docker compose exec -T -e BAO_TOKEN openbao sh -c \
  'cat > /tmp/r.snap &&
   bao operator raft snapshot restore /tmp/r.snap' \
  < bao-2026-09-16.snap

La 2.6.2 imprime Error properly closing policy file: close /tmp/r.snap: file already closed, pero sale con código 0 y el secreto borrado volvió. Las notas de la 2.7.0 lo corrigen (GH-3939), y en la beta ese mensaje ya no apareció.

Restaurar en un servidor nuevo exige las claves originales

Restaurar en otra instalación, con otras claves, es el caso de un desastre real, y falla sin -force:

* could not verify hash file, possibly the snapshot is using a
different set of unseal keys; use the snapshot-force API to bypass
this check

Con -force, el servidor nuevo se selló y rechazó su propia clave con cipher: message authentication failed. Tuve que reiniciar el contenedor: entonces bao status pasó a mostrar Total Shares 5 y Threshold 3, los del servidor original, y se deselló con tres de ellas. El token raíz original volvió a funcionar y el del servidor nuevo dejó de existir. La conclusión es directa: un snapshot sin sus claves de desellado no sirve, y las claves no deben viajar con él.

Qué pasa con el backend file en OpenBao 2.7

Las notas de la 2.6.0 anuncian "Deprecate file storage backend for removal in v2.7.0", y la 2.6.2 lo recuerda al arrancar con the file physical backend is deprecated; use bao operator migrate to move to a supported storage backend by v2.7.0. La documentación del backend de ficheros[7] ya lo desaconsejaba: "the Filesystem storage backend is not recommended for production installations as it is not transactional and lacks system-level file locking."

Para comprobarlo creé una instalación con storage "file", le escribí 500 secretos y arranqué la imagen 2.7.0-beta20260909 sobre el mismo volumen. El contenedor terminó con código 1 y una sola línea de error:

unknown storage type file

Migrar de file a Raft con bao operator migrate

La migración copia las claves tal cual, sin descifrarlas, así que el servidor migrado usa las mismas claves de desellado y el mismo token raíz. Se hace con OpenBao parado y con la 2.6.2, que todavía lee file. Crea migrate.hcl:

storage_source "file" {
  path = "/origen"
}

storage_destination "raft" {
  path    = "/openbao/file"
  node_id = "bao-1"
}

cluster_addr = "http://127.0.0.1:8201"

Después para el servicio, crea un volumen vacío para Raft y lanza la migración con los dos volúmenes montados. Sustituye openbao_datos_file por el nombre real que te dé docker volume ls:

docker compose stop openbao
docker volume create openbao_datos_raft
docker run --rm \
  -v openbao_datos_file:/origen \
  -v openbao_datos_raft:/openbao/file \
  -v "$PWD/migrate.hcl:/migrate.hcl:ro" \
  openbao/openbao:2.6.2 operator migrate -config=/migrate.hcl

El volumen de origen tiene que montarse con escritura: operator migrate deja un fichero de bloqueo en él, y con :ro falló con error setting migration lock: open /origen/core/_migration.temp: read-only file system. El destino tiene que estar vacío, sin inicializar.

Lo ejecuté tres veces sobre volúmenes nuevos, y las tres terminaron con Success! All of the keys have been migrated. tras copiar 1029 claves: los 500 secretos más la estructura interna de OpenBao. La copia en sí tardó 5,9 s de mediana (entre 3,6 s y 6,5 s), y antes Raft esperó 7,9 s de mediana a elegir líder. La máquina tenía una carga media de 19 sobre 18 núcleos durante esas pruebas, así que en un servidor sin otra actividad debería ir más deprisa.

Por último, cambia compose.yaml para que el servicio monte openbao_datos_raft (declarado con external: true) y la configuración para que use el bloque storage "raft" del paso 1. Al arrancar, desella con las claves de siempre. En mi prueba, bao kv list devolvió los 500 secretos y el mismo volumen arrancó después con la 2.7.0 beta sin cambios.

Cómo evitar desellar a mano en cada reinicio

Un servidor con desellado Shamir vuelve sellado tras cada reinicio, y tus aplicaciones reciben 503 hasta que alguien introduce tres claves. Hay tres salidas:

  • Aceptarlo: el healthcheck del paso 2 marca el contenedor como unhealthy y te sirve de alarma.
  • Plugins KMS: desde la 2.6.0 el desellado automático con un KMS externo se distribuye como plugin, y la beta de la 2.7.0 ya retira del binario los de AWS, GCP, Azure, Alibaba Cloud, OCI y PKCS#11. No lo he probado porque no tengo un KMS en la nube en este laboratorio.
  • Sello estático: OpenBao lee una clave AES de 32 bytes de un fichero o de una variable de entorno.

Probé el sello estático añadiendo este bloque a la configuración, con la clave creada por openssl rand -out unseal.key 32:

seal "static" {
  current_key_id = "lab-20260916"
  current_key    = "file:///certs/unseal.key"
}

Con este sello, bao operator init entregó cinco claves de recuperación (umbral 3) en lugar de claves de desellado, y tras docker compose restart el servidor volvió desellado. La documentación del sello estático[8] lo recomienda solo cuando ya existe otra fuente de confianza en el entorno. Tiene sentido: si la clave vive en el mismo disco que el volumen, quien copie el disco se lleva las dos cosas.

Preguntas frecuentes

¿Puedo pasar de HashiCorp Vault a OpenBao sin perder los datos?

La guía de migración de OpenBao[9] describe una migración en caliente probada desde Vault 1.14.1 Community Edition a OpenBao 2.2.0, con Raft y desellado Shamir. También avisa de que no funciona desde Vault 1.15.0 o posterior. No lo he probado en este laboratorio.

¿Cuánta memoria necesita OpenBao en Docker?

En esta prueba, con KV v2, AppRole y auditoría activos, docker stats marcó entre 39,5 MiB y 39,7 MiB en tres lecturas seguidas. El pico del cgroup fue de 164 MiB, que incluye la caché de páginas del binario bao de 185 MB. El límite de 512 MiB del paso 2 deja margen de sobra para una instalación pequeña.

¿OpenBao sustituye a un gestor de contraseñas como Vaultwarden?

No. OpenBao guarda los secretos que leen tus servicios y los entrega por API con políticas y auditoría. Para las contraseñas que usan las personas en el navegador, la herramienta adecuada es un gestor como Vaultwarden.

Conclusión

Instalar OpenBao con Docker lleva un fichero de configuración, un compose.yaml y tres claves para desellar. Los detalles que cuestan tiempo son el propietario del volumen, el swap en cgroup v2 y el token raíz. Si todavía tienes una instalación con storage "file", migra a Raft con la 2.6.2 antes de actualizar a la 2.7.0, que ya ni la arranca.

Guarda los snapshots y las claves de desellado en sitios distintos, porque cada pieza sin la otra no sirve. La versión en inglés de esta guía está en How to install OpenBao with Docker and Raft storage.

Fuentes

  1. blog de HashiCorp
  2. repositorio de Vault
  3. página de noticias de OpenBao
  4. documentación de namespaces de Vault
  5. documentación del backend Raft
  6. guía de instalación de OpenBao
  7. documentación del backend de ficheros
  8. documentación del sello estático
  9. guía de migración de OpenBao
  10. OpenBao, notas de la versión 2.6.x
  11. OpenBao, notas de la versión 2.7.x
  12. OpenBao, comando operator migrate
  13. OpenBao, comando operator raft
  14. OpenBao, auditoría declarativa
  15. openbao/openbao en Docker Hub
  16. Repositorio de OpenBao
  17. OpenBao se une a la OpenSSF