Joseph Edmonds

Using Ansible to Create Client SSL Certificates and Download Files with Them

by Joseph Edmonds

by Joseph Edmonds

I’m a big fan of Ansible – it’s an excellent tool for automatically configuring and managing local, staging and production servers and infrastructures.

One of the features I really appreciate is the ability to easily manage secrets including easy encryption/decryption of passwords, files etc.

One thing that is quite common is to require your ansible project to download data from a production server – for example database dumps. This is quite sensitive data and so a good amount of paranoia is sensible to ensure that the data is not downloadable by anyone who should not be able to get to it. An excellent solution for this kind of security is to use client SSL certificates. These are very much like the SSL certificates that you install on your server to allow your visitors to share information with your server over an encrypted line. The client SSL certificate enhances this with secure private key based authentication that is very difficult or impossible to get past without having the correct key and certificate files installed.

To generate the client SSL certificates, I have created a script in the Vault Scripts Ansbile Role:

https://github.com/LongTermSupport/ansible-role-vault-scripts#create-vaulted-ssl-client-certificate-and-authority

In order to use the certs and keys generated by this, you might want to write a play that looks something like this:

- hosts: all
  become: true
  vars:
    root_dir: "{{ playbook_dir }}/../../"
  vars_files:
    - "{{ root_dir }}/vars/project.yml"
  tasks:
    - name: Ensure Certs Directory Exists
      file:
        path: /root/certs/
        state: directory
        mode: 0700

    - name: Write Client Cert Files
      copy:
        dest: "/root/certs/{{ item.dest }}"
        content: "{{ item.content }}"
        mode: 0600
      with_items:
        - dest: staging-ca.crt
          content: "{{ vault_client_foo_staging_data__ca_cert }}"
        - dest: staging-client.crt
          content: "{{ vault_client_foo_staging_data__client_crt }}"
        - dest: staging-client.key
          content: "{{ vault_client_foo_staging_data__client_key }}"

    - name: Download Staging Data Files
      shell: >
        curl {{ verbose | ternary('-vvv','') }} {{ valid_server_ssl | ternary('', '--insecure') }}
        --cert {{ client_cert }}:'{{ client_cert_pass }}' --key {{ client_key}} --cacert {{ client_key }}
        {{ url }} > {{ dest }}
      # Disabling warnings as we have to use curl if we want to use client certs with passwords
      args:
        warn: false
      vars:
        url: "https://staging-data.foo.co.uk:8001/{{ item.filename }}"
        dest: "{{ item.dest }}"
        client_cert: /root/certs/staging-client.crt
        client_cert_pass: "{{ vault_client_foo_staging_data__client_pass_txt }}"
        client_key: /root/certs/staging-client.key
        valid_server_ssl: no
        verbose: no
      with_items:
        - filename: foo.txt
          dest: /tmp/foo.txt
        - filename: bar.txt
          dest: /tmp/bar.txt

This play will first of all create the necessary key files by writing the vaulted data that is created with the vault scripts process.

Then it will use curl to download the files as required. We must use Curl using the shell module as unfortunately the built in get_url module does not support password protected client certs.

Facebook
Twitter
LinkedIn
About Joseph Edmonds

About Joseph Edmonds

Personal musings, tech tips, trivia and other things that might be interesting.

Get in touch today

Send me a message concerning your idea, problem, or question – and I’ll personally respond as soon as possible.

Connect with me on LinkedIn.