Ansible Vault – Bringing Security & Automation together

In the last post, we went through a basic introduction of Ansible and how it can be utilized to automate/optimize network management. We also demonstrated the ease with which some of the most common network actions can be performed through Ansible, with the help of an example exercise.

In a perfect world, that post would’ve been enough to drive home the benefits of Ansible and its usage vis-a-vis Network Management. However, the cyber world today is not perfect and if we continue to build Playbooks & Inventory files the way we demonstrated in our previous post then unfortunately, it wouldn’t take much for the adversaries to bring us to our knees. I am not sure how many of the readers noticed a critical mistake in the previous post’s example. We had not only kept the username/password combination in plain text in the host file but also left the playbook unencrypted. That’s the sort of a mistake which is akin to a cardinal sin in the IT world. We might as well have put this information on a sticky note and paste it on the door for everyone to see.

So, now we know our mistake but how do we prevent this ? What other options are available to us ? This is where the concept of Ansible Vault comes into the picture.

Ansible Vault encrypts variables and files so that sensitive content such as passwords and other such details can be secured in an encrypted file rather than in plain text files. All actions pertaining to ansible vault need to be prefixed with the ansible-vault command. Some of the common actions that Ansible vault performs are given below

  • Encrypt a file
  • Decrypt a file
  • View an encrypted file without breaking the encryption
  • Edit an encrypted file

In order to perform above mentioned operations, we always have to pass “encrypt”, “decrypt”, “view”, “edit” keyword along with the path to the YAML playbook. We will discuss each of them as we go along.

How To Use Ansible Vault ?

  • Objective : Encrypt and then Decrypt a Playbook
  • Command to Encrypt : ansible-vault encrypt /etc/ansible/playbook.yml
  • Command to Decrypt : ansible-vault decrypt /etc/ansible/playbook.yml

When you execute the encrypt command, you will be asked to set up an encryption password. You can think of it as a “private key” that you’ll need if you ever wanted to decrypt the file.

The following is how the Playbook originally looked like before encryption

[ssingh7@localhost ~]$ cat /etc/ansible/playbook.yml
- name: "Connecting to CSR Router"
  connection: network_cli
  hosts: router
  gather_facts: no

  tasks:
    - name: Capture Interface Details
      ios_command:
        commands: show ip int brief
      register: result

    - name: display results
      debug:
        var: result.stdout_lines
[ssingh7@localhost ~]$

And this is how it looked like after encryption

[ssingh7@localhost ~]$ cat /etc/ansible/playbook.yml
$ANSIBLE_VAULT;1.1;AES256
64656334353262336436643365343232363433306465653231306639343833303261333435653031
3135613435363636623438376139653536633233336539620a343937653537393539633539323661
66336130316439313238646236613532393735633030306335623761656133373231323135633031
6439383165653530650a376231386238396461333866633531663966366538363162366535333063
34643761383238643535636664386434666331613136343034393635623063393263333362656166
33643662343764393461653462316466343630626566613837313764663839626639633431653766
39356339363663666231326661323332623336613464303531643231373465396639393730656332
36356439353266353361303131313735623633666661633038346236396530353166623433666464
64633564306462646332633339656636633330303036323332643361626431636530633237373637
31336430383637616637316330656536663035363130343366646134663837666463346661633161
39343136386533613639303932376236306363363230313831353763656362303633336132336366
33396235376132666238396665633938656135353731643033633533366439383935646465613434
33633837623564346434633632333730626139366561316431353731316665336262353761663536
32646134346439613061616132346131636461333765306634613739663633386363366539646439
63376163303037623165646266373532653532353739303166363132353834383739326532366435
65376464303438613334316238323330626261643461613231366634393236613034653233313338
30386235656230376336363862613732613664643137333832363730623463633030663165326262
38306234306332613662303964633431663837666439363930366334616562666638386463663562
313861356566306634363165643639633561
[ssingh7@localhost ~]$

You can also observe the complete process in the following video as well

Once you’ve encrypted a playbook, you will not be able to read or edit it in a usual manner with an editor like vim or nano. You will always have to use the ansible-vault module to perform such activities.

  • Objective : Read and Edit the playbook
  • Command to Read : ansible-vault view <path to the Playbook>
  • Command to Edit : ansible-vault edit <path to the Playbook>

Now since we have explained how we can encrypt/decrypt Playbooks and Read/Write encrypted Playbook using Ansible Vault, the next question that comes to mind is, does it change the way Playbooks are actually executed on the console. The answer is YES.


How to execute a Vaulted Playbook

Traditionally, we have used the “ansible-playbook” command to execute a Playbook but since the file is encrypted now, we need a way to provide the Vault password so that Ansible can use that to first decrypt the contents of the playbook and then perform the actual action outlined in the plays. You primarily have 2 ways to accomplish this. We will go through both of these scenarios one by one.

  1. You can either prompt for the Vault password
  2. Or you can point to a file that contains the Vault password

Prompt for Password

For this option, we need to pass the “–ask-vault-pass” keyword along with the rest of the command. The system will then prompt us for the vault password. The script will execute upon successful acceptance of the password.

[ssingh7@localhost ~]$ ansible-playbook --ask-vault-pass /etc/ansible/playbook.yml
Vault password:

PLAY [Connecting to CSR Router] *******************************************************************************************************************************

TASK [Capture Interface Details] ******************************************************************************************************************************
ok: [10.0.0.115]

TASK [display results] ****************************************************************************************************************************************
ok: [10.0.0.115] => {
    "result.stdout_lines": [
        [
            "Interface              IP-Address      OK? Method Status                Protocol",
            "GigabitEthernet1       10.0.0.115      YES NVRAM  up                    up      ",
            "GigabitEthernet2       unassigned      YES NVRAM  up                    up      ",
            "GigabitEthernet3       unassigned      YES NVRAM  administratively down down"
        ]
    ]
}

PLAY RECAP ****************************************************************************************************************************************************
10.0.0.115                 : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

[ssingh7@localhost ~]$

Point to a File

We have created a simple text file that contains the vault password. The contents of the file are show below

[ssingh7@localhost ~]$ cat /etc/ansible/pass.txt
cisco@123
[ssingh7@localhost ~]$

Let’s now execute the playbook using the second method. For this method, we need to pass the –vault-password-file keyword followed by the path to the Vault file and the rest of the command.

[ssingh7@localhost ~]$ ansible-playbook --vault-password-file /etc/ansible/pass.txt /etc/ansible/playbook.yml

PLAY [Connecting to CSR Router] *******************************************************************************************************************************

TASK [Capture Interface Details] ******************************************************************************************************************************
ok: [10.0.0.115]

TASK [display results] ****************************************************************************************************************************************
ok: [10.0.0.115] => {
    "result.stdout_lines": [
        [
            "Interface              IP-Address      OK? Method Status                Protocol",
            "GigabitEthernet1       10.0.0.115      YES NVRAM  up                    up      ",
            "GigabitEthernet2       unassigned      YES NVRAM  up                    up      ",
            "GigabitEthernet3       unassigned      YES NVRAM  administratively down down"
        ]
    ]
}

PLAY RECAP ****************************************************************************************************************************************************
10.0.0.115                 : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

[ssingh7@localhost ~]$

I hope that this post was helpful, in some way, to those who want to explore different features of Ansible especially from a security point of view. The objective was to introduce the reader to the real world challenges that usually arise whenever we talk about automating anything on a wider scale and the options available to us to tackle such challenges. We will be going through some more real world scenarios in the coming posts. So, stay tuned.

Please feel free to drop your feedback/suggestions, if any. Until then, Happy Learnings!!

Let’s connect on LinkedIn

Leave a Reply