Report this

What is the reason for this report?

Use Ansible Vault to Protect Sensitive Playbook Data

Updated on June 29, 2026
Use Ansible Vault to Protect Sensitive Playbook Data

Introduction

Ansible Vault is a feature that allows you to encrypt values and data structures within Ansible projects. This provides the ability to secure any sensitive data that is necessary to successfully run Ansible plays but should not be publicly visible, such as passwords, API keys, or private keys. Ansible automatically decrypts vault-encrypted content at runtime when the correct password is provided.

In this guide, you will learn how Ansible Vault works under the hood, how to encrypt whole files and individual variables, how to supply the vault password to Ansible interactively or through a password file, and how to manage multiple vault passwords with vault IDs. You will also see how Ansible Vault compares with other approaches to secrets management. You will use a single Ansible control machine and no remote hosts are required. This guide was tested on an Ubuntu server, but the workflow is identical on any Linux distribution where Ansible is installed.

Key takeaways

  • Ansible Vault encrypts secrets at rest so you can keep sensitive and nonsensitive configuration data together in one project without exposing the secrets.
  • You can encrypt an entire file with ansible-vault encrypt, or encrypt a single value inline with ansible-vault encrypt_string, which is friendlier for shared repositories.
  • The ansible and ansible-playbook commands decrypt vault content automatically when given the password through --ask-vault-pass, a --vault-password-file, or the ANSIBLE_VAULT_PASSWORD_FILE environment variable.
  • A vault password file must be kept out of version control (add it to .gitignore) and locked down with chmod 600.
  • Vault IDs (the --vault-id label@source syntax) let you manage multiple passwords, such as separate secrets for development, staging, and production.
  • In CI/CD pipelines, store the vault password as a protected pipeline secret, write it to a temporary file at runtime, and remove that file after the run.
  • Ansible Vault protects data on disk only; once decrypted at runtime, secrets live in memory and can appear in verbose output or logs, so handle them carefully.
  • If you lose a vault password, the encrypted data cannot be recovered, which is why storing vault passwords in a dedicated password or secrets manager matters.
  • For large teams scaling their automation, an external secrets manager such as HashiCorp Vault can complement or replace Ansible Vault.

Prerequisites

To follow along, you will need an Ubuntu server with a non-root user with sudo privileges. You can follow our Initial Server Setup with Ubuntu guide to create a user with the appropriate permissions.

On the server, you will need to install and configure Ansible. You can follow our tutorial on installing Ansible on Ubuntu to install the appropriate packages. Continue with this guide when your server is configured with the above requirements.

What is Ansible Vault?

Ansible Vault is a mechanism that allows encrypted content to be incorporated transparently into Ansible workflows. A utility called ansible-vault secures confidential data, called secrets, by encrypting it on disk. To integrate these secrets with regular Ansible data, both the ansible and ansible-playbook commands, used for executing ad hoc tasks and structured playbooks respectively, support decrypting vault-encrypted content at runtime.

Vault is implemented with file-level granularity, meaning that individual files are either encrypted or unencrypted as a whole. It can also encrypt single values inline, which you will see later. Ansible identifies and decrypts any vault-encrypted content it finds while executing a playbook or task, as long as it has the right password.

Encryption algorithm and security model

Ansible Vault encrypts content with AES-256 in CTR mode and derives the encryption key from your password using PBKDF2 with HMAC-SHA256, run over 10,000 iterations with a 32-byte random salt, then authenticates the ciphertext with an HMAC-SHA256 digest. These are strong, industry-standard primitives, so in practice the security of a vault comes down to the strength of the password you choose and how carefully you store it. A short or reused password undermines otherwise solid cryptography.

It is equally important to understand what Ansible Vault does not protect against. Vault secures data only while it sits on disk. Once Ansible decrypts a secret to use it during a run, that value exists in memory as an ordinary variable and can appear in verbose output (for example, when you run with -vvv), in task results, or in logs if you are not careful. Vault also has no per-user access control beyond the shared password: anyone with the password can read everything that password protects. Treat it as encryption at rest, not as a complete secrets-management platform.

Now that you understand what Vault is and how it secures data, you can start using the tools Ansible provides.

Setting the Ansible Vault editor

Before using the ansible-vault command, it is a good idea to specify your preferred text editor. Several of Vault’s commands open an editor to manipulate the contents of an encrypted file. Ansible reads the EDITOR environment variable to find your preferred editor, and if it is unset, it defaults to vi.

