Ansible Vault

Every infrastructure automation project deals with secrets: database passwords, API keys, SSL private keys, cloud provider credentials. Storing these in plaintext YAML files and committing them to version control is a serious security vulnerability. Ansible Vault solves this problem by providing strong AES-256 encryption for sensitive data that integrates seamlessly with the Ansible workflow — encrypted files are used identically to their unencrypted counterparts in playbooks.

What Ansible Vault Does

Ansible Vault encrypts files or individual string values using a password you provide. The encrypted content is stored as a specially-formatted text block that can be safely committed to version control. When Ansible runs and encounters Vault-encrypted content, it prompts for the password (or reads it from a file or secrets manager) and decrypts the content in memory — it is never written to disk in plaintext.

Encrypting a Whole File

# Encrypt an existing file
ansible-vault encrypt vars/secrets.yml

# Create a new encrypted file
ansible-vault create vars/secrets.yml

# View an encrypted file (decrypts to stdout temporarily)
ansible-vault view vars/secrets.yml

# Edit an encrypted file in your default editor
ansible-vault edit vars/secrets.yml

# Decrypt a file (removes encryption — use with caution)
ansible-vault decrypt vars/secrets.yml

# Re-key a file with a new password
ansible-vault rekey vars/secrets.yml

After running ansible-vault encrypt vars/secrets.yml, the file looks like this:

$ANSIBLE_VAULT;1.1;AES256
39363237353766643464393233333132363135343961363266663839653039313830
63623461373738626534316162306631336463363630333032373539643362623836
...more hex lines...

This is safe to commit to Git. Without the Vault password, the content is unreadable.

Encrypting Individual String Values (vault encrypt_string)

Encrypting entire files is powerful but means opening the whole file to read any value. For single secrets embedded in otherwise-plaintext variable files, use encrypt_string:

ansible-vault encrypt_string 'my_secret_password' --name 'db_password'

Output:

db_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          38643737326432323665663935383462316234326637303635356664
          ...more hex...

Paste this directly into a variable file. The rest of the file remains plaintext while only the sensitive value is encrypted. This is the most practical approach for most projects.

A Practical Secrets File

Create group_vars/all/vault.yml containing only encrypted values:

vault_db_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          ...encrypted..

vault_api_key: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          ...encrypted...

vault_ssl_private_key: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          ...encrypted...

Create group_vars/all/vars.yml with plaintext variables that reference vault variables:

db_password: "{{ vault_db_password }}"
api_key: "{{ vault_api_key }}"
ssl_private_key: "{{ vault_ssl_private_key }}"

The convention of prefixing vault variables with vault_ and creating plaintext aliases is best practice — it keeps your playbooks readable while making the secret boundary explicit.

Running Playbooks with Vault

# Prompt for vault password interactively
ansible-playbook site.yml --ask-vault-pass

# Read vault password from a file
ansible-playbook site.yml --vault-password-file ~/.vault_pass

# Use an environment variable (for CI/CD)
ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass ansible-playbook site.yml

Never commit the vault password file to version control. Add it to .gitignore immediately. In CI/CD pipelines, store the vault password in the CI system's secrets store (GitHub Actions Secrets, GitLab CI Variables, Jenkins credentials) and inject it as an environment variable or temporary file.

Multiple Vault Passwords with Vault IDs

Large projects may have different secrets requiring different access levels — production secrets accessible only to senior engineers, development secrets accessible to all. Vault IDs allow multiple passwords:

# Encrypt with a specific vault ID
ansible-vault encrypt_string 'prod_secret' --vault-id prod@prompt --name db_password
ansible-vault encrypt_string 'dev_secret'  --vault-id dev@prompt  --name db_password

# Run with multiple vault passwords
ansible-playbook site.yml --vault-id prod@~/.vault_pass_prod --vault-id dev@~/.vault_pass_dev

Vault and Version Control: The .gitignore Pattern

Create a .gitignore in your project root:

# Vault password files
.vault_pass
*.vault_pass
vault-pass.txt

# Never commit decrypted secrets
vars/secrets_decrypted.yml

# But DO commit encrypted vault files
# (they are safe to commit)

A pre-commit hook can enforce that no unencrypted secrets are accidentally committed. Tools like detect-secrets and git-secrets scan commits for common secret patterns.

Integrating Vault with External Secrets Managers

In enterprise environments, secrets are often managed by HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault rather than Ansible Vault files. Ansible supports this through lookup plugins:

- name: Retrieve database password from HashiCorp Vault
  debug:
    msg: "{{ lookup('hashi_vault', 'secret=secret/myapp/db_password') }}"

- name: Use AWS Secrets Manager
  debug:
    msg: "{{ lookup('amazon.aws.aws_secret', 'myapp/db_password') }}"

This approach centralises secret management and provides audit trails, rotation policies, and fine-grained access control beyond what Ansible Vault files can offer.

Try This: Encrypt Your Lab Secrets

In your lab project, identify all places where passwords or keys appear in plaintext. Use ansible-vault encrypt_string to encrypt each value. Create a group_vars/all/vault.yml with the encrypted values and a group_vars/all/vars.yml with plaintext aliases. Create a .vault_pass file with your password and add it to .gitignore. Run your existing playbooks with --vault-password-file .vault_pass and confirm they work identically. Then run ansible-vault view group_vars/all/vault.yml to confirm you can inspect the secrets when needed.

Summary

Ansible Vault provides AES-256 encryption for sensitive data in playbooks and variable files. Whole files or individual string values can be encrypted. The vault_ prefix convention and plaintext alias pattern keeps playbooks readable while securing secrets. Vault passwords are provided interactively, via password files, or through environment variables — the last being essential for CI/CD automation. Multiple vault IDs support tiered access controls. For enterprise deployments, external secrets managers integrate with Ansible through lookup plugins.

Leave a Comment