Back to Linux guides

Ansible Vault: Securing Your Automation Secrets

Ayooluwa Isaiah
Updated on April 7, 2025

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:

  1. Simple implementation: Requires minimal additional setup as it's built into Ansible.
  2. Flexible encryption: Can encrypt entire files or individual variables.
  3. Secure storage: Allows sensitive data to be safely committed to version control.
  4. 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
Output
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

Ansible vault

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.

secret_vars.yml
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
Output
$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.

Ansible secrets

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

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:

  1. Prompt you for the vault password.
  2. Decrypt the file in memory (not on disk).
  3. Open the decrypted content in your default editor.
  4. 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

Viewing encrypted content

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:

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:

vault-pass.py
#!/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:

ansible.cfg
[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'
Output
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:

inventory.ini
[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!

Author's avatar
Article by
Ayooluwa Isaiah
Ayo is a technical content manager at Better Stack. His passion is simplifying and communicating complex technical ideas effectively. His work was featured on several esteemed publications including LWN.net, Digital Ocean, and CSS-Tricks. When he's not writing or coding, he loves to travel, bike, and play tennis.
Got an article suggestion? Let us know
Next article
Managing Secrets in Ansible Playbooks: A Comprehensive Guide
Learn how to securely manage sensitive information in Ansible playbooks using interactive prompts, Ansible Vault encryption, and integration with external secret management systems.
Licensed under CC-BY-NC-SA

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

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
Writer of the month
Marin Bezhanov
Marin is a software engineer and architect with a broad range of experience working...
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.com

or submit a pull request and help us build better products for everyone.

See the full list of amazing projects on github