If you do not want to edit with the vi editor, set the EDITOR variable in your environment.

Note: If you find yourself within a vi session accidentally, you can exit by pressing the Esc key, typing :q!, and then pressing Enter. If you are not familiar with vi, any changes you make are likely to be unintentional, so this command exits without saving.

To set the editor for a single command, prepend the command with the environment variable assignment, like this:

  1. EDITOR=nano ansible-vault . . .

To make this persistent, open your ~/.bashrc file:

  1. nano ~/.bashrc

Specify your preferred editor by adding an EDITOR assignment to the end of the file:

~/.bashrc
export EDITOR=nano

Save and close the file when you are finished, then source the file again to read the change into the current session:

  1. . ~/.bashrc

Display the EDITOR variable to check that your setting was applied:

  1. echo $EDITOR

The command prints the editor you set:

Output
nano

Now that you have established your preferred editor, you can explore the operations available with the ansible-vault command.

Managing sensitive files with ansible-vault

The ansible-vault command is the main interface for managing encrypted content within Ansible. You use it to initially encrypt files and then to view, edit, rekey, or decrypt the data. The following subsections walk through each operation.

Creating new encrypted files

To create a new file encrypted with Vault, use the ansible-vault create command and pass in the name of the file you wish to create. For example, to create an encrypted YAML file called vault.yml to store sensitive variables, type the following:

  1. ansible-vault create vault.yml

You are prompted to enter and confirm a password:

Output
New Vault password: 
Confirm New Vault password:

When you have confirmed your password, Ansible immediately opens an editing window where you can enter your desired contents. To test the encryption, enter some sample text:

vault.yml
Secret information

Ansible encrypts the contents when you close the file. If you check the file, instead of the words you typed, you see an encrypted block:

  1. cat vault.yml

The file now contains a Vault header followed by the encrypted payload:

Output
$ANSIBLE_VAULT;1.1;AES256
65316332393532313030636134643235316439336133363531303838376235376635373430336333
3963353630373161356638376361646338353763363434360a363138376163666265336433633664
30336233323664306434626363643731626536643833336638356661396364313666366231616261
3764656365313263620a383666383233626665376364323062393462373266663066366536306163
31643731343666353761633563633634326139396230313734333034653238303166

The header tells Ansible how to handle the file, and it is followed by the encrypted contents, which display as hexadecimal digits.

Encrypting existing files

If you already have a file that you wish to encrypt with Vault, use the ansible-vault encrypt command instead. For testing, create an example file:

  1. echo 'unencrypted stuff' > encrypt_me.txt

Now encrypt the existing file:

  1. ansible-vault encrypt encrypt_me.txt

Again, you are prompted to provide and confirm a password, after which a message confirms the encryption:

Output
New Vault password: 
Confirm New Vault password:
Encryption successful

Instead of opening an editing window, ansible-vault encrypts the contents of the file and writes it back to disk, replacing the unencrypted version. If you check the file, you see a similar encrypted pattern:

  1. cat encrypt_me.txt

The output shows the same Vault header and encrypted body as a newly created file:

Output
$ANSIBLE_VAULT;1.1;AES256
66633936653834616130346436353865303665396430383430353366616263323161393639393136
3737316539353434666438373035653132383434303338640a396635313062386464306132313834
34313336313338623537333332356231386438666565616537616538653465333431306638643961
3636663633363562320a613661313966376361396336383864656632376134353039663662666437
39393639343966363565636161316339643033393132626639303332373339376664

As you can see, Ansible encrypts existing content in much the same way as it encrypts new files.

Viewing encrypted files

Sometimes you need to reference the contents of a vault-encrypted file without editing it or writing it to the filesystem unencrypted. The ansible-vault view command feeds the contents of a file to standard output, which by default displays them in the terminal. Pass the vault-encrypted file to the command:

  1. ansible-vault view vault.yml

You are asked for the file’s password, and after entering it successfully the contents are displayed:

Output
Vault password:
Secret information

The password prompt is mixed into the output of the file contents, so keep this in mind when using ansible-vault view in automated processes.

Editing encrypted files

When you need to edit an encrypted file, use the ansible-vault edit command:

  1. ansible-vault edit vault.yml

