There are a number of ways to protect secrets you wish to use in your Playbooks. I’ll show a simple example here of how you can encrypt a string, copy it into your Playbook for use and then run the Playbook, where the string is de-crypted in-line and used without exposing it in plain text within any of the Ansible YAML files. If you are using version control to store your Ansible Playbooks (you are right? 😀 ), then you’ll not want to be storing the plain text passwords direct into the YAML.
Create the Encrypted String
First we need to create an encrypted string, in this example we’re using Ansible Vault for this, we’ll run the following command which will take the string we wish to be encrypted for later use in our Playbook.
ansible-vault encrypt_string --vault-id @prompt WellSecretString!
You’ll be prompted for the vault password, you’ll need to enter this to encrypt the string, and you’ll also need to provide it when you run the Playbook, or the string will not be able to be de-crypted and used. When run you’ll see an output something like this:
Add to the Playbook
Within your Playbook you then need to include the encrypted text (ciphertext) in say a variable, where you can then call upon the variable within a task to use it for something. Here is a very simple example playbook that consists of three files, you add the encrypted text into a variable called “secretstring” in the vault-play.yml file. Note the name of the server is because i’m using it to build a Kubernetes cluster, so just using it for this example.
vault.yml
---
- hosts: localhost
become: false
pre_tasks:
- name: Check Ansible Version
assert:
that:
- ansible_version.major == 2
- ( ansible_version.minor == 7 or ansible_version.minor == 9)
msg: "Sanger Ansible requires Ansible 2.7 or 2.9"
- import_playbook: vault-play.yml
vault-play.yml
---
- name: "Reachability Checks"
hosts: k8sservers
vars:
secretstring: !vault |
$ANSIBLE_VAULT;1.1;AES256
63353931383132636330333034343831386539333830626236366231303264613930383437373932
3566333337633465343764656335653163303337306637350a333961616233323932373439306138
30366161346331663730616261333038623839303963373362336463626636643531323936646166
3563636230316165360a663162396635303165323034646334396330386264306231646534386136
39323335373738613133633065646337643231623239383064616636656165646365
tasks:
- name: "Test Reachability"
ping:
- name: "Print Secret String"
ansible.builtin.debug:
msg: "{{ secretstring }}"
hosts
[k8sservers]
my-k8s-1.domain.com
Okay, great we’re ready to run the Playbook.
Run the Playbook
Now, you can’t just run the Playbook as you normally would otherwise when Ansible reaches the encrypted string it will barf because it is unable to decrypt the string. So to get round this all we need to do is supply the vault password when we run the Playbook as follows:
ansible-playbook vault.yml -i hosts --ask-vault-pass
And there you go, as you can see Ansible first asks you for your vault password then runs the Playbook and decrypts the string in-line, okay this isn’t very helpful, we’re just printing the secret to the string, but think of what else you could do, such as feeding this secret into a command to perform some privileged operation such as become/sudo etc.
$ ansible-playbook vault.yml -i hosts --ask-vault-pass
Vault password:
PLAY [localhost] **********************************************************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************************************
ok: [localhost]
TASK [Check Ansible Version] **********************************************************************************************************************************
ok: [localhost] => {
"changed": false,
"msg": "All assertions passed"
}
PLAY [Reachability Checks] ************************************************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************************************
ok: [my-k8s-1.domain.com]
TASK [Test Reachability] **************************************************************************************************************************************
ok: [my-k8s-1.domain.com]
TASK [Print Secret String] ************************************************************************************************************************************
ok: [my-k8s-1.domain.com] => {
"msg": "WellSecretString!"
}
PLAY RECAP ****************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
my-k8s-1.domain.com : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Conclusion
Although simple, it is powerful. As mentioned there are other methods to protect secrets in your Playbooks, a downside of this method is that the Vault password is a shared password, i.e. anyone who needs to run the Playbook needs to know it, but if you are a small team or its just you, it can be an excellent way to protect your secrets without too much hassle.