Skip to main content

How to encrypt sensitive data in playbooks with Ansible Vault

Ansible Vault lets you keep sensitive data, such as passwords and keys, in encrypted files. Here’s how to use it in playbooks to improve automation workflow safety.
Image
Locks on a rope

Image by Jan Lüddemann from Pixabay

Ansible Vault is a feature in the Ansible automation engine that allows you to encrypt any data file. This is very useful when you're dealing with sensitive information in your Ansible installation.

You can encrypt any structured data file used in Ansible, including:

  • ansible_facts
  • A variable file in host_vars
  • group_vars directories
  • Variable files loaded by vars_files
  • include_vars keywords within a playbook
  • Variable files passed on the command line using the -e option followed by the name of the variable file (for example, -e @var_file.yml)

Ansible Vault allows you to keep sensitive data, such as passwords and keys, in encrypted files, rather than as plain text in playbooks or roles. The ansible-vault command is used for this purpose.

Restrict a user from viewing content in a playbook

In a previous article, I looked at implementing Jinja2 templates in playbooks to fully automate and manage Apache web servers. In this article, I'll show you how to implement encryption at the individual variable level to restrict a normal user from viewing sensitive content in a playbook. In this example, I will encrypt the ssh_port variable and its value.

Here's a snippet from a simple playbook:

<---
- hosts: '*'
  vars:
    ssh_port: 2049
  tasks:
    - name: Tell SELinux about SSH's New Port
      seport:
        ports: "{{ ssh_port }}"
        proto: tcp
        setype: ssh_port_t
        state: present

    - name: Harden sshd configuration
      lineinfile:
        dest: /etc/ssh/sshd_config
        regexp: "{{item.regexp}}"
        line: "{{item.line}}"
        state: present
        validate: 'sshd -T -f %s'
      with_items:
        - regexp: "^Port"
          line: "Port {{ ssh_port }}"
        - regexp: "^PermitRootLogin"
          line: "PermitRootLogin no"
        - regexp: "^AllowUsers"
          line: "AllowUsers ansible-devops"
        - regexp: "^PasswordAuthentication"
          line: "PasswordAuthentication no"
        - regexp: "^AllowAgentForwarding"
          line: "AllowAgentForwarding no"
        - regexp: "^AllowTcpForwarding"
          line: "AllowTcpForwarding no"
        - regexp: "^MaxAuthTries"
          line: "MaxAuthTries 3"
        - regexp: "^MaxSessions"
          line: "MaxSessions 6"
        - regexp: "^TCPKeepAlive"
          line: "TCPKeepAlive no"
        - regexp: "^UseDNS"
          line: "UseDNS no"
      notify: restart sshd
    - name: add user ansible-devops
      user:
        name: ansible-devops
    - name: add sudo group rights for deployment user
      lineinfile:
        dest: /etc/sudoers.d/ansible-devops
        regexp: "^ansible-devops"
        line: "ansible-devops ALL=(ALL) NOPASSWD: ALL"
        state: present
  handlers:
    - name: restart sshd
      service:
        name: sshd
        state: restarted

Make sure it validates with yamllint:

$ yamllint ssh-config.yaml || echo "Success"
Success

[ Download now: A system administrator's guide to IT automation. ]

To encrypt a value in a playbook, provide the string you want to encrypt (2049 in this example) along with the key it belongs to (ssh_port, in this example). Use the --ask-vault-pass option to be prompted to create a password. The output is very long, so I've truncated it for clarity:

$ ansible-vault encrypt_string --ask-vault-pass '2049' --name 'ssh_port'
New vault password:
Confirm password:
ssh_port: !vault | 
          $ANSIBLE_VAULT;1.1;AES256 
          3433313631373[...]3631 
Encryption successful

Now copy the result into your playbook. You must copy everything from the key name (ssh_port) to the end of the long string of numbers containing the encrypted data. It looks a little messy, but in the end, your playbook contains this (this playbook is truncated for brevity):

---
- hosts: '*'
  vars:
    ssh_port: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          65633138303133363034333734653734383235353564393264326532376433336137363263353837
          6233663762623833393432653438616263396565316365330a376630353530643434653539323834
          63386637366462386535636536613032376539633661653462636461613037636131343736623561
          6137663533333432390a373563653837386165666633396464343565303766653738656361363237
          3234
  tasks:
    - name: Tell SELinux about SSH's New Port
      seport:
        ports: "{{ ssh_port }}"
        proto: tcp
        setype: ssh_port_t
        state: present
[...]

Make sure it validates with yamllint:

$ yamllint ssh-config.yaml || echo "Success"
Success

Run an encrypted playbook

To run a playbook containing an encrypted string, use the ansible-playbook command, adding the --ask-vault-pass option. In this example, you can ignore the warnings about valid hosts, because you're just testing an example playbook:

$ ansible-playbook --ask-vault-pass ssh-config.yaml
Vault password:  

PLAY [ssh_server] ************************************** 

TASK [Gathering Facts] ********************************** 
ok: [localhost]

TASK [Tell SELinux about SSH's New Port] **************** 
ok: [localhost]

PLAY RECAP ********************************************** 
localhost: ok=2  [...] failed=0    skipped=0
Success!

Automate it

The advantage of Ansible is, of course, automation. So that you don't have to manually enter a password every time you want to run a playbook, you can instead use passwords stored in a text file.

Make sure you store password files safely by using disk encryption or a password vault. If you use a thumb drive and your Ansible control node is in an on-premises datacenter, you can implement USBGuard rules and policies for your server to restrict access to rogue thumb drives.

Here's a simple example of a password file called secrets.txt containing one password:

password123

To run your playbook using this password file instead of manual password entry, use the ansible-playbook command as usual but with the --vault-id option referencing the encrypted key (ssh_port, in this example) along with the name of the password file:

$ ansible-playbook ssh-config.yaml --vault-id ssh_port@secrets.txt

[ Need more on Ansible? Take a free technical overview course from Red Hat. Ansible Essentials: Simplicity in Automation Technical Overview. ]

You can also use multiple passwords by providing multiple vault ID flags. Here's an example password file containing more than one password, assuming that both the ssh_port and setype keys in the example YAML file are encrypted with:

ansible-vault encrypt_string --vault-id ssh_port@secrets.txt '2049' --name 'ssh_port' 

and 

ansible-vault encrypt_string --vault-id setype@secrets.txt 'ssh_port_t' --name 'setype'

respectively.

Here is an example password file (secrets.txt):

ssh_port: password123
setype: password456

To run the playbook, specify each encrypted key and its password file using the --vault-id option:

$ ansible-playbook --vault-id ssh_port@secrets.txt \
--vault-id setype@secrets.txt ssh-config.yaml

For more examples, check out the official Ansible documentation on how to use encrypted variables and files and the various ways of passing single and multiple passwords to playbooks.

Better automation through encryption

This article covers basic Ansible Vault usage, and there's much more this feature can do. Using Ansible Vault is an easy way to add encryption to your automation, so use it in your important playbooks to keep your automation workflow safe.

[ Learn more about server and configuration management by downloading Ansible for DevOps. ]

Topics:   Security   Ansible  
Author’s photo

Robert Kimani

Robert is a Linux enthusiast and an open source advocate, currently transitioning into a site reliability engineering (SRE) role. Always striving to learn more, he's pursuing Red Hat Certified Architect - Infrastructure path certification. Besides his love for Linux, he believes in helping others More about me

Try Red Hat Enterprise Linux

Download it at no charge from the Red Hat Developer program.