Ansible Vault: Encrypt Secrets & Manage Encrypted Variables (Complete Guide)
By Luca Berton · Published 2024-01-01 · Category: troubleshooting
Complete guide to Ansible Vault. Encrypt files, strings, variables. Multi-vault setup, vault-id, best practices for secrets management.
Ansible Vault encrypts sensitive data — passwords, API keys, certificates — so you can version-control them safely. Here's everything from basic encryption to multi-vault production patterns.
Basic Operations
Encrypt a File
# Create a new encrypted file
ansible-vault create secrets.yml
# Encrypt an existing file
ansible-vault encrypt group_vars/production/vault.yml
# Output:
# Encryption successful
Decrypt a File
# Decrypt permanently
ansible-vault decrypt secrets.yml
# View without decrypting
ansible-vault view secrets.yml
# Edit in place (decrypts → opens editor → re-encrypts)
ansible-vault edit secrets.yml
Run a Playbook with Vault
# Prompt for password
ansible-playbook site.yml --ask-vault-pass
# Use password file
ansible-playbook site.yml --vault-password-file ~/.vault_pass
# Environment variable
export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass
ansible-playbook site.yml
See also: Ansible Vault: Encrypt Secrets & Manage Credentials (2026 Guide)
Encrypting Variables (Not Files)
Encrypt a Single Variable
# Encrypt a string
ansible-vault encrypt_string 'SuperSecret123!' --name 'db_password'
# Output (paste into your vars file):
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
6631626438353534...
Mix Encrypted and Plain Variables
# group_vars/production/vars.yml
db_host: db.production.example.com
db_port: 5432
db_name: myapp_production
db_user: myapp
# Encrypted inline
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
6631626438353534613432373666...
# Plain
app_debug: false
app_log_level: warn
This is the recommended approach — encrypt individual secrets, not entire files. You can see which variables exist without decrypting.
Multi-Vault IDs
Different passwords for different environments:
# Encrypt with a vault ID
ansible-vault encrypt_string 'ProdPassword!' --vault-id prod@prompt --name 'db_password'
ansible-vault encrypt_string 'StagingPass!' --vault-id staging@prompt --name 'db_password'
# Encrypt a file with vault ID
ansible-vault encrypt --vault-id prod@~/.vault_pass_prod group_vars/production/vault.yml
ansible-vault encrypt --vault-id staging@~/.vault_pass_staging group_vars/staging/vault.yml
# Run with multiple vault IDs
ansible-playbook site.yml \
--vault-id prod@~/.vault_pass_prod \
--vault-id staging@~/.vault_pass_staging
Vault ID in Encrypted Files
# The vault ID is embedded in the header:
db_password: !vault |
$ANSIBLE_VAULT;1.2;AES256;prod
6631626438353534...
See also: Ansible Vault: Encrypt & Decrypt Secrets — Complete Guide (2026)
Password File Patterns
Static Password File
# Create password file
echo 'MyVaultPassword' > ~/.vault_pass
chmod 600 ~/.vault_pass
# ansible.cfg
[defaults]
vault_password_file = ~/.vault_pass
Script-Based Password (Pull from Secret Manager)
#!/bin/bash
# ~/.vault_pass_script.sh
# Pull from AWS Secrets Manager
aws secretsmanager get-secret-value \
--secret-id ansible-vault-password \
--query SecretString \
--output text
chmod +x ~/.vault_pass_script.sh
# ansible.cfg
[defaults]
vault_password_file = ~/.vault_pass_script.sh
Environment Variable
#!/bin/bash
# vault_pass_env.sh
echo "$ANSIBLE_VAULT_PASSWORD"
# CI/CD pipeline
export ANSIBLE_VAULT_PASSWORD="from-ci-secret"
ansible-playbook site.yml --vault-password-file vault_pass_env.sh
Rekey (Change Password)
# Change vault password
ansible-vault rekey secrets.yml
# Enter old password, then new password
# Rekey with vault IDs
ansible-vault rekey --vault-id prod@old_pass --new-vault-id prod@new_pass secrets.yml
# Rekey all vault files at once
find . -name "vault.yml" -exec ansible-vault rekey {} +
See also: Ansible Vault Error: Fix 'Attempting to Decrypt but No Vault Secrets Found'
Project Structure Best Practice
project/
├── ansible.cfg
├── site.yml
├── group_vars/
│ ├── all/
│ │ ├── vars.yml # Plain variables (shared)
│ │ └── vault.yml # Encrypted variables (shared secrets)
│ ├── production/
│ │ ├── vars.yml # Plain production config
│ │ └── vault.yml # Encrypted production secrets
│ └── staging/
│ ├── vars.yml # Plain staging config
│ └── vault.yml # Encrypted staging secrets
└── host_vars/
└── special-host/
├── vars.yml
└── vault.yml
Naming Convention
# group_vars/production/vars.yml (plain)
db_host: db.production.example.com
db_port: 5432
db_user: myapp
db_password: "{{ vault_db_password }}" # Reference vault variable
# group_vars/production/vault.yml (encrypted)
vault_db_password: SuperSecret123!
vault_api_key: sk-abc123...
vault_ssl_key: |
-----BEGIN PRIVATE KEY-----
MIIEvg...
-----END PRIVATE KEY-----
The vault_ prefix makes it clear which variables are encrypted.
CI/CD Integration
GitHub Actions
# .github/workflows/deploy.yml
- name: Run Ansible Playbook
env:
ANSIBLE_VAULT_PASSWORD: ${{ secrets.ANSIBLE_VAULT_PASSWORD }}
run: |
echo "$ANSIBLE_VAULT_PASSWORD" > .vault_pass
ansible-playbook site.yml --vault-password-file .vault_pass
rm -f .vault_pass
GitLab CI
# .gitlab-ci.yml
deploy:
script:
- echo "$VAULT_PASSWORD" > .vault_pass
- ansible-playbook site.yml --vault-password-file .vault_pass
- rm -f .vault_pass
variables:
VAULT_PASSWORD: $ANSIBLE_VAULT_PASSWORD
Jenkins
pipeline {
stages {
stage('Deploy') {
steps {
withCredentials([string(credentialsId: 'ansible-vault-pass', variable: 'VAULT_PASS')]) {
sh '''
echo "$VAULT_PASS" > .vault_pass
ansible-playbook site.yml --vault-password-file .vault_pass
rm -f .vault_pass
'''
}
}
}
}
}
Common Mistakes
Mistake 1: Encrypting Entire Files
# ❌ BAD — can't see what variables exist without decrypting
# group_vars/production/main.yml (fully encrypted)
$ANSIBLE_VAULT;1.1;AES256
6631626438353534613432373666...
# ✅ GOOD — only encrypt the secrets
# group_vars/production/vars.yml (plain)
db_host: db.example.com
db_password: "{{ vault_db_password }}"
# group_vars/production/vault.yml (encrypted)
vault_db_password: secret123
Mistake 2: Committing Password Files
# .gitignore — ALWAYS exclude vault password files
.vault_pass
*.vault_pass
vault_pass*
Mistake 3: Not Using no_log
# ❌ BAD — decrypted secret appears in Ansible output
- ansible.builtin.debug:
var: db_password
# ✅ GOOD — suppress output for sensitive tasks
- name: Set database password
community.postgresql.postgresql_user:
name: myapp
password: "{{ vault_db_password }}"
no_log: true
FAQ
Can I use Vault with ansible-pull?
Yes. Pass --vault-password-file to ansible-pull, or set ANSIBLE_VAULT_PASSWORD_FILE as an environment variable on the target host. For automated pulls, use a script that retrieves the password from a local secret store.
How do I encrypt files other than YAML?
ansible-vault encrypt works on any file — certificates, private keys, configuration files. The entire file is encrypted. Use ansible.builtin.copy with the encrypted file as source; Ansible decrypts it automatically during deployment.
Is Ansible Vault secure enough for production?
Vault uses AES-256 encryption, which is strong. The weak point is password management — if your vault password is weak or stored insecurely, the encryption is meaningless. Use a password manager or secrets manager for the vault password itself.
Can I search inside encrypted files?
Not directly. Use the vault_ prefix naming convention so you can grep for variable references in plain files. Use ansible-vault view to inspect individual encrypted files.
Conclusion
Encrypt individual variables (not whole files), use the vault_ prefix convention, store vault passwords in secret managers (not files), and always use no_log: true for tasks that handle decrypted secrets. Vault is simple but requires discipline.
Related Articles
• Ansible Vault: Encrypt and Decrypt • Ansible Variable Precedence Guide • Ansible set_fact vs vars vs extra_vars • Ansible for CI/CD PipelinesCategory: troubleshooting