You are prompted for the file’s password, and after entering it, Ansible opens the file in an editing window where you can make any necessary changes. Upon saving, the new contents are encrypted again with the file’s password and written to disk.

Manually decrypting encrypted files

To decrypt a vault-encrypted file, use the ansible-vault decrypt command.

Note: Because of the increased likelihood of accidentally committing sensitive data to your project repository, the ansible-vault decrypt command is best reserved for when you want to remove encryption from a file permanently. If you only need to view or edit a vault-encrypted file, use ansible-vault view or ansible-vault edit instead.

Pass in the name of the encrypted file:

  1. ansible-vault decrypt vault.yml

You are prompted for the encryption password, and once you enter the correct one, the file is decrypted:

Output
Vault password:
Decryption successful

If you view the file again, you see the actual contents instead of the encrypted block:

  1. cat vault.yml

The file is now plain text on disk:

Output
Secret information

Your file is now unencrypted on disk, so be sure to remove any sensitive information or re-encrypt the file when you are finished.

Changing the password of encrypted files

If you need to change the password of an encrypted file, use the ansible-vault rekey command:

  1. ansible-vault rekey encrypt_me.txt

When you enter the command, you are first prompted for the file’s current password:

Output
Vault password:

After entering it, you are asked to select and confirm a new vault password:

Output
Vault password:
New Vault password:
Confirm New Vault password:

When you have successfully confirmed a new password, you receive a message indicating the re-encryption succeeded:

Output
Rekey successful

The file is now accessible using the new password, and the old password no longer works.

Encrypting individual variables with ansible-vault encrypt_string

Encrypting an entire file is useful, but it has a drawback for shared projects: a reviewer cannot see which variables a file defines without decrypting it. The ansible-vault encrypt_string command solves this by encrypting a single value inline, so you can keep one readable variables file where most values are plain text and only the sensitive ones are encrypted.

To encrypt a value and assign it a variable name, run the command and pass the value along with the --name flag:

  1. ansible-vault encrypt_string 'supersecretpassword' --name 'mysql_password'

You are prompted for a vault password, and then Ansible prints a ready-to-paste YAML snippet:

Output
New Vault password: 
Confirm New Vault password: 
mysql_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          39613463343766353861393236363232383831356636373033386230623261306566653034643865
          6566383437333436353331353764633033366563343631380a316234383...
Encryption successful

You can paste that block directly into a regular variables file, mixing encrypted and unencrypted values in one place:

vars.yml
---
# nonsensitive data
mysql_port: 3306
mysql_host: 10.0.0.3
mysql_user: fred

# sensitive data, encrypted inline
mysql_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          39613463343766353861393236363232383831356636373033386230623261306566653034643865
          6566383437333436353331353764633033366563343631380a316234383...

The !vault tag tells Ansible that the value is encrypted and should be decrypted at runtime. This approach keeps variable names visible in code review while protecting only the secret values, which is why it is often preferred over encrypting whole files in collaborative repositories.

Running Ansible with vault-encrypted files

After you encrypt your sensitive information with Vault, you can use the files with Ansible’s conventional tooling. The ansible and ansible-playbook commands both know how to decrypt vault-protected content given the correct password, and there are a few different ways to provide that password depending on your needs.

To follow along, you need a vault-encrypted file. Create one with the following:

  1. ansible-vault create secret_key

Select and confirm a password, then fill in whatever dummy contents you want:

secret_key
confidential data

Save and close the file. Next, create a temporary hosts file to act as an inventory:

  1. nano hosts

Add just the Ansible localhost to it. To prepare for a later step, place it in the [database] group:

hosts
[database]
localhost ansible_connection=local

Save and close the file. Now create an ansible.cfg file in the current directory if one does not already exist:

  1. nano ansible.cfg

For now, add a [defaults] section and point Ansible to the inventory you just created:

ansible.cfg
[defaults]
inventory = ./hosts

When you are ready, continue on to the different ways of supplying a password.

Using an interactive prompt

The most straightforward way to decrypt content at runtime is to have Ansible prompt you for the password. Add the --ask-vault-pass flag to any ansible or ansible-playbook command, and Ansible will prompt you for a password to use when it encounters vault-protected content.

For example, to copy the contents of a vault-encrypted file to a host, you could use the copy module with the --ask-vault-pass flag. If the file contains real sensitive data, you most likely want to lock down access on the remote host with permission and ownership restrictions.

