Ansible Vault Tutorial: Encrypt Variables, Files and Passwords

Learn Ansible Vault to encrypt files and variables with create, view, edit, encrypt, decrypt, rekey, vault IDs, password options, and secure group_vars and host_vars usage.

Published

Updated

Read time 10 min read

Reviewed byDeepak Prasad

Ansible Vault commands for encrypted files, vault IDs, and encrypted variables on Rocky Linux

Ansible Vault is the built-in way to keep secrets out of plain-text YAML. You can encrypt structured data files used by Ansible, including group_vars, host_vars, files loaded through vars_files or include_vars, and variable files passed with -e @file.yml.

This guide walks through file and variable encryption end-to-end: create, view, edit, encrypt, decrypt, rekey, vault password handling, vault IDs, and practical layout for course labs. Use it with Ansible variables and project layout for complete secret management. For inventory layout with encrypted group_vars and host_vars, see Vault with group_vars and host_vars.

Tested on: Rocky Linux 10.2 (Red Quartz); kernel 6.12.0-211.16.1.el10_2.0.1.x86_64; ansible-core 2.16.16.

NOTE
This chapter is part of the GoLinuxCloud Ansible tutorial (RHCE EX294). Follow along from ~/ansible-project, inventory group lab, and playbooks in playbooks/. Use your own host names and paths if yours differ.
IMPORTANT
This article covers Ansible Vault for variable and data-file encryption in playbooks and inventory workflows. It does not cover external secret managers (HashiCorp Vault, cloud KMS, AAP credential plugins) in depth.


What is Ansible Vault?

Ansible Vault encrypts sensitive content so you can keep it in the same repository as playbooks without exposing raw secrets. The encrypted file stays readable by Git and review tools as ciphertext, and Ansible decrypts it at runtime when you provide a valid vault secret.

Use Vault for passwords, tokens, private keys, certificates, and app secrets that should never live in plain text.


Why Use Ansible Vault?

Without Vault, secrets leak easily through:

  • plain-text group_vars files committed to Git
  • copied snippets in tickets and chat
  • old backups and editor swap files

Vault reduces that risk while keeping your playbook workflow simple. Red Hat and Ansible docs explicitly treat plain-text credential storage as a security problem.


What Should You Encrypt with Ansible Vault?

Typical values to encrypt:

  • database passwords and API tokens
  • cloud access keys
  • TLS private key material
  • service account secrets
  • environment-specific confidential variables
  • password hashes for Linux accounts—see manage users, groups and sudo for the user module workflow

Do not encrypt everything by default. Keep non-secret values readable for easier review and debugging.


Ansible Vault Command Overview

Core commands you will use most:

Command Purpose
ansible-vault create Create a new encrypted file
ansible-vault view Read encrypted file contents
ansible-vault edit Edit encrypted files safely
ansible-vault encrypt Encrypt an existing plain-text file
ansible-vault decrypt Decrypt an encrypted file back to plain text
ansible-vault rekey Change vault password for encrypted content
ansible-vault encrypt_string Encrypt one variable value inline

Prepare Demo Vault Password Files

For the examples, create separate demo password files and keep them out of Git:

bash
printf 'old-demo-vault-pass\n' > .vault-pass
printf 'dev-demo-vault-pass\n' > .vault-dev.pass
printf 'prod-demo-vault-pass\n' > .vault-prod.pass
chmod 600 .vault-pass .vault-dev.pass .vault-prod.pass

These are lab examples only. In real projects, store vault password files outside the repository and manage access through your team’s approved secret process.


Create an Encrypted Vault File

Use create when you are starting a brand-new secret file.

bash
ansible-vault create created-vault.yml --vault-password-file .vault-dev.pass

With --vault-password-file, Ansible reads the password from that file, opens your default editor, and encrypts the saved content before writing it back to disk.

The file created in the test lab decrypts as:

bash
ansible-vault view created-vault.yml --vault-password-file .vault-dev.pass

Sample output:

output
api_token: created-via-create

