How to properly encrypt a file from inside an Ansible Playbook?

Viewed 1241

I'm currently using an Ansible playbook to extract and then transfer a configuration backup from some network devices (a basic text file) to an external storage.

I'd like to encrypt the configuration backups before sending them to their final storage. What would be the most adequate way to encrypt a file from inside an Ansible playbook task? To me, the obvious way would be to use the shell module to either call an external encryption tool (openssl) or an ansible-vault command to encrypt the backup in a format that ansible itself can read later in some other context; i.e. one of the two tasks below (simplified):

  - name: Encrypt stuff with OpenSSL using a password read from vault file
    shell:
      cmd: openssl {{ openssl_parameters }} -k {{ vaulted_encryption_password }} -in {{ file_to_encrypt }} -out {{ encrypted_file }}

  - name: Encrypt stuff with Ansible-Vault
    shell:
      cmd: ansible-vault encrypt {{ file_to_encrypt }} --vault-password-file {{ vault_password_file }}

However, none of these solutions seem completely secure, given they require passing the encryption password to an external tool via a shell (which can expose the password to anyone monitoring the processes on the host this runs in, for example) or require writing the plain-text password on a file for ansible-vault to use.

Is there a better way of doing file encryption inside an Ansible task that I'm missing here? (a dedicated module, or some other solution?).

1 Answers

There are no modules I know to use ansible-vault from playbooks directly (besides the obvious intended use which is to decrypt variables and file contents on the fly).

One possible way to improve security (as far as listing processes is concerned) with your ansible-vault example through a command would be to use the interactive prompt mode and fill the password with the expect module. An other security layer can be added by adding the no_log: true parameter to the task so it does not print content of the variables.

Here is a simple example (you will need to pip install pexpect on the target host):

 ---
 - hosts: localhost
   gather_facts: false
 
   tasks:
     - name: Vault encrypt a given file
       vars:
         vault_pass: v3rys3cur3
       expect:
         command: ansible-vault encrypt --ask-vault-pass toto.txt
         responses:
           New Vault password: "{{ vault_pass }}"
           Confirm New Vault password: "{{ vault_pass }}"

Which gives (using the verbose mode to illustrate the no_log feature and provided the given file exist and is not yet encrypted...):

$ ansible-playbook -v test.yml 
No config file found; using defaults

PLAY [localhost] **************************************************************************************************************************************************************************************************

TASK [Vault encrypt a given file] *********************************************************************************************************************************************************************************
changed: [localhost] => {"censored": "the output has been hidden due to the fact that 'no_log: true' was specified for this result", "changed": true}

PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
Related