Skip to main content

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 }}'