Ansible Vault cifra con AES256 archivos y variables que contienen datos sensibles (contraseñas, tokens de API, claves privadas) para que puedas guardarlos en Git junto al resto del proyecto. Ansible los descifra en memoria al ejecutar el playbook, siempre que le proporciones la contraseña de la bóveda. En este tutorial cifrarás un archivo de variables, cifrarás valores sueltos, separarás las contraseñas por entorno con vault IDs y usarás los secretos en un playbook sin exponerlos en la salida.
Requisitos previos
Necesitas:
- Una máquina de control con Ubuntu 24.04 LTS, por ejemplo tu equipo o un VPS de CubePath, con un usuario no root con
sudo. - Conocimientos básicos de playbooks e inventarios de Ansible.
Los ejemplos se ejecutan contra localhost, así que no necesitas servidores gestionados para seguir la guía.
Paso 1: Instalar Ansible y preparar el proyecto
Ubuntu 24.04 incluye Ansible en el repositorio universe, y ansible-vault forma parte del mismo paquete:
sudo apt update
sudo apt install ansible
Comprueba la versión:
ansible-vault --version
ansible-vault [core 2.16.x]
...
Crea un directorio de proyecto con la estructura habitual de variables por grupo:
mkdir -p ~/vault-demo/group_vars/all
cd ~/vault-demo
Todos los comandos siguientes se ejecutan desde ~/vault-demo.
Paso 2: Crear un archivo cifrado
La forma más cómoda de empezar es crear el archivo ya cifrado. ansible-vault create pide una contraseña, abre tu editor y cifra el contenido al guardar, de modo que el texto plano nunca se escribe en disco:
EDITOR=nano ansible-vault create group_vars/all/vault.yml
Introduce la contraseña de la bóveda dos veces y escribe las variables. Usa el prefijo vault_ para que se vea claramente qué valores están cifrados:
vault_db_password: your_strong_password
vault_api_token: your_api_token
Guarda y sal. Comprueba que en disco solo hay texto cifrado:
cat group_vars/all/vault.yml
$ANSIBLE_VAULT;1.1;AES256
62336534643966346337623835363961376664393336356561633061643736353365376537653937
...
Para trabajar con el archivo usa estos comandos, que siempre piden la contraseña:
ansible-vault view group_vars/all/vault.yml
ansible-vault edit group_vars/all/vault.yml
Si ya tienes un archivo en texto plano, cífralo en su sitio con ansible-vault encrypt archivo.yml. ansible-vault decrypt hace lo contrario y deja el archivo en claro en disco, así que úsalo solo si de verdad quieres dejar de cifrarlo.
Paso 3: Referenciar los secretos desde variables en claro
Si todas las variables de un grupo están cifradas, nadie puede buscar con grep dónde se define db_password. La práctica recomendada es tener al lado un archivo en claro que apunte a las variables cifradas:
nano group_vars/all/vars.yml
db_user: app
db_password: "{{ vault_db_password }}"
api_token: "{{ vault_api_token }}"
Ansible carga los dos archivos de group_vars/all/ automáticamente. Los playbooks usan db_password, y el valor real solo existe dentro de la bóveda.
Paso 4: Usar los secretos en un playbook
Crea un playbook de prueba que escriba un archivo de configuración con el secreto. Fíjate en no_log: true: evita que Ansible imprima los argumentos de la tarea, que incluirían la contraseña, en la salida o en los logs:
nano site.yml
- name: Configurar la aplicación
hosts: localhost
connection: local
gather_facts: false
tasks:
- name: Escribir el archivo de credenciales
ansible.builtin.copy:
dest: "{{ lookup('env', 'HOME') }}/vault-demo/app.env"
content: |
DB_USER={{ db_user }}
DB_PASSWORD={{ db_password }}
mode: "0600"
no_log: true
Ejecútalo pidiendo la contraseña de la bóveda:
ansible-playbook site.yml --ask-vault-pass
Vault password:
PLAY [Configurar la aplicación] ************************************************
TASK [Escribir el archivo de credenciales] *************************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=0
Comprueba que el valor se descifró correctamente y que el archivo tiene permisos restrictivos:
ls -l app.env
cat app.env
-rw------- 1 your_user your_user 38 ... app.env
DB_USER=app
DB_PASSWORD=your_strong_password
Si ejecutas el playbook sin --ask-vault-pass, Ansible se detiene con Attempting to decrypt but no vault secrets found.
Paso 5: Cifrar valores sueltos con encrypt_string
A veces solo quieres cifrar una variable dentro de un archivo que por lo demás es legible. encrypt_string genera un bloque que puedes pegar directamente en YAML. Con --stdin-name el valor se lee de la entrada estándar y no queda en el historial de la shell:
ansible-vault encrypt_string --stdin-name 'smtp_password'
Introduce la contraseña de la bóveda, escribe el secreto y pulsa Ctrl+D dos veces (sin salto de línea al final, o formará parte del valor):
Reading plaintext input from stdin. (ctrl-d to end input, twice if your content does not already have a newline)
smtp_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
38656233373639633431363030623164396565303831633063393564366631373861353438373638
...
Encryption successful
Pega ese bloque en cualquier archivo de variables, por ejemplo en group_vars/all/vars.yml. Comprueba que Ansible lo descifra:
ansible localhost -m ansible.builtin.debug -a var=smtp_password --ask-vault-pass
El inconveniente de este método es que no puedes editar el valor con ansible-vault edit; para cambiarlo, generas un bloque nuevo. Para muchos secretos, un archivo cifrado completo (paso 2) es más fácil de mantener.
Paso 6: Separar entornos con vault IDs
Usar la misma contraseña para desarrollo y producción significa que cualquiera con acceso a desarrollo puede leer los secretos de producción. Los vault IDs etiquetan cada contenido cifrado con el nombre de su contraseña, y Ansible prueba la adecuada al descifrar.
Guarda cada contraseña en un archivo fuera del proyecto, legible solo por tu usuario:
mkdir -p ~/.ansible-vault
chmod 700 ~/.ansible-vault
nano ~/.ansible-vault/dev
nano ~/.ansible-vault/prod
chmod 600 ~/.ansible-vault/dev ~/.ansible-vault/prod
Escribe en cada archivo una contraseña larga distinta, en una sola línea. Puedes generarlas con openssl rand -base64 32.
Cifra un archivo de variables con el ID prod:
mkdir -p group_vars/prod
EDITOR=nano ansible-vault create --vault-id prod@~/.ansible-vault/prod group_vars/prod/vault.yml
La cabecera del archivo incluye ahora la etiqueta:
head -n 1 group_vars/prod/vault.yml
$ANSIBLE_VAULT;1.2;AES256;prod
El archivo group_vars/all/vault.yml del paso 2 sigue cifrado con la primera contraseña, sin etiqueta. Vuelve a cifrarlo con el ID dev para que todo el proyecto use los nuevos archivos de contraseña (te pedirá la contraseña antigua):
ansible-vault rekey --ask-vault-pass --new-vault-id dev@~/.ansible-vault/dev group_vars/all/vault.yml
El bloque smtp_password del paso 5 no se puede recifrar con rekey: genéralo de nuevo con ansible-vault encrypt_string --vault-id dev@~/.ansible-vault/dev --stdin-name 'smtp_password' y sustituye el anterior.
Para ejecutar un playbook que use secretos de varios entornos, pasa cada vault ID:
ansible-playbook site.yml --vault-id dev@~/.ansible-vault/dev --vault-id prod@~/.ansible-vault/prod
Si quieres que una contraseña se pida de forma interactiva en lugar de leerse de un archivo, usa prompt como origen, por ejemplo --vault-id prod@prompt.
Para no escribir los IDs en cada comando, decláralos en el ansible.cfg del proyecto:
nano ansible.cfg
[defaults]
vault_identity_list = dev@~/.ansible-vault/dev, prod@~/.ansible-vault/prod
Con este archivo, ansible-playbook site.yml y ansible-vault view encuentran las contraseñas solos.
Paso 7: Cambiar la contraseña de una bóveda
Cuando alguien con acceso deja el equipo, o cada cierto tiempo, rota la contraseña. rekey descifra con la contraseña actual y vuelve a cifrar con la nueva:
ansible-vault rekey --vault-id prod@~/.ansible-vault/prod --new-vault-id prod@prompt group_vars/prod/vault.yml
Tras comprobar que el archivo se abre con la nueva contraseña, actualiza ~/.ansible-vault/prod. Ten en cuenta que rotar la contraseña de Vault no cambia los secretos: si la contraseña antigua se filtró junto con el repositorio, cambia también las credenciales cifradas en los sistemas reales.
Paso 8: Usar Vault en CI/CD y en Git
En un pipeline no hay nadie que escriba la contraseña. Guárdala como secreto enmascarado de tu sistema de CI, escríbela en un archivo temporal con permisos 600 al iniciar el trabajo y pásala con --vault-id:
ansible-playbook site.yml --vault-id prod@"$VAULT_PASS_FILE"
Aquí VAULT_PASS_FILE es la ruta del archivo temporal que crea el pipeline. Bórralo al terminar el trabajo.
Para evitar subir por error contraseñas o archivos descifrados, añade al .gitignore del proyecto cualquier archivo de contraseña o generado:
nano .gitignore
.vault_pass*
*.env
Antes de cada commit, puedes comprobar que los archivos de bóveda siguen cifrados:
grep -L '^\$ANSIBLE_VAULT' group_vars/*/vault.yml
El comando lista los archivos vault.yml que no empiezan por la cabecera de Vault; si no imprime nada, todos están cifrados.
Solución de problemas
Decryption failed (no vault secrets were found that could decrypt): la contraseña o el vault ID no corresponden a ese archivo. Revisa la etiqueta conhead -n 1y que pasas el ID correcto.Attempting to decrypt but no vault secrets found: el playbook usa datos cifrados y no has pasado ninguna contraseña (--ask-vault-pass,--vault-idovault_identity_list).- El secreto aparece en la salida con
-v: faltano_log: trueen la tarea que lo usa. - Un valor de
encrypt_stringtiene un salto de línea de más: terminaste la entrada con Intro antes deCtrl+D. Genera de nuevo el bloque.
Conclusión
Has cifrado archivos y variables con Ansible Vault, separado las contraseñas por entorno con vault IDs y usado los secretos en un playbook sin mostrarlos en la salida. Como siguientes pasos, puedes integrar las contraseñas de Vault con un gestor de secretos mediante un script cliente de vault ID, o mover los secretos más sensibles a un almacén externo como HashiCorp Vault o OpenBao y leerlos con su lookup.
