Using Ansible Vault to Encrypt a String

Ansible DevOps Security

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.

Leave a Reply

Your email address will not be published. Required fields are marked *