Note: This example uses localhost as the target host to minimize the number of servers required, but the results are the same as if the host were truly remote.

  1. ansible --ask-vault-pass -bK -m copy -a 'src=secret_key dest=/tmp/secret_key mode=0600 owner=root group=root' localhost

The task specifies that the file’s ownership should change to root, so administrative privileges are required. The -bK flag tells Ansible to prompt for the sudo (become) password on the target host, so you are asked for that first, then for the Vault password:

Output
BECOME password:
Vault password:

When the passwords are provided, Ansible executes the task, using the Vault password for any encrypted files it finds. Keep in mind that all files referenced during a single execution must use the same password:

Output
localhost | SUCCESS => {
    "changed": true, 
    "checksum": "7a2eb5528c44877da9b0250710cba321bc6dac2d", 
    "dest": "/tmp/secret_key", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "270ac7da333dd1db7d5f7d8307bd6b41", 
    "mode": "0600", 
    "owner": "root", 
    "size": 18, 
    "src": "/home/sammy/.ansible/tmp/ansible-tmp-1480978964.81-196645606972905/source", 
    "state": "file", 
    "uid": 0
}

Prompting for a password is secure, but it can be tedious on repeated runs and it hinders automation, so the next sections cover alternatives.

Using a vault password file

If you do not want to type the Vault password each time, you can store it in a file and reference that file during execution. For example, put your password in a .vault_pass file:

  1. echo 'my_vault_password' > .vault_pass

Note: A vault password file is as sensitive as the password itself. Restrict its permissions so only your user can read it, and never commit it to version control.

Lock down the file so that only your user can read it, then, if you use version control, add it to your ignore file so you do not commit it by accident:

  1. chmod 600 .vault_pass
  2. echo '.vault_pass' >> .gitignore

Now reference the file with the --vault-password-file flag. You can complete the same task from the last section without an interactive Vault prompt:

  1. ansible --vault-password-file=.vault_pass -bK -m copy -a 'src=secret_key dest=/tmp/secret_key mode=0600 owner=root group=root' localhost

You are not prompted for the Vault password this time:

Output
localhost | SUCCESS => {
    "changed": false,
    "checksum": "52d7a243aea83e6b0e478db55a2554a8530358b0",
    "dest": "/tmp/secret_key",
    "gid": 0,
    "group": "root",
    "mode": "0600",
    "owner": "root",
    "path": "/tmp/secret_key",
    "size": 8,
    "state": "file",
    "uid": 0
}

Reading the password file automatically

To avoid providing a flag at all, set the ANSIBLE_VAULT_PASSWORD_FILE environment variable with the path to the password file:

  1. export ANSIBLE_VAULT_PASSWORD_FILE=./.vault_pass

You can now run the command without the --vault-password-file flag for the current session:

  1. ansible -bK -m copy -a 'src=secret_key dest=/tmp/secret_key mode=0600 owner=root group=root' localhost

To make Ansible aware of the password file location across sessions, edit your ansible.cfg file. Open the local ansible.cfg you created earlier:

  1. nano ansible.cfg

In the [defaults] section, set the vault_password_file option to the location of your password file. This can be a relative or absolute path, whichever is most useful for you:

ansible.cfg
[defaults]
. . .
vault_password_file = ./.vault_pass

Now, when you run commands that require decryption, you are no longer prompted for the vault password. As a bonus, ansible-vault also uses the password in the file automatically when creating new files with ansible-vault create or encrypting existing ones with ansible-vault encrypt.

Reading the password from an environment variable

You may worry about accidentally committing your password file to your repository. While Ansible has an environment variable that points to the location of a password file, it does not have one for setting the password value itself. However, if your password file is executable, Ansible runs it as a script and uses the resulting output as the password. The following short script reads the password from an environment variable instead of storing it on disk.

Open your .vault_pass file in your editor:

  1. nano .vault_pass

Replace the contents with the following script. Note the parentheses on print(), which are required in Python 3:

.vault_pass
#!/usr/bin/env python3

import os
print(os.environ['VAULT_PASSWORD'])

Make the file executable:

  1. chmod +x .vault_pass

You can then set and export the VAULT_PASSWORD environment variable, which is available for your current session:

  1. export VAULT_PASSWORD=my_vault_password

