Securing Sensitive Data in Ansible Using Vault
Learn how to secure sensitive variables in Ansible using Vault. This guide covers file encryption, string encryption, secure playbook execution, and CI/CD integration.
23 Aug 2026, 20:50 UTC

The Problem: Plaintext Secrets in Automation
Storing API keys, database passwords, or SSH private keys in plaintext within Ansible playbooks or inventory files creates a significant security vulnerability. If these files are committed to a version control system like Git, any user with repository access can compromise your infrastructure.
The takeaway: Use Ansible Vault to encrypt sensitive variables at rest. This allows you to store encrypted files in version control safely, decrypting them only in memory during playbook execution.
Prerequisites
- Ansible installed on the control node (version 2.9 or newer recommended; the examples below assume the 2.9+ CLI syntax).
- A dedicated vault password (a strong, unique string).
- Permission to create and edit files on the control node where you run the
ansible-vaultcommands.
Method 1: Encrypting Entire Files
This approach is best for dedicated secret files, such as group_vars/all/secrets.yml, where every value in the file is sensitive.
Creating an Encrypted File
Run the following command on your control node to create a new encrypted file:
ansible-vault create secrets.ymlYou will be prompted to set a vault password. Once the editor opens, enter your sensitive variables in standard YAML format:
db_password: "SuperSecret123!"
api_key: "abc-123-def-456"Editing an Existing Encrypted File
To modify the values without manually decrypting and re-encrypting the file, use the edit command:
ansible-vault edit secrets.ymlMethod 2: Encrypting Individual Strings
When you need to mix sensitive and non-sensitive data in a single file, use the encrypt_string feature. This lets you see the variable name and surrounding structure in Git diffs while keeping only the value encrypted.
Generating an Encrypted String
Run this command on your control node, replacing the placeholder value and variable name with your own:
ansible-vault encrypt_string 'SuperSecret123!' --name 'db_password'The output will be a block of encrypted text. Copy this block directly into your vars.yml or inventory file. It looks like this (truncated here; your output will be longer):
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
3361323435623133...Executing Playbooks with Vault
Because the data is encrypted, Ansible cannot read it during runtime without the password. You have two primary options for providing it.
Option A: Interactive Prompt
Use the --ask-vault-pass flag. This is the most secure method for manual runs, since the password never touches the disk:
ansible-playbook site.yml --ask-vault-passOption B: Password File (CI/CD)
For automated pipelines, store the password in a protected file on the control node (for example, ~/.vault_pass) and reference it in your ansible.cfg:
[defaults]
vault_password_file = ~/.vault_passRisk: Never commit the vault password file to Git — doing so defeats the purpose of the encryption. Restrict access with chmod 600 ~/.vault_pass so only the file owner can read it. In CI systems, prefer injecting the file from the pipeline's secret store at job runtime rather than leaving it on a shared runner.
Comparison: Vault vs. External Secret Managers
Ansible Vault is not the only option. External secret managers (such as HashiCorp Vault) can be queried at runtime through lookup plugins. The trade-offs:
| Feature | Ansible Vault | External Manager (e.g., HashiCorp) |
|---|---|---|
| Storage | Local encrypted files | Centralized secure API |
| Complexity | Low (built-in) | High (requires infrastructure and plugins) |
| Rotation | Manual re-encryption | Automated dynamic secrets |
| Audit Trail | Git history (encrypted blobs) | Detailed access logs |
For small teams already using Git, Vault is usually sufficient. If you need automated rotation or per-access auditing, plan for an external manager instead.
Verification and Diagnostics
To ensure your configuration is working correctly, perform these three checks:
- Content check: Run
ansible-vault view secrets.yml. If the password is correct, the plaintext content displays in the terminal. - Execution check: Run your playbook with the password provided. Tasks referencing the encrypted variables should succeed without "variable not defined" or decryption errors.
- Negative test: Run the playbook without
--ask-vault-pass(and without a configured password file). The run should fail when it reaches the first encrypted variable, confirming the secrets are not silently exposed.
Limitations
- No password recovery: If the vault password is lost, the encrypted data is permanently unrecoverable. Store the password in a separate, backed-up secret store.
- Opaque diffs: Fully encrypted files appear as binary-like blobs in Git, so pull request reviews cannot show what changed. Prefer
encrypt_stringfor files that need reviewable diffs. - Manual rotation: Changing a secret means re-encrypting and recommitting; there is no automatic expiry.
Rollback: Removing Encryption
If you need to revert a file to plaintext (for example, when migrating secrets to an external manager), use the decrypt command on the control node:
ansible-vault decrypt secrets.ymlThis permanently rewrites the file as plaintext, so make sure the file is not committed to a shared repository while decrypted.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.