View an Encrypted Vault File

view is the safest way to inspect encrypted content without writing a plain-text copy to disk.

For the next few examples, create a plain vars file first:

bash
cat > vars-plain.yml << 'EOF'
db_user: app
db_password: plaintext-pass
EOF

Then encrypt it:

bash
ansible-vault encrypt vars-plain.yml --vault-password-file .vault-pass
bash
ansible-vault view vars-plain.yml --vault-password-file .vault-pass

Sample output:

output
db_user: app
db_password: plaintext-pass

This command decrypts in memory for display only.


Edit an Encrypted Vault File

Use edit for routine secret changes. Ansible Vault decrypts temporarily, opens your editor, and re-encrypts on save.

bash
ansible-vault edit created-vault.yml --vault-password-file .vault-dev.pass

After editing in the test lab, the value changed to:

bash
ansible-vault view created-vault.yml --vault-password-file .vault-dev.pass

Sample output:

output
api_token: edited-value

Encrypt an Existing File

When you already have a plain-text vars file, encrypt it in place:

bash
cat > app-secrets.yml << 'EOF'
api_key: plain-api-key
api_secret: plain-api-secret
EOF
bash
ansible-vault encrypt app-secrets.yml --vault-password-file .vault-pass

encrypt modifies the file in place. After this command, app-secrets.yml is replaced by Vault ciphertext. Keep version control history or a secure backup if you need to audit the original content.


Decrypt an Encrypted File

Decrypt only when absolutely necessary.

bash
ansible-vault decrypt vars-plain.yml --vault-password-file .vault-pass

This writes plain text back to disk. Treat the file as exposed until you re-encrypt it:

bash
ansible-vault encrypt vars-plain.yml --vault-password-file .vault-pass

Change Vault Password with rekey

Rotate vault passwords without changing file contents:

bash
ansible-vault rekey vars-plain.yml --vault-password-file .vault-pass --new-vault-password-file .vault-dev.pass

Sample output:

output
Rekey successful

Use this after team access changes, credential rotation policies, or suspected compromise. After rekey, future commands for this file should use the new password source (for example .vault-dev.pass in this lab).


Use Vault Files in Playbooks

Vault files load like normal vars files. Only runtime secret handling changes.

playbook-vault.yml in the test lab:

yaml
---
- hosts: localhost
  connection: local
  gather_facts: false
  vars_files:
    - vars-plain.yml
  tasks:
    - ansible.builtin.debug:
        msg: "db_user={{ db_user }}"

Run with the vault password file:

bash
ansible-playbook playbook-vault.yml --vault-password-file .vault-dev.pass

Sample output:

output
PLAY [localhost] ***************************************************************

TASK [ansible.builtin.debug] ***************************************************
ok: [localhost] => {
    "msg": "db_user=app"
}
WARNING
Vault encrypts data at rest, not in task output. Avoid printing vaulted values with debug. Use no_log: true on tasks that handle passwords, tokens, or private keys.

Ansible Vault is not a full secrets manager—it protects files at rest in your repo, not rotation, audit trails, or fine-grained access control. At runtime, decrypted values can still appear in Ansible output when you run with high verbosity (-vvv or higher) or when modules echo arguments. Avoid ansible-playbook --diff on tasks that template or copy vaulted content carelessly; diff output can expose secrets in your terminal and logs. Pair Vault with no_log: true and external secret stores when requirements grow beyond course labs.


Encrypt Variables Instead of Whole Files

When only one value is sensitive, use encrypt_string and keep the rest of the file readable:

bash
ansible-vault encrypt_string --vault-password-file .vault-dev.pass --name 'vault_db_password' 'S3cret!Pass'

Sample output:

output
vault_db_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          30343034373663653265333835613366376562396462373065366534666161666532383732313236
          3732633434303261636564383033653138353234326237640a313131303361653862353339386539
          33326638353962313838313735306637366632366230336366643036663739643039663663643037
          3064373939326366300a616664323639653434376361663434336636386339343065363433353237
          3934