You have to do this at the beginning of each Ansible session, which may sound inconvenient. However, it effectively guards against accidentally committing your Vault password, since the password itself is never written to disk. This pattern is also the foundation of the CI/CD approach described later.

Working with multiple vault passwords

As projects grow, a single password rarely fits every secret. You often want separate passwords for development, staging, and production, so that a developer with the dev password cannot decrypt production secrets. Ansible handles this with vault IDs, which attach a label to each password.

A vault ID uses the syntax label@source, where source is either a password file or the keyword prompt. For example, to encrypt a string with a production vault ID and be prompted for the password, run the following:

  1. ansible-vault encrypt_string --vault-id prod@prompt 'RealProductionPassword' --name 'vault_db_password'

When you use a labeled vault ID, the label is recorded in the encrypted block’s header, which changes from version 1.1 to 1.2 and includes the label:

Output
$ANSIBLE_VAULT;1.2;AES256;prod

When you run a playbook, you can supply several vault IDs at once, and Ansible tries each one as needed. The following passes a development password from a file and prompts for the production password:

  1. ansible-playbook site.yml --vault-id dev@dev_pass --vault-id prod@prompt

When decrypting, Ansible tries the password whose label matches the encrypted content first, then falls back to trying the others in the order you provided them. Vault IDs are most useful when you separate secrets by environment, when different team members hold different passwords, or when you rotate one environment’s password without touching the others.

Using vault-encrypted variables with regular variables

While Ansible Vault can encrypt arbitrary files, it is most frequently used to protect sensitive variables. This section works through an example that transforms a regular variables file into a configuration that balances security and usability. It complements the inline encrypt_string approach shown earlier by splitting secrets into a separate encrypted file.

Setting up the example

For this example, pretend you are configuring a database server, without actually installing a database. When you created the hosts file earlier, you placed the localhost entry in a group called database to prepare for this step. Databases usually require a mixture of sensitive and nonsensitive variables, which you can assign in a group_vars directory in a file named after the group:

  1. mkdir -p group_vars
  2. nano group_vars/database.yml

Inside the group_vars/database.yml file, add some typical variables. Some, like the MySQL port number, are not secret and can be freely shared, while others, like the database password, are confidential:

group_vars/database.yml
---
# nonsensitive data
mysql_port: 3306
mysql_host: 10.0.0.3
mysql_user: fred

# sensitive data
mysql_password: supersecretpassword

You can test that all of the variables are available to your host with Ansible’s debug module and the hostvars variable:

  1. ansible -m debug -a 'var=hostvars[inventory_hostname]' database

The output confirms that every variable you defined is applied to the host:

Output
localhost | SUCCESS => {
    "hostvars[inventory_hostname]": {
        "ansible_check_mode": false, 
        "ansible_version": {
            "full": "2.18.1", 
            "major": 2, 
            "minor": 18, 
            "revision": 1, 
            "string": "2.18.1"
        }, 
        "group_names": [
            "database"
        ], 
        "groups": {
            "all": [
                "localhost"
            ], 
            "database": [
                "localhost"
            ], 
            "ungrouped": []
        }, 
        "inventory_dir": "/home/sammy", 
        "inventory_file": "hosts", 
        "inventory_hostname": "localhost", 
        "inventory_hostname_short": "localhost", 
        "mysql_host": "10.0.0.3",
        "mysql_password": "supersecretpassword",
        "mysql_port": 3306,
        "mysql_user": "fred",
        "omit": "__omit_place_holder__1c934a5a224ca1d235ff05eb9bda22044a6fb400", 
        "playbook_dir": "."
    }
}

The output confirms that all of the variables are applied to the host. However, the group_vars/database.yml file currently holds all of the variables together. This means you can either leave it unencrypted, which is a security concern because of the database password, or encrypt all of the variables, which creates usability and collaboration problems.

Moving sensitive variables into Ansible Vault

To solve this, make a distinction between sensitive and nonsensitive variables so you can encrypt confidential values while still easily sharing the rest. To do so, split the variables between two files.

You can use a variable directory in place of a variable file to apply variables from more than one file. First, rename the existing file from database.yml to vars.yml, which will be your unencrypted variable file:

  1. mv group_vars/database.yml group_vars/vars.yml

Next, create a directory with the same name as the old variable file, and move the vars.yml file inside it:

  1. mkdir group_vars/database
  2. mv group_vars/vars.yml group_vars/database/

You now have a variable directory for the database group instead of a single file, plus one unencrypted variable file. Since you will be encrypting your sensitive variables, remove them from the unencrypted file. Edit group_vars/database/vars.yml to remove the confidential data:

  1. nano group_vars/database/vars.yml

In this case, remove the mysql_password variable so the file looks like this:

group_vars/database/vars.yml
---
# nonsensitive data
mysql_port: 3306
mysql_host: 10.0.0.3
mysql_user: fred

Next, create a vault-encrypted file in the directory that will live alongside the unencrypted vars.yml file:

  1. ansible-vault create group_vars/database/vault.yml

In this file, define the sensitive variables that used to be in the vars.yml file. Use the same variable names, but prepend the string vault_ to indicate that these variables are defined in the vault-protected file:

group_vars/database/vault.yml
---
vault_mysql_password: supersecretpassword

Save and close the file. The resulting directory structure looks like this:

.
├── . . .
├── group_vars/
│   └── database/
│       ├── vars.yml
│       └── vault.yml
└── . . .

At this point, the variables are separate and only the confidential data is encrypted. This is secure, but it has reduced usability: while the goal was to protect sensitive values, you have also unintentionally hidden the variable names. It is not clear which variables are assigned without referencing more than one file, and you probably still want to share the variable names even while restricting access to the values. To address this, the Ansible project recommends a slightly different approach.

Referencing vault variables from unencrypted variables

When you moved the sensitive data to the vault-protected file, you prefaced the variable names with vault_, so mysql_password became vault_mysql_password. You can add the original variable names back to the unencrypted file and, instead of setting them to sensitive values directly, use Jinja2 templating to reference the encrypted variables. This way, you can see all of the defined variables in a single file, while the confidential values remain in the encrypted file.

Open the unencrypted variables file again:

  1. nano group_vars/database/vars.yml

Add the mysql_password variable again, this time using Jinja2 templating to reference the variable defined in the vault-protected file:

group_vars/database/vars.yml
---
# nonsensitive data
mysql_port: 3306
mysql_host: 10.0.0.3
mysql_user: fred

# sensitive data
mysql_password: "{{ vault_mysql_password }}"

The mysql_password variable is set to the value of vault_mysql_password, which is defined in the vault file. With this method, you can understand all of the variables that apply to hosts in the database group by viewing the group_vars/database/vars.yml file, while the sensitive parts stay obscured behind the Jinja2 reference. You only need to open group_vars/database/vault.yml when the values themselves need to be viewed or changed.

You can check that all of the mysql_* variables are still correctly applied using the same method as before.

Note: If your Vault password is not being applied automatically through a password file, add the --ask-vault-pass flag to the command below.

  1. ansible -m debug -a 'var=hostvars[inventory_hostname]' database

The output shows both variables resolving to the same secret value:

Output
localhost | SUCCESS => {
    "hostvars[inventory_hostname]": {
        "ansible_check_mode": false, 
        "ansible_version": {
            "full": "2.18.1", 
            "major": 2, 
            "minor": 18, 
            "revision": 1, 
            "string": "2.18.1"
        }, 
        "group_names": [
            "database"
        ], 
        "groups": {
            "all": [
                "localhost"
            ], 
            "database": [
                "localhost"
            ], 
            "ungrouped": []
        }, 
        "inventory_dir": "/home/sammy/vault", 
        "inventory_file": "./hosts", 
        "inventory_hostname": "localhost", 
        "inventory_hostname_short": "localhost", 
        "mysql_host": "10.0.0.3",
        "mysql_password": "supersecretpassword",
        "mysql_port": 3306,
        "mysql_user": "fred",
        "omit": "__omit_place_holder__6dd15dda7eddafe98b6226226c7298934f666fc8", 
        "playbook_dir": ".", 
        "vault_mysql_password": "supersecretpassword"
    }
}

Both vault_mysql_password and mysql_password are accessible, and this duplication is harmless and will not affect your use of the system.

Ansible Vault compared with environment variables and external secrets managers

Ansible Vault is not the only way to handle secrets in automation, and choosing the right tool depends on your team size, your workflow, and how your secrets are consumed. The following table compares the three most common approaches.

Method Encryption at rest Safe to commit to version control CI/CD friendly Complexity
Ansible Vault Yes (AES-256) Yes (encrypted files only) Yes, with a password injected at runtime Low
Plain environment variables No No (never commit secrets) Yes, via pipeline secrets Very low
External secrets manager Yes, with rotation and auditing Yes (no secret stored in repo) Yes, via API or plugin High

Ansible Vault is the best fit when you want secrets encrypted at rest and stored alongside your playbooks in the same repository, which suits small to mid-sized teams and infrastructure-as-code workflows. Plain environment variables are simplest for a single secret consumed at runtime, but they offer no encryption at rest and must never be committed. An external secrets manager is the strongest option for large organizations that need centralized rotation, fine-grained access control, and audit logging, at the cost of additional infrastructure to run and integrate. Many teams combine approaches, for example using Ansible Vault for project-level secrets and an external manager for organization-wide credentials.

Best practices for managing secrets with Ansible Vault

A few habits keep a vault-based workflow both secure and maintainable:

  • Keep the vault password file outside version control and restrict it with chmod 600, and add unencrypted secret files to .gitignore so they are never committed.

  • Prefer ansible-vault encrypt_string for individual values in shared repositories so reviewers can still see variable names, and reserve whole-file encryption for files that are entirely sensitive.

  • Use a clear naming convention, such as the vault_ prefix, so it is obvious which variables come from an encrypted source.

  • Separate vault IDs by environment (for example dev, staging, and prod) so that access to one environment’s secrets does not grant access to another’s.

  • Rotate vault passwords on a defined schedule using ansible-vault rekey, and rotate immediately if a password may have been exposed.

  • Store the vault passwords themselves in a dedicated password manager or secrets manager, because losing a vault password means the encrypted data cannot be recovered.

  • Use no_log: true on any task that handles a decrypted secret to prevent the value from appearing in task output, logs, or Ansible Tower / AWX job results. For example:

    - name: Create database user
    community.mysql.mysql_user:
        name: "{{ mysql_user }}"
        password: "{{ mysql_password }}"
        state: present
    no_log: true
    

    Vault protects data on disk; no_log protects it at runtime. Both controls together give you defense in depth.

  • Although ansible-vault encrypt works on any file including entire playbooks, whole-playbook encryption is rarely practical in team settings because it prevents anyone from reading the task list without decrypting it first. Prefer encrypting only the variables files that contain secrets, and keep your playbooks in plain text.

FAQs

1. Can you use Ansible Vault to store sensitive information?

Yes, Ansible Vault is designed specifically to store sensitive information such as passwords, API keys, private keys, and TLS certificates by encrypting them at rest. It is appropriate for any secret you need available during a playbook run but do not want visible in plain text in your repository. Keep in mind what it does not protect: once Ansible decrypts a value at runtime, that value exists in memory as a normal variable and can appear in verbose output or logs, so it secures data on disk rather than during execution.

2. How do you encrypt a file with Ansible Vault?

Run ansible-vault encrypt filename.yml to encrypt an existing file, or ansible-vault create filename.yml to create and encrypt a new one. In both cases Ansible prompts you to enter and confirm a vault password, then writes the encrypted content back to disk in place of the original. You can confirm the result with cat filename.yml, which shows the $ANSIBLE_VAULT header followed by the encrypted payload instead of your plain text.

3. How secure is Ansible Vault?

Ansible Vault uses AES-256 encryption in CTR mode and derives its key from your password with PBKDF2 using HMAC-SHA256 over 10,000 iterations, which are strong, industry-standard algorithms. Because the key is derived directly from your password, the real-world security depends on choosing a long, unique password and storing it safely rather than on the algorithm. Vault protects data at rest only, so it does not prevent a decrypted secret from being exposed in memory, logs, or verbose output during a run.

4. Which feature should you use to securely manage sensitive data such as passwords in your Ansible playbook?

Ansible Vault is the built-in feature for securely managing sensitive data such as passwords in your playbooks. It encrypts secrets at rest and integrates directly with the ansible and ansible-playbook commands, which decrypt the content automatically at runtime when you supply the password. For organization-wide credential management with rotation and auditing, you can complement Vault with an external secrets manager such as HashiCorp Vault.

5. What is the difference between ansible-vault encrypt and ansible-vault encrypt_string?

