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— Executed on ansible-core 2.21.3.
$ 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— Executed on ansible-core 2.21.3. The file contains db_password: REPLACE_ME.
$ ansible-vault encrypt --vault-password-file .dev-pass plain.yml; head -2 plain.yml
Four fields, semicolon-separated, and every one of them is readable by
anyone who can read the file:
Field
Meaning
$ANSIBLE_VAULT
the magic string that tells Ansible this file is encrypted
1.1
envelope format version
AES256
the 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— Executed on 2.21.3. The version moves to 1.2 and the label is appended.
$ 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— Executed on 2.21.3. Decrypts to stdout; the file on disk is unchanged.
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— Executed on 2.21.3. CONFIGURATION severity: it modifies a file in your repository and leaves a credential on disk.
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 wanted
Use this instead
Read the values
ansible-vault view
Change a value
ansible-vault edit
Change the password
ansible-vault rekey
Feed a value to another program
ansible-vault view file | your-program
Diff two vault files
decrypt both to stdout with --output - and diff those
Stop using Vault for this file
decrypt — 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— Executed on 2.21.3 with no controlling terminal.
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— Executed on 2.21.3 with a umask of 0002, so the file started world-readable.
$ 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
Q1. You need to check what value a vault-encrypted vars file currently holds for one variable. Which command is correct?
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?
Q3. Which statements about ansible-vault operations on 2.21.3 are correct? Select all that apply.
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.