Using Ansible Keyring Lookups
Sometimes in order to run an Ansible play you need local, per-user secrets. For example, if your playbook joins a machine to a domain it will need the credentials of a domain administrator.
The naive solution is just to throw the credentials in plaintext in vars/secret.yml
with an appropriate .gitignore
so that they don’t accidentally get committed. But all it really takes is a thoughtless git add -af
and you’re in trouble.
Of course, Ansible itself provides its own Vault functionality for encrypting secret files and/or vars. However, the downside of this is either using --ask-vault-pass
and typing your password on every invocation, or using --vault-password-file
which means you’re storing that password in plaintext somewhere and have similar risks.
But if you use GNOME, or something GNOME-adjacent, for your desktop environment, then you’re likely already got a solution ready to go: keyrings. Long story short, the GNOME keyring stores your secrets encrypted in ~/.local/share/keyrings
and the agent starts with your login session to provide access.
Ansible uses Python’s keyring
package to interface with this, though the way it operates is fairly rigid. I’ll get to this later.
Requirements
- The
keyring
Python package, eg:pip install keyring
- A running
gnome-keyring-daemon
process. This should start with your login, but if not then rungnome-keyring-daemon --unlock
.
Setting the Secrets
From the command line, run keyring set foo bar
which will prompt you to enter a password, but this is the value of the secret that you are storing.
Using the Secrets in Ansible
Using the above secret is as simple as lookup('keyring', 'foo bar')
.
Python’s Weird Implementation of Keyring
The broad stroke of the GNOME keyring is that each entry is identified by one or more attribute-value pairs, has a label, and of course a secret. These attribute-value pairs can really be anything you like, but the Python implementation strictly locks these to service
and username
attributes, and constructs a generic label.
Eg: For keyring set foo bar
the following entry will be made in the default keyring:
Label: Password for 'bar' on 'foo'
Attributes:
application: Python keyring library
service: foo
username: bar
To make an equivalent entry using GNOME’s own secret-tool
utility:
secret-tool store \
--label="Password for 'bar' on 'foo'" \
application 'Python keyring library' \
service foo \
username bar
You can also view and manage keyring entries via the Seahorse GUI utility, which is useful when it comes time to rotate passwords, but beware that as of this writing there is no apparent way to set attributes on entries during creation.
“But I want to securely share secrets across the whole environment and/or organization!”
Then I cannot recommend Hashicorp’s Vault highly enough. The basic secrets engine will do exactly this, but there are also additional engine for thing like running an internal PKI CA, or performing transit encryption.
Use it.
Disclaimer: I am not paid, endorsed, or otherwise beholden to Hashicorp. They just make really good stuff.