Lessons from working and playing with things like AWS, Ansible, and others
Modelling Credentials Configuration in Ansible
02 Apr 2014
One of the most common things to configure in an application is some kind
of credentials based connection. Typically this will be to a database or
an API endpoint, but it doesn’t really matter too much - the examples in
this post will be database configuration, but the principles are the same.
For simplicity’s sake, we’ll assume we’re trying to write a file called
config.properties that has database configuration in the form of a simple
jdbc type URL - e.g.
In terms of things that remain the same between environments, the DB type,
DB name and username are likely to be consistent, and password, DB servers,
and possibly port will vary. It’s very likely that DB type will be so
consistent that we might hardcode it in the template rather than having
unnecessary templating (there can be a temptation to template everything
but the principle of YAGNI applies)
Between DBs in the same environment, there is little in common, but if more
than one application uses the same DB then they might share configuration
(possibly with different usernames and passwords, depending on security
and monitoring requirements).
In terms of the location of credentials, we’ll store everything in the flat
inventory files, with the exception of DB passwords which will be stored
in separate variable files (in a separate repo, or even using ansible vault)
There are a number of ways to achieve this in Ansible.
Flat configuration strings
We can use hierarchical dictionaries of properties to configure properties
in a slightly nicer fashion - rather than have variables named customerdb_dbname
we can have a customerdb object that has a dbname property. And the
storedb will have similar properties.
This version of the template is more sophisticated (and more complicated) but
allows both DB connection strings to be expressed in a for loop.
The modelling of the credentials (see below under Secrets) allows us to
map per-database usernames and passwords.
Before we use this template, we’ll discuss how we handle secrets.
There are a number of approaches to storing secrets. We’ll show the old way
by way of illustration so that we can run the playbook and generate the
I’ve actually committed dbsecrets.yml to the ansible-ec2-example repo for
illustration, but it to keep sensitive information out of the playbooks
repository it would perhaps be in a separate, more locked-down repo.
Running this then generates two almost identical configuration files
(the order of the two DB configurations is not guaranteed - which
shouldn’t matter in general).
Ansible vault allows you to encrypt your secrets with a password. These
encrypted files can then be safely part of the repo.
I’ll copy dbsecrets.yml to dbsupersecrets.yml and then encrypt it with
ansible-vault encrypt dbsupersecrets.yml
Should I then wish to edit the credentials,
ansible-vault edit dbsupersecrets.yml
will work. I used the excellent password ‘badpassword’ should you
wish to follow along.
Finally we can check this with a playbook that uses dbsupersecrets.yml and
run ansible-playbook with --ask-vault-pass
And voilà, config properties files with the much more secure
password of ‘Ch4ng3M3!’.
03 April 2014
I realised my credentials modelling takes no account of environment. One simple way to do this is to store the environment name
in the environment config file (i.e. add “env: production” to production.yml) and then have a hierarchy of vars files e.g.
The nice thing about how Ansible Vault works is that you can choose to just encrypt the files under the production directory
and have cleartext versions for dev and UAT, and the same templates and playbooks will still work (you only need to then
pass –ask-vault-pass when running against production)
I’ve updated the github repo to reflect this, but the main change is to the location of the credentials files and the playbook: