Ansible Vault vs HashiCorp Vault: which secret goes where
One encrypts files in your repo, the other serves secrets at runtime. Most teams need both — here is the split that works.
Two tools, the same word in the name, completely different jobs. Ansible Vault encrypts files at rest so a secret can live safely in your Git repo. HashiCorp Vault is a running server that hands out secrets at runtime, leased and audited. Confuse them and you either commit plaintext to Git or stand up a cluster to hold one API key. The split is not philosophical — it is about whether the secret is static and small enough to travel with the playbook, or dynamic enough to need a server.
This note walks Ansible Vault encryption for bootstrap secrets, HashiCorp Vault lookups for production credentials, and a decision table for which secret goes where. For the broader secrets architecture, continue with Secrets management foundations.
Static bootstrap tokens belong in ansible-vault ciphertext. Rotating database creds belong in HashiCorp Vault with a lease.
Ansible Vault: secrets that ship with the play
Ansible Vault encrypts a vars file with a passphrase. The ciphertext is safe to commit, and Ansible decrypts it in memory when the playbook runs. It is the right tool for the handful of static secrets a playbook needs to bootstrap a host — a registry pull password, an initial API token, a TLS key for a one-time install.
ansible-vault encrypt group_vars/prod/secrets.ymlNew Vault password: ********Encryption successful head -2 group_vars/prod/secrets.yml$ANSIBLE_VAULT;1.1;AES25639396264613966... (ciphertext — safe to commit)# group_vars/prod/secrets.yml is ansible-vault encrypted- hosts: prodtasks:- name: write app configtemplate:src: app.conf.j2 # references {{ db_password }}dest: /etc/app.conf # decrypted only in memory, at run time
Supply the passphrase at run time — interactively, or from a 0600 file in CI that is never committed. In CI, inject the passphrase from your platform's secret store and pass --vault-password-file pointing at a temp file the job deletes on exit.
ansible-playbook playbook.yml --ask-vault-pass# in CI, from a locked-down file:ansible-playbook playbook.yml --vault-password-file .vault-pass
HashiCorp Vault: secrets that live elsewhere
When secrets must rotate, differ per environment, or be revoked centrally, they do not belong in your repo at all. Ansible can look them up from HashiCorp Vault at run time, so nothing sensitive is ever stored with the playbook. Database credentials with a ten-minute TTL, cloud keys scoped to a role, PKI certificates — all of these belong here.
- hosts: prodvars:db_password: "{{ lookup('community.hashi_vault.hashi_vault','secret=database/creds/app:password') }}"tasks:- name: run migration with a freshly-leased credentialcommand: ./migrate.shenvironment:DB_PASS: "{{ db_password }}"
Which secret goes where
The rule of thumb: if the secret is static and small and needs to travel with the playbook — a bootstrap token, a registry pull password — reach for Ansible Vault. If it should rotate, expire, or be audited centrally — database creds, cloud keys, anything production-critical — put it in HashiCorp Vault and look it up. Most teams run both, and that is correct, not redundant.
Where this goes next
Once the split is clear, wire HashiCorp Vault auth for Ansible in CI — AppRole or JWT — so playbooks never embed a long-lived Vault token. Rotate ansible-vault passphrases when people leave the team, and audit Vault lookup paths separately from encrypted files in Git. The Secrets management foundations course maps the full landscape — at rest, in transit, and at runtime.
Go deeper in a courseSecrets management foundationsWhere secrets actually belong — at rest, in transit, and at runtime.View course