Secrets with Ansible Vault
Your playbooks live in git, and so do their variables. But some variables are passwords: the database password the app needs, an API key, a TLS private key. In the DevOps path you kept secrets out of git with .env files. Ansible offers another answer: keep them in git, encrypted. Ansible Vault encrypts files or single values with a password, and playbooks decrypt them on the fly.
You will learn
ansible-vault encrypt,view,edit,decrypt,createandrekey- Running playbooks with
--ask-vault-passor a vault password file - The
vars.yml+vault.ymlpattern that keeps secrets findable encrypt_stringfor a single value inside a normal fileno_log, and why secrets must not leak into output
Encrypt a file
ansible-vault encrypt group_vars/web/vault.yml # asks for a new vault password, twice cat group_vars/web/vault.yml # unreadable now ansible-vault view group_vars/web/vault.yml # read it (asks for the password) ansible-vault edit group_vars/web/vault.yml # change it: decrypt → editor → re-encrypt
$ANSIBLE_VAULT;1.1;AES256 65326638653261316438323230316631333466616235366435393835653730643338656466386431 3362366464616131303939393731303566326366666338350a646562303436636630356438396331 …
The real Vault uses AES-256, so without the password the file is just noise, and it's safe to commit. The practice terminal copies the file format, not the real cryptography.
The vars.yml + vault.yml pattern
If every secret hides inside an encrypted file, nobody can grep for where a variable is set. The common fix: two files, side by side.
db_password: "{{ vault_db_password }}"vault_db_password: Tickets-2026-orange-kayak
Everyone can see that db_password exists and where it comes from. Only people with the vault password can see its value. The vault_ prefix makes encrypted variables obvious.
Running playbooks with a vault
ansible-playbook site.yml # ERROR! Attempting to decrypt but no vault secrets found ansible-playbook site.yml --ask-vault-pass # type it each time # or: a password file, never in git, only readable by you echo 'the-vault-password' > ~/.vault_pass chmod 600 ~/.vault_pass # in ansible.cfg, under [defaults]: vault_password_file = ~/.vault_pass
In CI, the vault password comes from the CI system's secret store and is written to a temporary file for the run. The encrypted files stay in git, and the one key that opens them does not.
One value: encrypt_string
ansible-vault encrypt_string --prompt --name api_key # --prompt keeps it out of shell history
api_key: !vault |
$ANSIBLE_VAULT;1.1;AES256
3663353437316537353465306531346436…
Paste that into any vars file. The rest of the file stays readable, and only this value is encrypted.
Don't leak it in the output
Ansible prints task results, and --diff prints file changes. For a task that handles a secret, that could print the password into a CI log. Add no_log: true to such tasks:
- name: Write the app's config
ansible.builtin.template:
src: app.conf.j2
dest: /etc/cht/app.conf
mode: "0600" # root only: the file holds a password
no_log: true # results (and errors) are hidden
Use a long random vault password, keep the password file out of git (.gitignore), and share it through a password manager. If it leaks, run ansible-vault rekey to change it, and rotate the secrets inside too: anyone who had the old password could already read them.
Vault is perfect for small teams: nothing extra to run. Bigger setups often keep secrets in HashiCorp Vault/OpenBao or a cloud secret manager, and let Ansible fetch them at run time with a lookup plugin. The idea from the DevOps secrets lesson is the same either way: secrets never sit in plain text in git.
Practice: lock up the database password 🔏
The web role now also writes the app's config, which needs a database password. Someone left it in plain text in group_vars/web/vault.yml. Encrypt it, run the playbook both ways, and set up a password file.
Quick check
1. Is it OK to commit a vault-encrypted file to git?
✓ Encrypted data in git, key somewhere else.
2. Why keep db_password: "{{ vault_db_password }}" in a plain vars.yml?
✓ It's a convention, and a very useful one.
3. What does no_log: true do?
✓ Use it on tasks that touch secrets, especially in CI.