Acceso seguro a AWS con OpenBao
Publicado originalmente en inglés en digitalis.io el 25 de septiembre de 2026.
Resumen
- Una clave de acceso en
~/.aws/credentialses válida hasta que alguien se acuerde de borrarla. OpenBao puede sustituirla por credenciales STS que pides cuando las necesitas y que caducan solas en menos de una hora. - OpenBao guarda un único usuario IAM que solo puede asumir un pequeño conjunto de roles. Nadie llega a ver su clave porque OpenBao la rota justo después de la configuración.
- Un login de OpenBao de un día con credenciales de AWS de una hora significa que el acceso se corta poco después de que termine la jornada. Las credenciales cargadas en una subshell desaparecen al cerrarla.
- Las credenciales STS no se pueden revocar una a una, así que mantén el TTL corto y ten claro dónde está el botón de emergencia.
- El código OpenTofu, una configuración de servidor de desarrollo y un Makefile están en github.com/digitalis-io/openbao-aws-creds-demo.
En el último artículo hablé de mi antiguo directorio de ficheros .env lleno de credenciales de clientes y prometí ocuparme de las que viven en los portátiles de los ingenieros. La peor de todas ni siquiera es un fichero .env, sino ~/.aws/credentials. La mayoría de los ingenieros que conozco tienen uno con un puñado de perfiles. Cada perfil tiene una clave de acceso que se creó el día que entraron en el proyecto y que nunca se ha rotado desde entonces.
Ya usamos OpenBao para credenciales dinámicas de bases de datos, y AWS funciona con el mismo principio. En lugar de una clave que vive para siempre, le pides credenciales a OpenBao cuando las necesitas y dejan de funcionar por sí solas.
Cómo emite OpenBao credenciales de AWS
El motor de secretos de AWS guarda un conjunto de credenciales de AWS para sí mismo y las usa para crear credenciales para ti. Admite cuatro tipos de credenciales. iam_user crea un usuario IAM real con una clave de acceso y lo borra cuando termina el lease. Los otros tres (assumed_role, federation_token y session_token) devuelven credenciales STS temporales.
Nosotros usamos assumed_role. OpenBao llama a sts:AssumeRole sobre un rol IAM que tú defines y recibes una access key, un secret y un session token. Caducan tras el TTL que hayas pedido, que puede ir de 15 minutos a 12 horas. No se crea nada en IAM al solicitarlas, así que no hay nada que limpiar. Los permisos viven en roles IAM normales que tu equipo de AWS puede revisar como cualquier otro.
La pega es la revocación. AWS no tiene ninguna API para cancelar una sesión STS concreta, así que revocar el lease en OpenBao no hace nada en el lado de AWS. Si necesitas credenciales que puedas anular a demanda, iam_user te lo da. El precio es que OpenBao necesita permiso para crear y borrar usuarios IAM, y cada usuario nuevo tarda unos segundos en propagarse. Para el acceso diario de ingeniería preferimos credenciales STS de corta duración.
Lo que OpenBao necesita en AWS
Necesitas dos cosas en AWS. La primera es un usuario IAM al que llamamos openbao. Su política permite sts:AssumeRole sobre los roles que reparte OpenBao, más las cuatro acciones IAM que necesita para rotar su propia clave. La segunda es un rol IAM por cada nivel de acceso, como openbao-developer con ReadOnlyAccess. Su trust policy indica que el usuario openbao es el único principal autorizado a asumirlo.
Primero lo monté a mano y me llevó más tiempo del que me gustaría admitir. Mi primer intento falló con AccessDenied porque le había dado a OpenBao mis propias claves IAM y el rol solo confiaba en el usuario openbao. El segundo falló porque había copiado la trust policy de un rol existente que todavía confiaba en un usuario de otra cuenta. Después falló rotate-root porque a la política le faltaba iam:GetUser. Nada de esto es difícil, pero los mensajes de error solo te dicen qué llamada se denegó. No te dicen cuál de las dos políticas está mal.
Conviene conocer dos límites de AWS antes de empezar. El MaxSessionDuration de un rol es de una hora por defecto y AWS rechaza cualquier petición de una sesión más larga, así que súbelo hasta el TTL más largo que quieras permitir. Además, las credenciales propias de OpenBao deben pertenecer a un usuario IAM y no a un rol, porque AWS limita el encadenamiento de roles a una hora, permita lo que permita el rol.
Mantener la clave raíz fuera del alcance de todos
El usuario openbao necesita una clave de acceso, y esa clave es lo más sensible de toda la configuración. Nuestra primera idea fue crearla con aws_iam_access_key en OpenTofu y pasársela al recurso vault_aws_secret_backend. Funciona, pero el provider de AWS guarda el secreto en el fichero de estado y no existe una versión write-only de ese recurso.
OpenBao tiene una respuesta mejor llamada rotate-root. Crea una clave nueva para su propio usuario IAM y borra la antigua. Tampoco pudimos manejar eso desde OpenTofu. En cuanto OpenBao borra la clave que creó OpenTofu, el siguiente plan ve que la clave ha desaparecido y crea otra, así que acabas en un bucle. Al final movimos el arranque a un pequeño script que OpenTofu ejecuta una sola vez:
aws iam create-access-key --user-name "$IAM_USER" --output json |
jq --arg region "$AWS_REGION" \
'{access_key: .AccessKey.AccessKeyId, secret_key: .AccessKey.SecretAccessKey, region: $region}' |
bao write "${MOUNT_PATH}/config/root" - >/dev/nullbao write -f "${MOUNT_PATH}/config/rotate-root"La clave viaja desde el AWS CLI hasta OpenBao a través de una tubería, así que nunca aparece en pantalla, en el historial de la shell ni en el estado. Unos segundos después, OpenBao la sustituye por una clave generada por él mismo y, a partir de ahí, nadie conoce las credenciales que hay detrás de cada rol. El script real reintenta rotate-root durante un minuto porque una clave IAM recién creada puede tardar unos segundos en empezar a funcionar.
Ejecutar la demo
Todo lo anterior está en el repositorio, junto con una configuración para un servidor OpenBao de desarrollo local que descarga el plugin de AWS al arrancar:
git clone https://github.com/digitalis-io/openbao-aws-creds-demo.git
cd openbao-aws-creds-demo
make bao-dev # primer terminal
export BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root
export AWS_PROFILE=my-admin # una identidad que pueda gestionar IAM
make plan && make apply
bao write aws/sts/developer ttl=1hLos niveles de acceso son un mapa, así que añadir un rol de administrador de corta duración solo requiere unas pocas líneas en terraform.tfvars:
roles = {
developer = {
managed_policy_arns = ["arn:aws:iam::aws:policy/ReadOnlyAccess"]
}
admin = {
managed_policy_arns = ["arn:aws:iam::aws:policy/AdministratorAccess"]
default_ttl = 900
max_ttl = 3600
}
}Cada rol recibe además su propia política de OpenBao (aws-developer y aws-admin), que asignas a quien deba poder solicitarlo. Abajo puedes ver una prueba rápida. Estoy ocultando las partes sensibles, aunque, para ser sincero, cuando leas esto las credenciales ya habrán caducado.
Get Sergio Rua’s stories in your inbox
Join Medium for free to get updates from this writer.
[Insertar aquí la captura de pantalla del artículo original]
Credenciales que viven en un solo terminal
Lo que yo quería eran credenciales que existieran en un terminal y en ningún otro sitio. La forma más sencilla de conseguirlo es una subshell con las credenciales en su entorno:
aws-session() {
local role="${1:?usage: aws-session <role> [ttl]}" ttl="${2:-1h}" creds
creds=$(bao write -format=json "aws/sts/${role}" ttl="$ttl") || return 1
env -u AWS_PROFILE \
AWS_ACCESS_KEY_ID="$(jq -r .data.access_key <<<"$creds")" \
AWS_SECRET_ACCESS_KEY="$(jq -r .data.secret_key <<<"$creds")" \
AWS_SESSION_TOKEN="$(jq -r '.data.session_token // .data.security_token' <<<"$creds")" \
AWS_SESSION_ROLE="$role" \
"$SHELL"
}aws-session developer 2h te deja en una shell donde el AWS CLI, Terraform y cualquier otra herramienta basada en el SDK recogen las credenciales. Escribe exit o cierra la ventana y desaparecen de la máquina. No se escribe nada en disco y cada terminal puede tener un rol distinto al mismo tiempo.
Ten claro lo que hace realmente cerrar el terminal. Las credenciales desaparecen de tu portátil, pero siguen siendo válidas en AWS hasta que se agote el TTL, y por eso mantenemos el valor por defecto en una hora.
Mi forma preferida, con diferencia, es este sencillo truco en ~/.aws/config:
[profile openbao-developer]
region = eu-west-2
credential_process = sh -c "bao write -format=json aws/sts/developer ttl=1h | jq '{Version: 1, AccessKeyId: .data.access_key, SecretAccessKey: .data.secret_key, SessionToken: (.data.session_token // .data.security_token), Expiration: (now + .lease_duration | todate)}'"Después puedes usarlo como cualquier otro perfil de AWS:
$ BAO_ADDR=http://localhost:8200 AWS_PROFILE=openbao-developer aws sts get-caller-identity
{
"UserId": "AROAXXXXXXXXXXHH:vault-token-developer-1790243125-8BP6BZl2IANwr7kF4IYT",
"Account": "000000000000",
"Arn": "arn:aws:sts::000000000000:assumed-role/openbao-developer/vault-token-developer-1790243125-8BP6BZl2IANwr7kF4IYT"
}El comando bao necesita BAO_ADDR y un token en su entorno. La primera vez se me olvidó la dirección y lo único que me dijo el AWS CLI fue Expecting value: line 1 column 1 (char 0), que es lo que obtienes cuando el proceso no devuelve absolutamente nada.
Cortar el acceso al final del día
La última pieza es el propio login de OpenBao. Cada lease es hijo del token que lo solicitó y nadie puede pedir nada una vez que ese token ha caducado. Si los ingenieros se autentican mediante OIDC con un token de ocho horas, hacen login con SSO por la mañana y piden tantas credenciales de una hora como necesiten a lo largo del día. Poco después de dejar de trabajar, se quedan sin acceso a AWS:
bao write auth/oidc/role/engineers \
token_policies=aws-developer token_ttl=8h token_max_ttl=8h \
...En el peor de los casos, las últimas credenciales emitidas siguen siendo válidas durante una hora después de que caduque el token. No hay ninguna clave en el portátil que se pueda filtrar y, con un audit device activado, cada petición queda registrada a nombre de la persona que la hizo.
Para emergencias, AWS puede invalidar de golpe todas las sesiones de un rol. El botón “Revoke active sessions” de la consola de IAM añade una política que deniega cualquier cosa con un token emitido antes de ese momento. Es una medida drástica porque corta el acceso a todos los que usan el rol, pero conviene saber dónde está antes de necesitarlo.
OpenBao y Vault
Todo lo que hay aquí funciona también con HashiCorp Vault. Vault trae el motor de AWS integrado, mientras que en OpenBao lo ejecutamos como plugin desde el registro de OpenBao. Configuramos OpenBao con el provider de OpenTofu hashicorp/vault porque ambos comparten API.
No solo AWS
AWS era el tema de hoy, pero la misma idea se aplica a la mayoría de las credenciales que lleva encima un ingeniero. OpenBao tiene motores de secretos para Google Cloud y Azure que reparten tokens de acceso de corta duración, claves de service account o service principals de forma muy parecida. Para Kubernetes, el motor de secretos crea un token de service account limitado a un namespace, lo cual es mucho mejor que un kubeconfig con cluster admin que no caduca nunca. El motor SSH firma un certificado válido durante media hora, así que nadie tiene que añadir su clave a authorized_keys, y el motor de bases de datos que tratamos en Credenciales dinámicas con OpenBao y Vault hace lo mismo con los usuarios de base de datos.
El patrón no cambia de uno a otro. OpenBao guarda la única credencial poderosa, tú haces login con SSO y lo que recibes caduca por sí solo. Una vez que el login y las políticas están en su sitio, añadir otro servicio consiste básicamente en montar otro motor. Hablaremos de GCP en un próximo artículo.
Dónde entramos nosotros
Sacar el primer conjunto de credenciales de OpenBao lleva una tarde. Convertirlo en algo que todo un equipo de ingeniería use a diario lleva más. Necesitas un clúster de OpenBao de alta disponibilidad y con copias de seguridad, SSO conectado a los grupos correctos, roles IAM que reflejen cómo trabajan realmente tus equipos y un plan para deshacerte de las claves que ya están en el portátil de todo el mundo. Eso es lo que construimos para nuestros clientes, y lo respaldamos con servicios gestionados 24x7.
Si tus ingenieros todavía llevan encima claves de AWS de larga duración, ponte en contacto con nosotros en digitalis.io/contact.
Yo, por mi parte, doy la bienvenida a nuestros nuevos señores robot.
Digitalis.io ofrece servicios gestionados y consultoría experta en OpenBao, Vault, Kubernetes, Cassandra, Kafka y el ecosistema cloud native en general. Si quieres ayuda para diseñar, operar o migrar tu gestión de secretos, escríbenos en digitalis.io/contact.