The --name value becomes the variable name. The encrypted block becomes its value. In playbooks and templates, you still reference it normally as {{ vault_db_password }} after supplying a vault password at runtime.


Vault Password Options

Use --ask-vault-pass

For interactive runs:

bash
ansible-playbook site.yml --ask-vault-pass

Best for ad hoc manual execution on trusted terminals.

Use --vault-password-file

For non-interactive CI/CD or repeatable local runs:

bash
ansible-playbook site.yml --vault-password-file .vault-dev.pass

Keep password files outside Git and chmod 600 them.

Use ANSIBLE_VAULT_PASSWORD_FILE

Set a runtime default to avoid repeating the CLI flag:

bash
ANSIBLE_VAULT_PASSWORD_FILE=.vault-dev.pass ansible-vault view created-vault.yml

Sample output:

output
api_token: created-via-create

You can also configure this path in ansible.cfg with vault_password_file.


Use Vault IDs

Why vault IDs are useful

Vault IDs label encrypted content by context such as dev, stage, or prod. They help organize multiple vault passwords and guide which secret Ansible should try first. If you need strict matching, enable vault_id_match in ansible.cfg.

ini
[defaults]
vault_id_match = true

Create encrypted content with a vault ID

Start with separate plain-text files per environment, then encrypt each one with its own label and password source.

bash
cat > dev-secrets.yml << 'EOF'
dev_token: DEV123
EOF

Now encrypt the dev file with the dev vault ID:

bash
ansible-vault encrypt dev-secrets.yml --vault-id [email protected]

Repeat for the production file:

bash
cat > prod-secrets.yml << 'EOF'
prod_token: PROD456
EOF
bash
ansible-vault encrypt prod-secrets.yml --vault-id [email protected]

Verify both files are encrypted and labeled:

bash
head -1 dev-secrets.yml

Sample output:

output
$ANSIBLE_VAULT;1.2;AES256;dev
bash
head -1 prod-secrets.yml

Sample output:

output
$ANSIBLE_VAULT;1.2;AES256;prod

The vault ID label (dev or prod) in the header helps Ansible choose which secret to try first at runtime.

Run playbooks with a vault ID

If your playbook only needs one environment secret file, pass one matching vault ID:

bash
ansible-playbook site.yml --vault-id [email protected]

Use multiple vault IDs

playbook-vault-ids.yml in the test lab loads both files:

yaml
---
- hosts: localhost
  connection: local
  gather_facts: false
  vars_files:
    - dev-secrets.yml
    - prod-secrets.yml
  tasks:
    - ansible.builtin.debug:
        msg: "dev={{ dev_token }} prod={{ prod_token }}"

Run with both IDs:

bash
ansible-playbook playbook-vault-ids.yml --vault-id [email protected] --vault-id [email protected]

Sample output:

output
TASK [ansible.builtin.debug] ***************************************************
ok: [localhost] => {
    "msg": "dev=DEV123 prod=PROD456"
}

Store Vault Files with group_vars and host_vars

A clean inventory layout:

text
inventory/
├── group_vars/
│   ├── all.yml
│   ├── web.yml
│   └── web_vault.yml         # ansible-vault encrypted
└── host_vars/
    ├── web1.yml
    └── web1_vault.yml        # ansible-vault encrypted

A common pattern is to keep non-secret values in web.yml and secrets in web_vault.yml. Both load for the same group, but only the vault file needs encryption.

yaml
# inventory/group_vars/web.yml
web_port: 8080
db_user: app
db_password: "{{ vault_db_password }}"
yaml
# inventory/group_vars/web_vault.yml
vault_db_password: !vault |
  ...

Keep naming explicit (*_vault.yml) so reviewers know files are expected to be encrypted.


Use Vault with ansible-playbook

ansible-playbook is the standard runtime path for Vault:

bash
ansible-playbook site.yml --ask-vault-pass

or

bash
ansible-playbook site.yml --vault-password-file .vault-dev.pass

For automation, prefer password files or vault IDs over manual prompts.


Use Vault with ansible-navigator

ansible-navigator can pass Vault options through to the underlying playbook run, but execution environments add one extra concern: the password file or environment variable must be available inside the execution environment.

For local or non-EE usage, pass the same playbook options you use with ansible-playbook:

bash
ansible-navigator run site.yml -- --vault-password-file .vault-dev.pass

For execution-environment workflows, prefer ANSIBLE_VAULT_PASSWORD_FILE and pass the environment variable into the run based on your navigator configuration.

In this test environment, ansible-navigator was not installed, so runtime behavior was validated with ansible-playbook.


Common Ansible Vault Mistakes

Mistake Impact Fix
Commit vault password files to Git Secrets exposed Add password files to .gitignore and use strict permissions
Decrypt a file and forget to re-encrypt Plain-text secrets in repo Re-encrypt immediately after edits
Encrypt non-secret values blindly Harder review and troubleshooting Encrypt only secret values or files
Mix vault IDs without naming discipline Wrong password at runtime Use clear labels (dev, prod) and matching filenames
Assume -e @file.yml is safe by default Plain-text secrets on disk Encrypt that vars file or switch to encrypt_string
No backup for vault password Permanent data loss risk Store recovery process in secure team docs

Common Vault Errors and Fixes

Error / symptom Likely cause Fix
Attempting to decrypt but no vault secrets found No vault password option passed Use --ask-vault-pass, --vault-password-file, or --vault-id
Decryption failed Wrong password or wrong vault ID Check the file header and password source
Playbook prompts for password in CI Interactive option used Use password file or vault ID in CI
Encrypted file starts with normal YAML File was never encrypted Run ansible-vault encrypt file.yml
Secret appears in output Task/debug printed decrypted value Avoid printing secrets; use no_log: true where needed

Ansible Vault Best Practices

  • Keep variable names readable even when values are encrypted.
  • Encrypt secrets only; keep structure and non-sensitive metadata plain.
  • Use vault IDs per environment and rotate with rekey.
  • Store password files outside repositories and lock permissions.
  • Prefer view and edit over manual decrypt/re-encrypt loops.
  • Audit CI jobs to ensure they never echo vault passwords.

For small Ansible labs:

  1. Keep base defaults in inventory/group_vars/all.yml.
  2. Put secrets in inventory/group_vars/lab_vault.yml encrypted with Vault.
  3. Use --vault-password-file ~/.vault_lab.pass locally.
  4. Add vault IDs only when splitting environments (dev and prod).
  5. Use encrypt_string for one-off secrets in otherwise readable files.

This keeps day-to-day tasks simple while preserving safe secret handling.


Summary

Ansible Vault secures secrets in playbook workflows by encrypting files or individual variable values. You can create, view, edit, encrypt, decrypt, and rekey vaulted content, then load it normally through vars_files, group_vars, host_vars, or -e @file.yml with runtime password options. Use vault IDs to separate environment secrets, keep password files out of Git, and encrypt only what is truly sensitive.


Frequently Asked Questions

1. What can Ansible Vault encrypt?

Ansible Vault can encrypt variable files, group_vars and host_vars files, files loaded by vars_files or include_vars, and individual values created with encrypt_string.

2. Should I encrypt full files or only variables?

Encrypt full files when most values are secrets. Use encrypt_string when only one or two values are sensitive and the rest should stay readable.

3. What is the safest way to pass vault passwords?

Use --ask-vault-pass for manual runs or --vault-password-file/ANSIBLE_VAULT_PASSWORD_FILE for automation, and keep password files out of Git.

4. Why should I use vault IDs?

Vault IDs let you separate secrets by environment such as dev and prod, each with its own password and label.

5. Can I recover data if I lose the vault password?

No. If you lose the vault password and have no backup, the encrypted content cannot be decrypted.

6. Does ansible-navigator work with vault passwords?

Yes. It passes through to ansible-playbook vault options and can use the same --vault-password-file or vault-id based runtime approach.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …