Skip to main content
RunBook Academy

AnsibleXXI · Secrets ManagementSecrets management

Vault file operations

Intermediate⏱ ~22 minansible-core

What you'll learn

  • Read a vault header line and say which format version and which label produced it
  • Choose between view, edit and decrypt by what each one leaves on disk
  • Use encrypt, rekey and the output option correctly, including their file mode behaviour
  • Lay out a repository so that encrypted and reviewable content are separate files

Prerequisites

Verified against ansible-core 2.21.x · ansible (community package) 14.x · Python (controller) 3.12+ · ansible-lint 26.x · Molecule 26.x · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL / Rocky / AlmaLinux 9.x · 2026-08-11

Not yet marked complete on this device.

Ansible Vault is a file encryption tool with seven subcommands and one idea: a file in your repository is encrypted at rest, and Ansible decrypts it in memory when it needs the values.

Read-only / Safethe whole surface
$ ansible-vault --help
usage: ansible-vault [-h] [--version] [-v]
                   {create,decrypt,edit,view,encrypt,encrypt_string,rekey} ...

encryption/decryption utility for Ansible data files

positional arguments:
  create              Create new vault encrypted file
  decrypt             Decrypt vault encrypted file or string
  edit                Edit vault encrypted file
  view                View vault encrypted file
  encrypt             Encrypt YAML file
  encrypt_string      Encrypt a string
  rekey               Re-key a vault encrypted file

This lesson covers six of them. encrypt_string gets its own lesson, because it addresses a different problem — reviewability — and the argument for it is worth making properly.

The header line is metadata

Read-only / Safeencrypt, then read the first line
$ ansible-vault encrypt --vault-password-file .dev-pass plain.yml; head -2 plain.yml
Encryption successful
$ANSIBLE_VAULT;1.1;AES256
64333130303835376533306363613666313538636639353831363762356335383962643232363539

Four fields, semicolon-separated, and every one of them is readable by anyone who can read the file:

FieldMeaning
$ANSIBLE_VAULTthe magic string that tells Ansible this file is encrypted
1.1envelope format version
AES256the cipher
(absent here)the vault ID label, when one was used

Encrypt the same content under a labelled vault ID and the header changes:

Read-only / Safethe same file, encrypted under a label
$ ansible-vault encrypt --vault-id prod@.prod-pass prod-secrets.yml; head -1 prod-secrets.yml
$ANSIBLE_VAULT;1.2;AES256;prod

1.2 is the format that carries a label; 1.1 is the format that does not. So the version field is not a quality signal and there is nothing to upgrade — a 1.1 file is simply one encrypted without a vault ID. The labels are the subject of a later lesson in this part.

view and edit: the two you should be using

Read-only / Saferead without writing anything
$ ansible-vault view --vault-password-file .dev-pass plain.yml
db_password: REPLACE_ME
api_token: REDACTED

view decrypts to standard output. Nothing is written.

edit decrypts to a temporary file, opens your $EDITOR, and re-encrypts on save. The window in which plaintext exists on disk is the duration of your editing session, in a temporary file, and it is cleaned up afterwards.

decrypt: what it does, and why the answer is usually no

Configuration changethis replaces the encrypted file with plaintext
$ ansible-vault decrypt --vault-password-file .dev-pass plain.yml; cat plain.yml
Decryption successful
db_password: REPLACE_ME
api_token: REDACTED

The file is now plaintext, in your working tree, one git add . away from being committed — and the previous lesson covered what a committed credential costs to undo.

Everything people reach for decrypt to do has a better answer:

What you wantedUse this instead
Read the valuesansible-vault view
Change a valueansible-vault edit
Change the passwordansible-vault rekey
Feed a value to another programansible-vault view file | your-program
Diff two vault filesdecrypt both to stdout with --output - and diff those
Stop using Vault for this filedecrypt — this is the real use

The legitimate case is retiring Vault for a file, usually because the content turned out not to be secret or because it is moving to an external secret manager. That is a deliberate, reviewed, one-time act. It is not a step in a debugging session.

encrypt, create and rekey

Configuration changethe three that write
# Encrypt an existing plaintext file in place
ansible-vault encrypt --vault-id prod@prompt group_vars/prod/vault.yml

# Create a new encrypted file directly - never exists as plaintext on disk
ansible-vault create --vault-id prod@prompt group_vars/prod/vault.yml

# Change the password without changing the content
ansible-vault rekey --vault-id prod@prompt \
--new-vault-id prod@prompt group_vars/prod/vault.yml

create is the better habit when the content is new. encrypt requires the plaintext to exist first, which means it existed on disk, which means the question from the previous callout applies. create opens an editor on an empty buffer and writes only the encrypted result.

It needs a terminal, which is worth knowing before you script it:

Read-only / Safecreate is interactive by design
$ ansible-vault create --vault-password-file .dev-pass newfile.yml
[ERROR]: not a tty, editor cannot be opened

Two behaviours confirmed on 2.21.3 that are worth relying on.

Double encryption is refused.

Read-only / Safeencrypting an encrypted file is an error, not a nesting
$ ansible-vault encrypt --vault-password-file .dev-pass plain.yml; echo exit=$?
[ERROR]: input is already encrypted
exit=1

So a re-run of an encryption step is safe rather than destructive, which matters if you are scripting a migration.

encrypt tightens the file mode to 0600, and decrypt does not loosen it back.

Read-only / Safemodes through the cycle
$ stat -c %a m.yml   # before encrypt, after encrypt, after decrypt
664
600
600

The first transition is a genuine, quiet improvement — a vars file created under a permissive umask becomes owner-only when you encrypt it. The second is the one to remember: after a decrypt, the plaintext credential is at least not world-readable on a shared controller. That is a mitigation, not a reprieve. It is still plaintext, in your repository directory, and every argument in the previous section still applies.

Knowledge check

Knowledge check · 4 questions

  1. Q1. You need to check what value a vault-encrypted vars file currently holds for one variable. Which command is correct?

  2. Q2. A vault file header reads $ANSIBLE_VAULT;1.1;AES256 and a colleague says it should be upgraded to 1.2. What is the accurate response?

  3. Q3. Which statements about ansible-vault operations on 2.21.3 are correct? Select all that apply.

  4. Q4. Rekeying a vault file after the vault password leaked is sufficient, because the old password no longer opens the file.

Passing score: 75%. Answers are checked in this browser.