Vault
Vault Basics
Creating Vault Files
# Create new vault file
ansible-vault create secrets.yml
# Create vault with custom editor
EDITOR=vim ansible-vault create secrets.yml
# Create vault with password file
ansible-vault create --vault-password-file password.txt secrets.yml
# Create vault with multiple passwords
ansible-vault create --vault-id prod@prompt secrets.yml
Editing Vault Files
# Edit existing vault file
ansible-vault edit secrets.yml
# Edit with password file
ansible-vault edit --vault-password-file password.txt secrets.yml
# Edit with specific vault ID
ansible-vault edit --vault-id prod@prompt secrets.yml
Viewing Vault Files
# View vault file content
ansible-vault view secrets.yml
# View with password file
ansible-vault view --vault-password-file password.txt secrets.yml
# View specific vault ID
ansible-vault view --vault-id prod@prompt secrets.yml
Vault Operations
Encrypting Existing Files
# Encrypt existing file
ansible-vault encrypt secrets.yml
# Encrypt multiple files
ansible-vault encrypt secrets.yml database.yml
# Encrypt with specific vault ID
ansible-vault encrypt --vault-id prod@prompt secrets.yml
# Encrypt with password file
ansible-vault encrypt --vault-password-file password.txt secrets.yml
Decrypting Files
# Decrypt vault file
ansible-vault decrypt secrets.yml
# Decrypt with password file
ansible-vault decrypt --vault-password-file password.txt secrets.yml
# Decrypt with specific vault ID
ansible-vault decrypt --vault-id prod@prompt secrets.yml
Changing Vault Passwords
# Change vault password
ansible-vault rekey secrets.yml
# Change password with password file
ansible-vault rekey --vault-password-file old_password.txt --new-vault-password-file new_password.txt secrets.yml
# Change vault ID
ansible-vault rekey --vault-id old@prompt --new-vault-id new@prompt secrets.yml
Vault Content Examples
Basic Vault File
# secrets.yml (encrypted)
---
database_password: secret123
api_key: abc123def456
ssl_private_key: |
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...
-----END PRIVATE KEY-----
admin_users:
- username: admin
password: admin_secret
- username: root
password: root_secret
aws_credentials:
access_key: AKIAIOSFODNN7EXAMPLE
secret_key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Group-Specific Vault
# group_vars/production/vault.yml
---
vault_mysql_root_password: production_secret
vault_ssl_certificate_key: |
-----BEGIN PRIVATE KEY-----
Production SSL private key content
-----END PRIVATE KEY-----
vault_api_tokens:
payment_gateway: prod_token_123
monitoring: prod_monitor_456
# group_vars/staging/vault.yml
---
vault_mysql_root_password: staging_secret
vault_ssl_certificate_key: |
-----BEGIN PRIVATE KEY-----
Staging SSL private key content
-----END PRIVATE KEY-----
vault_api_tokens:
payment_gateway: staging_token_123
monitoring: staging_monitor_456
Host-Specific Vault
# host_vars/web1.example.com/vault.yml
---
vault_host_private_key: |
-----BEGIN PRIVATE KEY-----
Host-specific private key
-----END PRIVATE KEY-----
vault_host_certificates:
- cert_name: web1.example.com
certificate: |
-----BEGIN CERTIFICATE-----
Certificate content
-----END CERTIFICATE-----
Using Vault Variables
In Playbooks
---
- name: Deploy application
hosts: production
vars:
mysql_root_password: '{{ vault_mysql_root_password }}'
api_key: '{{ vault_api_key }}'
tasks:
- name: Configure database
mysql_user:
name: root
password: '{{ mysql_root_password }}'
login_password: '{{ mysql_root_password }}'
- name: Configure application
template:
src: app.conf.j2
dest: /etc/app/app.conf
vars:
app_api_key: '{{ api_key }}'
In Templates
# templates/app.conf.j2
[database]
host = {{ db_host }}
user = {{ db_user }}
password = {{ vault_db_password }}
[api]
key = {{ vault_api_key }}
secret = {{ vault_api_secret }}
[ssl]
certificate = {{ ssl_cert_path }}
private_key = {{ ssl_key_path }}
Mixed Vault and Plain Variables
# group_vars/production/vars.yml
---
db_host: db.production.example.com
db_user: appuser
db_port: 3306
ssl_cert_path: /etc/ssl/certs/app.crt
ssl_key_path: /etc/ssl/private/app.key
# group_vars/production/vault.yml
---
vault_db_password: production_db_secret
vault_api_key: prod_api_key_123
vault_ssl_private_key: |
-----BEGIN PRIVATE KEY-----
Production SSL private key
-----END PRIVATE KEY-----
Vault IDs and Multiple Vaults
Multiple Vault IDs
# Create vault with specific ID
ansible-vault create --vault-id prod@prompt production_secrets.yml
ansible-vault create --vault-id staging@prompt staging_secrets.yml
# Edit specific vault
ansible-vault edit --vault-id prod@prompt production_secrets.yml
# View with multiple vault IDs
ansible-vault view --vault-id prod@prompt --vault-id staging@prompt secrets.yml
Vault ID in Files
# production_secrets.yml
---
database_password: !vault |
$ANSIBLE_VAULT;1.2;AES256;prod
66386439653236336464626566653436...
# staging_secrets.yml
---
database_password: !vault |
$ANSIBLE_VAULT;1.2;AES256;staging
33386439653236336464626566653436...
Using Multiple Vaults
---
- name: Deploy with multiple vaults
hosts: all
vars:
prod_db_password: '{{ vault_prod_db_password }}'
staging_db_password: '{{ vault_staging_db_password }}'
tasks:
- name: Configure production database
mysql_user:
name: produser
password: '{{ prod_db_password }}'
when: environment == "production"
- name: Configure staging database
mysql_user:
name: staginguser
password: '{{ staging_db_password }}'
when: environment == "staging"
Password Management
Password Files
# Create password file
echo "vault_password_here" > .vault_password
# Secure password file
chmod 600 .vault_password
# Use password file
ansible-vault create --vault-password-file .vault_password secrets.yml
Password Scripts
#!/bin/bash
# vault_password.sh
echo "my_vault_password"
# Make script executable
chmod +x vault_password.sh
# Use password script
ansible-vault create --vault-password-file ./vault_password.sh secrets.yml
Environment Variable Passwords
# Set environment variable
export ANSIBLE_VAULT_PASSWORD=my_vault_password
# Use environment variable
ansible-vault create secrets.yml
Interactive Password Prompt
# Prompt for password
ansible-vault create --vault-id @prompt secrets.yml
# Named prompt
ansible-vault create --vault-id production@prompt secrets.yml
Running Playbooks with Vault
Basic Execution
# Run playbook with vault prompt
ansible-playbook -i inventory playbook.yml --ask-vault-pass
# Run with password file
ansible-playbook -i inventory playbook.yml --vault-password-file .vault_password
# Run with vault ID
ansible-playbook -i inventory playbook.yml --vault-id prod@prompt
Multiple Vault IDs
# Multiple vault IDs
ansible-playbook -i inventory playbook.yml \
--vault-id prod@prompt \
--vault-id staging@.staging_password
# Multiple password files
ansible-playbook -i inventory playbook.yml \
--vault-id prod@prod_password.txt \
--vault-id staging@staging_password.txt
Configuration File
# ansible.cfg
[defaults]
vault_password_file = .vault_password
vault_identity_list = prod@prod_password.txt, staging@staging_password.txt
Inline Vault Encryption
Encrypt String
# Encrypt string
ansible-vault encrypt_string 'secret_value' --name 'secret_var'
# Encrypt with vault ID
ansible-vault encrypt_string 'secret_value' --vault-id prod@prompt --name 'secret_var'
# Encrypt from stdin
echo 'secret_value' | ansible-vault encrypt_string --stdin-name 'secret_var'
Inline Encrypted Variables
---
- name: Use inline encrypted variables
hosts: all
vars:
database_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
66386439653236336464626566653436643866643934656536303166336634393863326535323531
3334626439633838343264646664393063633265383936660a303435323662353033643133333734
37303464386432333538303434363539376334343032333134613466623836646565353436333862
3237393639343466630a333365373836666634373263346366366538373965376139666134373736
3463
api_key: !vault |
$ANSIBLE_VAULT;1.1;AES256
33386439653236336464626566653436643866643934656536303166336634393863326535323531
3334626439633838343264646664393063633265383936660a303435323662353033643133333734
37303464386432333538303434363539376334343032333134613466623836646565353436333862
3237393639343466630a333365373836666634373263346366366538373965376139666134373736
3463
tasks:
- name: Use encrypted variables
debug:
msg: 'Database password is {{ database_password }}'
no_log: true
Vault Best Practices
File Organization
inventory/
├── group_vars/
│ ├── all/
│ │ ├── vars.yml
│ │ └── vault.yml
│ ├── production/
│ │ ├── vars.yml
│ │ └── vault.yml
│ └── staging/
│ ├── vars.yml
│ └── vault.yml
├── host_vars/
│ ├── web1.example.com/
│ │ ├── vars.yml
│ │ └── vault.yml
│ └── db1.example.com/
│ ├── vars.yml
│ └── vault.yml
└── vault/
├── production.yml
├── staging.yml
└── .vault_password
Variable Naming Convention
# Good naming convention
---
# Plain variables (vars.yml)
mysql_host: localhost
mysql_port: 3306
mysql_user: appuser
# Vault variables (vault.yml)
vault_mysql_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
66386439653236336464626566653436...
vault_ssl_private_key: !vault |
$ANSIBLE_VAULT;1.1;AES256
33386439653236336464626566653436...
# Usage in playbooks
mysql_password: '{{ vault_mysql_password }}'
ssl_private_key: '{{ vault_ssl_private_key }}'
Security Practices
# Secure vault usage
---
- name: Configure database
hosts: databases
vars:
mysql_root_password: '{{ vault_mysql_root_password }}'
tasks:
- name: Set MySQL root password
mysql_user:
name: root
password: '{{ mysql_root_password }}'
login_password: '{{ mysql_root_password }}'
no_log: true # Hide sensitive output
- name: Create application database
mysql_db:
name: '{{ app_database }}'
state: present
login_password: '{{ mysql_root_password }}'
no_log: true
Vault File Permissions
# Secure vault files
chmod 600 vault.yml
chmod 600 .vault_password
# Secure vault directory
chmod 700 vault/
chmod 600 vault/*
# Git ignore vault passwords
echo ".vault_password" >> .gitignore
echo "vault_password.txt" >> .gitignore
Troubleshooting Vault
Common Issues
# Check vault file format
ansible-vault view secrets.yml
# Verify vault password
ansible-vault decrypt --output=- secrets.yml
# Test vault with playbook
ansible-playbook playbook.yml --vault-id @prompt --check
# Debug vault issues
ansible-playbook playbook.yml --vault-id @prompt -vvv
Vault Recovery
# Recover forgotten password (if you have backup)
ansible-vault decrypt --vault-password-file backup_password.txt secrets.yml
ansible-vault encrypt --vault-password-file new_password.txt secrets.yml
# Rekey with new password
ansible-vault rekey secrets.yml
Validation
# Validate vault syntax
ansible-vault view secrets.yml > /dev/null
# Check vault in playbook
ansible-playbook --syntax-check playbook.yml
# Test vault decryption
ansible-playbook playbook.yml --vault-id @prompt --list-hosts
Advanced Vault Features
Vault Plugins
# Custom vault plugin
from ansible.plugins.vault import VaultSecret
class MyVaultPlugin(VaultSecret):
def get_secret(self, vault_id, secret_path):
# Custom logic to retrieve secret
return secret_value
Vault with CI/CD
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Deploy with vault
env:
VAULT_PASSWORD: ${{ secrets.VAULT_PASSWORD }}
run: |
echo "$VAULT_PASSWORD" > .vault_password
ansible-playbook -i inventory playbook.yml --vault-password-file .vault_password
rm .vault_password
External Secret Management
# Integration with external secret stores
---
- name: Retrieve secrets from external store
hosts: all
tasks:
- name: Get secret from HashiCorp Vault
hashivault_read:
secret: secret/myapp
key: database_password
register: vault_secret
- name: Use retrieved secret
mysql_user:
name: appuser
password: '{{ vault_secret.value }}'