ansible-vault encrypt encrypts an entire file, so the whole file becomes an opaque encrypted block, while ansible-vault encrypt_string encrypts a single value and returns an inline YAML snippet you can paste into an otherwise plain-text variables file. Use whole-file encryption when a file contains only secrets, and use encrypt_string when you want most variables to stay readable and only specific values encrypted. The inline approach is generally friendlier for code review in shared repositories.

6. How do you use a vault password file instead of typing a password interactively?

Save the password in a file and reference it with the --vault-password-file flag, for example ansible-playbook site.yml --vault-password-file .vault_pass, or set the ANSIBLE_VAULT_PASSWORD_FILE environment variable to the file’s path so you do not need the flag. You can also set vault_password_file in the [defaults] section of ansible.cfg to make it the default. In every case, restrict the file with chmod 600 and add it to .gitignore so it is never readable by others or committed to version control.

7. Can Ansible Vault be used in CI/CD pipelines?

Yes, Ansible Vault works well in CI/CD pipelines. Store the vault password as a protected pipeline secret (for example, a masked CI/CD variable), then have the pipeline write it to a temporary file at the start of the run, pass that file with --vault-password-file, and delete the file when the run finishes. This keeps the password out of the repository and out of the build logs while still allowing fully automated, unattended playbook runs.

Here is an example GitHub Actions step:

- name: Run playbook
  env:
    VAULT_PASSWORD: ${{ secrets.VAULT_PASSWORD }}
  run: |
    echo "$VAULT_PASSWORD" > .vault_pass
    chmod 600 .vault_pass
    ansible-playbook site.yml --vault-password-file .vault_pass
    rm -f .vault_pass

For GitLab CI, the pattern is equivalent: set VAULT_PASSWORD as a masked CI/CD variable in your project settings and reference it the same way. Always delete the temporary file in the same step so it is removed even if the playbook fails.

8. What happens if you lose your Ansible Vault password?

If you lose a vault password, the data encrypted with it cannot be recovered, because the password is required to derive the decryption key and there is no backdoor or recovery mechanism. Your only options are to restore the original unencrypted data from another source or recreate the secrets. To avoid this situation, store vault passwords in a dedicated password manager or secrets manager, and consider rekeying important vaults on a schedule so the current password is always known and backed up.

Conclusion

In this guide, you learned how Ansible Vault encrypts data with AES-256. You also learned how to encrypt both whole files and individual variables, how to supply vault passwords interactively or through password files and environment variables, how to manage multiple passwords with vault IDs, and how Vault compares with other secrets-management approaches. With these tools, you can keep all of your configuration data in one place without compromising security.

To keep building your Ansible skills, explore these related DigitalOcean tutorials:

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the author(s)

Justin Ellingwood
Justin Ellingwood
Author
See author profile

Former Senior Technical Writer at DigitalOcean, specializing in DevOps topics across multiple Linux distributions, including Ubuntu 18.04, 20.04, 22.04, as well as Debian 10 and 11.

Manikandan Kurup
Manikandan Kurup
Editor
Senior Technical Content Engineer I
See author profile

With over 6 years of experience in tech publishing, Mani has edited and published more than 75 books covering a wide range of data science topics. Known for his strong attention to detail and technical knowledge, Mani specializes in creating clear, concise, and easy-to-understand content tailored for developers.

Still looking for an answer?

Was this helpful?


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Hey Justin, is there a best practice key length for the ansible vault pass? If so, what is it? Between 12-16 characters, etc?

Hey, This has been very good and interesting article. I am recently looking for similar kind of solution that can hold my Database, API credentials encrypted (instead of I write them directly in my application code). Will this solution help me? I have posted my question here in detail: https://www.digitalocean.com/community/questions/how-to-secure-important-credentials-used-in-node-js-application-code-in-separate-side-utility?answer=39512

Is it possible to use ansible-vault module instead of configuring whole Ansible platform? As it seems quite big system that I notice here: https://www.ansible.com/

What are your recommendations on it in reference to my specific need.

This comment has been deleted

Hi Justin,

At the last part ‘Referencing Vault Variables from Unencrypted Variables’, can we add lots of dictionary of keys and value(passwords) in vault file and reference them in vars ?

Creative CommonsThis work is licensed under a Creative Commons Attribution-NonCommercial- ShareAlike 4.0 International License.
Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Start building today

From GPU-powered inference and Kubernetes to managed databases and storage, get everything you need to build, scale, and deploy intelligent applications.