Ansible Vault: Securing Your Automation Secrets
In the world of infrastructure automation, security remains a paramount concern. As organizations increasingly adopt infrastructure as code practices, sensitive information like API keys, passwords, and certificates must be handled carefully.
Ansible Vault provides a robust solution to this challenge, allowing you to encrypt sensitive data while keeping it seamlessly integrated with your automation workflows.
Understanding Ansible Vault
At its core, Ansible Vault is a feature built into Ansible that provides encryption and decryption services for sensitive data. It uses AES-256 encryption to protect files, ensuring that unauthorized users cannot access your secrets.
Ansible Vault works by encrypting files or individual variables with a password. During playbook execution, Ansible automatically decrypts this information when needed, making the encryption process transparent to your automation workflows.
What makes Ansible Vault particularly powerful is its deep integration with the broader Ansible ecosystem. You can use encrypted content anywhere you would use unencrypted content in your playbooks, roles, or variable files. This seamless integration ensures that adding security doesn't increase complexity or reduce functionality.
Key benefits of Ansible Vault include:
- Simple implementation: Requires minimal additional setup as it's built into Ansible.
- Flexible encryption: Can encrypt entire files or individual variables.
- Secure storage: Allows sensitive data to be safely committed to version control.
- Transparent usage: Encrypted data works seamlessly with existing Ansible functionality.
Getting started with Ansible Vault
Ansible Vault comes built into Ansible, so if you have Ansible installed, you already have access to Vault. To confirm your Ansible installation includes Vault, you can check your Ansible version:
ansible --version
ansible [core 2.16.14]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/ayo/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.13/site-packages/ansible
ansible collection location = /home/ayo/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.13.2 (main, Feb 4 2025, 00:00:00) [GCC 14.2.1 20250110 (Red Hat 14.2.1-7)] (/usr/bin/python3)
jinja version = 3.1.6
libyaml = True
Ansible Vault commands follow a consistent structure:
ansible-vault [action] [options] file_name
Common actions include:
create
: Create a new encrypted file.encrypt
: Encrypt an existing file.decrypt
: Decrypt an encrypted file.edit
: Edit an encrypted file.view
: View the contents of an encrypted file.rekey
: Change the encryption password.
Let's create a new encrypted file to store database credentials:
ansible-vault create secret_vars.yml
When you run this command, Ansible will prompt you to create and confirm a password. After entering a password, your default editor will open, allowing you to add content to the file.
db_user: admin
db_password: supersecretpassword123
db_host: db.example.com
db_port: 5432
After saving and closing the editor, your file will be encrypted automatically.
If you try to view the file using a regular text editor or command like cat
,
you'll see only encrypted content:
cat secret_vars.yml
$ANSIBLE_VAULT;1.1;AES256
32613736303961633861643936643839396438396438653932323939666630373962373765626362
3935633831643635633434323937333538346165663337610a373530626436343764646562636461
30663835356565383735653761386536663730306262386132613836363465636665323131353865
6365663932623835610a653565353362333435623135343965623836653634643935636363333734
30646337623166303739306436383861396661373439356635393131323331323839623366333065
36363162383235303637333166653534333764653965376562323532323433343832343766643834
37383666363663346531343530366266616638346337303033363065383337646236636563633265
34313733656566653032
This encrypted format ensures that your sensitive information remains protected while at rest. The encrypted file contains the AES256 cipher, a salt, and the actual encrypted data.
Core operations
Let's explore the essential operations you can perform with Ansible Vault. If
you already have configuration files with sensitive data, you can encrypt them
using the encrypt
command:
ansible-vault encrypt existing_config.yml
This command will prompt you for a password and then encrypt the file in place, replacing the original unencrypted file with the encrypted version. For example, let's say you have an existing file with API credentials:
api_key: a8d7f9e1c5b2e4d0
api_secret: 93hdj47dh3kdi7hd3jd93
api_endpoint: https://api.example.com/v1
After running the encrypt command, the file will be transformed into an encrypted version that's safe to store in version control.
You can encrypt multiple files simultaneously by providing multiple file paths:
ansible-vault encrypt file1.yml file2.yml file3.yml
This is particularly useful when setting up a new project with multiple configuration files containing sensitive information.
To convert an encrypted file back to plaintext, use the decrypt
command:
ansible-vault decrypt secret_vars.yml
You'll be prompted for the vault password, and upon successful authentication, the file will be decrypted in place. Be cautious with this command, as it removes the encryption protection from your sensitive data.
Decryption is typically used when you need to make significant changes to a file or when you're transitioning to a different security approach.
Editing encrypted files
Instead of decrypting a file to edit it and then re-encrypting it afterward (which creates a window of vulnerability), Ansible Vault provides a direct editing capability:
ansible-vault edit secret_vars.yml
This command will:
- Prompt you for the vault password.
- Decrypt the file in memory (not on disk).
- Open the decrypted content in your default editor.
- Re-encrypt the file automatically when you save and close the editor.
This approach ensures your sensitive data is never written to disk in an unencrypted form during the editing process.
Viewing encrypted content
When you need to check the contents of an encrypted file without editing it, the
view
command is ideal:
ansible-vault view secret_vars.yml
Similar to the edit command, this will decrypt the file in memory and display its contents without writing the decrypted version to disk.
Changing the encryption password
Security best practices often recommend periodic password rotation. To change the password used to encrypt a vault file:
ansible-vault rekey secret_vars.yml
You'll be prompted to enter the current password and then to create and confirm a new password. The file will be re-encrypted with the new password while the content remains unchanged.
Working with vault passwords
Managing vault passwords effectively is critical to maintaining both security and operational efficiency.
Single password management
The simplest approach is to use a single password for all your vault-encrypted files. While this is convenient, it provides limited security isolation. If you use this approach, you can avoid repeatedly typing the password by storing it in a file:
echo "your_secure_password" > ~/.vault_pass
chmod 600 ~/.vault_pass
Ensure that you set restrictive permissions on this file to prevent unauthorized access. Now, you can reference this password file in your commands:
ansible-vault create --vault-password-file=~/.vault_pass new_secret.yml
You can also configure Ansible to use this password file automatically by adding
the following to your ansible.cfg
:
[defaults]
vault_password_file = ~/.vault_pass
With this configuration, you won't need to specify the password file in each command.
Password files vs. password scripts
Instead of storing the vault password in a plaintext file (which has obvious security implications), you can use a script that retrieves the password dynamically. For example, you might create a script that fetches the password from a secure password manager:
#!/usr/bin/env python3
import subprocess
def get_password_from_manager():
# This is just an example - implement your own secure method
result = subprocess.run(['pass', 'show', 'ansible/vault'],
capture_output=True, text=True)
return result.stdout.strip()
if __name__ == "__main__":
print(get_password_from_manager())
Make the script executable:
chmod +x vault-pass.py
Then use it with vault commands:
ansible-vault edit --vault-password-file=./vault-pass.py secret_vars.yml
This approach adds an extra layer of security by avoiding storage of the vault password in plaintext.
Multiple vault password strategies
As your infrastructure grows, you might need different levels of security for different environments or types of secrets. Ansible Vault supports multiple password strategies through Vault IDs.
First, create separate password files for each environment:
echo "dev_environment_password" > ~/.vault_pass.dev
echo "prod_environment_password" > ~/.vault_pass.prod
chmod 600 ~/.vault_pass.*
Now you can create or encrypt files with specific Vault IDs:
ansible-vault create --vault-id dev@~/.vault_pass.dev dev_secrets.yml
ansible-vault create --vault-id prod@~/.vault_pass.prod prod_secrets.yml
The dev@
and prod@
prefixes are Vault IDs that identify which password
should be used for which file.
Vault ID implementation
You can configure multiple Vault IDs in your ansible.cfg
file:
[defaults]
vault_identity_list = dev@~/.vault_pass.dev, prod@~/.vault_pass.prod
With this configuration, Ansible will try each password in order when decrypting files. During encryption, you'll need to specify which ID to use:
ansible-vault encrypt --vault-id dev@~/.vault_pass.dev config_file.yml
This approach allows for more sophisticated secret management strategies while maintaining the simplicity of the Ansible Vault interface.
Here's how to use multiple vault passwords in a playbook:
- name: Deploy application with environment-specific secrets
hosts: all
vars_files:
- common_vars.yml
- "{{ env }}_secrets.yml" # Will be either dev_secrets.yml or prod_secrets.yml
tasks:
- name: Configure application
template:
src: app_config.j2
dest: /etc/app/config.yml
vars:
config_env: "{{ env }}"
When running this playbook, you would specify which environment to use:
ansible-playbook deploy.yml -e "env=dev" --vault-id dev@~/.vault_pass.dev
This command tells Ansible to use the dev_secrets.yml
file and decrypt it
using the password stored in ~/.vault_pass.dev
.
Using encrypted content in playbooks
Now that we understand how to manage encrypted files, let's explore how to use them effectively in Ansible playbooks.
Including encrypted files in playbooks
The simplest way to use encrypted content is to include encrypted files in your
playbooks using vars_files
:
- name: Deploy web application
hosts: webservers
vars_files:
- common_vars.yml
- secret_vars.yml # This is an encrypted file
tasks:
- name: Configure database connection
template:
src: db_config.j2
dest: /var/www/app/config/database.php
owner: www-data
group: www-data
mode: '0640'
When executing this playbook with the correct vault password provided, Ansible
will automatically decrypt the secret_vars.yml
file and make its variables
available to the playbook.
Running playbooks with vault-encrypted files
When running a playbook that uses encrypted files, you need to provide the vault password:
ansible-playbook deploy_webapp.yml --ask-vault-pass
This command will prompt you for the vault password before executing the playbook. Alternatively, you can use a password file:
ansible-playbook deploy_webapp.yml --vault-password-file=~/.vault_pass
If you've configured a vault_password_file
in your ansible.cfg
, you don't
need to specify it in the command.
Handling encrypted files in roles
When organizing your Ansible code into roles, you might need to include encrypted files within role directories. Here's a typical structure:
my_role/
├── defaults/
│ └── main.yml
├── files/
│ └── secure_config.yml.vault # Encrypted file
├── handlers/
│ └── main.yml
├── tasks/
│ └── main.yml
├── templates/
│ └── application.conf.j2
└── vars/
└── secrets.yml # Encrypted variables
You can reference encrypted files in your tasks:
- name: Copy secure configuration
copy:
src: secure_config.yml.vault
dest: /etc/application/config.yml
owner: root
group: app
mode: '0640'
And include encrypted variables:
- name: Include secret variables
include_vars:
file: secrets.yml
- name: Configure application with sensitive data
template:
src: application.conf.j2
dest: /etc/application/config.conf
owner: root
group: app
mode: '0640'
Variable-level encryption
Instead of encrypting entire files, Ansible Vault allows you to encrypt individual variables within a file. This approach is useful when only a few variables in a file contain sensitive information.
To encrypt a single variable, use the ansible-vault encrypt_string
command:
ansible-vault encrypt_string 'supersecretpassword' --name 'db_password'
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
31393861333766643966376131303735663839653432626130303766323966653866616638356233
3033353037323730666566353564333564626437623132620a653537366336376364356239636433
31383663373935363434366438383832303766623762656465396239636637396234613866623566
3032376436313831640a396233366137326566373036303333613337336639636231633561633433
3935
You can then include this encrypted variable in a YAML file:
# Regular variables
db_user: admin
db_host: db.example.com
db_port: 5432
# Encrypted variable
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
31393861333766643966376131303735663839653432626130303766323966653866616638356233
3033353037323730666566353564333564626437623132620a653537366336376364356239636433
31383663373935363434366438383832303766623762656465396239636637396234613866623566
3032376436313831640a396233366137326566373036303333613337336639636231633561633433
3935
This file can be committed to version control with only the password encrypted, making it easier to track changes to non-sensitive variables.
Using encrypted strings in inventory
You can also use encrypted strings in your inventory files to protect sensitive host-specific variables:
[webservers]
web1.example.com
web2.example.com
[database]
db1.example.com
[database:vars]
db_user=admin
db_password=!vault |
$ANSIBLE_VAULT;1.1;AES256
31393861333766643966376131303735663839653432626130303766323966653866616638356233
3033353037323730666566353564333564626437623132620a653537366336376364356239636433
31383663373935363434366438383832303766623762656465396239636637396234613866623566
3032376436313831640a396233366137326566373036303333613337336639636231633561633433
3935
This approach is particularly useful for environment-specific credentials that need to be associated with specific inventory groups.
Using Ansible Vault in practical scenarios
Let's explore some practical scenarios where Ansible Vault proves invaluable.
Securing database credentials
One of the most common use cases for Ansible Vault is protecting database credentials used in application deployments:
mysql_root_password: SuperSecretRoot123!
app_db_name: my_application
app_db_user: app_user
app_db_password: AppUserPass987!
You can use these variables in a database setup playbook:
- name: Configure MySQL database
hosts: database_servers
become: yes
vars_files:
- database_secrets.yml
tasks:
- name: Set MySQL root password
mysql_user:
name: root
password: "{{ mysql_root_password }}"
host_all: yes
state: present
- name: Create application database
mysql_db:
name: "{{ app_db_name }}"
state: present
login_user: root
login_password: "{{ mysql_root_password }}"
- name: Create application database user
mysql_user:
name: "{{ app_db_user }}"
password: "{{ app_db_password }}"
priv: "{{ app_db_name }}.*:ALL"
state: present
login_user: root
login_password: "{{ mysql_root_password }}"
Managing SSL certificates
Another common scenario is managing SSL certificates and private keys:
ssl_private_key: |
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7VJTUt9Us8cKj
MzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvu
NMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZ
[... rest of the key ...]
-----END PRIVATE KEY-----
ssl_certificate: |
-----BEGIN CERTIFICATE-----
MIIDnTCCAoWgAwIBAgIUJl6BIvdM+RfTfQDdBXcUxAXRnZowDQYJKoZIhvcNAQEL
BQAwXjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1TYW4gRnJh
bmNpc2NvMQ8wDQYDVQQKDAZNeU9yZzExGTAXBgNVBAMMEHd3dy5leGFtcGxlLmNv
[... rest of the certificate ...]
-----END CERTIFICATE-----
These can be used in a web server configuration playbook:
- name: Configure web server with SSL
hosts: webservers
become: yes
vars_files:
- ssl_secrets.yml
tasks:
- name: Create SSL directory
file:
path: /etc/nginx/ssl
state: directory
mode: '0700'
- name: Install SSL private key
copy:
content: "{{ ssl_private_key }}"
dest: /etc/nginx/ssl/private.key
owner: root
group: root
mode: '0600'
- name: Install SSL certificate
copy:
content: "{{ ssl_certificate }}"
dest: /etc/nginx/ssl/certificate.crt
owner: root
group: root
mode: '0644'
- name: Configure Nginx with SSL
template:
src: nginx_ssl.conf.j2
dest: /etc/nginx/sites-available/default
notify: Restart Nginx
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
Securing API keys
API keys and tokens used for external service integration are perfect candidates for vault encryption:
aws_access_key: AKIAIOSFODNN7EXAMPLE
aws_secret_key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
github_api_token: ghp_aBcDeFgHiJkLmNoPqRsTuVwXyZ1234567890
slack_webhook_url: https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
You can use these in a deployment playbook:
- name: Deploy application with external integrations
hosts: application_servers
vars_files:
- api_keys.yml
tasks:
- name: Configure AWS credentials
template:
src: aws_credentials.j2
dest: /home/app/.aws/credentials
owner: app
group: app
mode: '0600'
- name: Set up GitHub access for deployments
copy:
content: "{{ github_api_token }}"
dest: /home/app/.github_token
owner: app
group: app
mode: '0600'
- name: Send deployment notification to Slack
uri:
url: "{{ slack_webhook_url }}"
method: POST
body_format: json
body:
text: "Deployment to {{ inventory_hostname }} completed successfully!"
delegate_to: localhost
Final thoughts
Ansible Vault provides a powerful yet straightforward approach to securing sensitive data within your automation workflows.
By encrypting either entire files or individual variables, you can protect your secrets while still benefiting from the full capabilities of Ansible.
Thanks for reading!
Make your mark
Join the writer's program
Are you a developer and love writing and sharing your knowledge with the world? Join our guest writing program and get paid for writing amazing technical guides. We'll get them to the right readers that will appreciate them.
Write for us
Build on top of Better Stack
Write a script, app or project on top of Better Stack and share it with the world. Make a public repository and share it with us at our email.
community@betterstack.comor submit a pull request and help us build better products for everyone.
See the full list of amazing projects on github