Ansible Vault does one thing, and it does it well:
It encrypts data at rest in your repository.
That is the whole scope. Everything people believe it also does, it does
not do, and the belief is what turns a good tool into a false sense of
completion.
This lesson is the boundary, stated plainly and measured where it can be
measured.
A vault-encrypted variable is an ordinary string
The clearest demonstration is the simplest one. The vars file below has
db_password as an inline !vault value — encrypted at rest, unreadable
in a pull request. Here is what happens once the play runs:
Read-only / Safeencrypted in the file; plaintext in the run— Executed on ansible-core 2.21.3. db_password is a !vault value in the vars file supplied to this play.
TASK [The value is vault-encrypted in the repository] *************
ok: [localhost] => {
"db_password": "REPLACE_ME"
}
TASK [And it templates into anything] *****************************
ok: [localhost] => {
"msg": "postgresql://billing_ro:REPLACE_ME@db1.example.com/app"
}
The encryption did not follow the value into the run, and it was never
supposed to. Once decrypted, the variable is a string like any other. It
prints, it templates, it concatenates, it goes into a file, it goes over
the wire, it appears in a return value.
That is not a flaw. A secret you cannot use is not a secret you have.
The entire point of decrypting it is to use it. But it means every control
that applies to strings — no_log, output discipline, log permissions,
who can read a ticket — is a separate control that Vault does not provide.
The journey, annotated
Take the diagram from the first lesson of this part and mark it honestly:
Hop
Protected by Vault?
What protects it instead
At rest in the repository
yes
this is the whole job
In a Git object from an earlier plaintext commit
no
rotation; history rewriting
Decrypted in controller memory
no
controller access control
In a debug or a registered result
no
no_log, and not printing results whole
In --diff output
no
no_log on the task, or not diffing that task
In log_path or a callback log
no
file permissions, directory permissions, umask
As a module argument on the managed node
no
pipelining removes the file; nothing removes the argument
In a temporary file on the target
no
pipelining
In the target process table while the task runs
no
using a module rather than shell
In the config file the task wrote
no
file mode, ownership, the target’s own controls
In the target service’s own logs
no
that service’s configuration
In a backup: true copy on the target
no
not using backup for credential files
In CI job output or artifacts
no
CI configuration and retention policy
Against someone who has the vault password
no
vault ID scoping; where the password lives
One row is yes. That is the accurate picture, and it is worth putting in
front of anyone who says “it is fine, it is in Vault”.
What variable-level encryption specifically does not cover
encrypt_string encrypts values. Not keys, not structure, not tasks,
not anything else in the file.
Read-only / Safewhat a reader of this file learns without the password
# Everything here except the value is public information.
db_host: db1.example.com # your database hostname
db_user: billing_ro # the account name
db_port: 5432 # the port
api_endpoint: https://api-internal.example.com/v2
db_password: !vault |
$ANSIBLE_VAULT;1.2;AES256;prod
33656432323139626338306532383365366262333432313935643735336539393735303161336162
A reader without the password learns your internal hostnames, your account
names, your ports, your API endpoints, the fact that there is a prod
vault label, and that a password exists for that account. That is
reconnaissance, delivered neatly.
Whether that matters depends on where the repository is. For an internal
repository it is usually fine and the reviewability is worth more. For
anything public, or anything a wide contractor population can read, the
structure itself is worth protecting and file-level encryption is the
better choice.
The related limits, which follow from the same fact:
rekey does not touch inline values. It operates on a vault file
payload. A file of encrypt_string values is ordinary YAML with encrypted
scalars in it, so a password rotation must re-encrypt each value
individually — covered with its consequences in the encrypt_string
lesson.
Tasks are not encryptable. You can encrypt a variable a task uses. You
cannot encrypt the task, the play, or the fact that this playbook
configures a payments database. If the existence of something is
sensitive, Vault is the wrong layer entirely.
Knowledge check
Knowledge check · 4 questions
Q1. A variable is stored as an inline !vault value. A task does debug with that variable. What is printed?
Q2. Which statement about Vault and the person holding the vault password is accurate?
Q3. Which are true of variable-level encryption specifically, as opposed to file-level? Select all that apply.
Q4. Because Ansible Vault uses strong symmetric encryption, adding a contributor who may write secrets but must not read existing ones is a matter of configuring their vault ID correctly.
Passing score: 75%. Answers are checked in this browser.