Now we know how to inject client certificates into Firefox and Chrome it’s time to automate that process with Ansible.
The goal is to take a client and CA certificate and deliver it to the .pki keystore on the client. The actual generation of the certificate happens using easyrsa
and is not part of this process. Let’s assume you already have generated a series of certificates, and converted them to a .pfx
(pkcs12) for each client and just need to deliver them – although I may write up that process later.
Further let’s assume you are naming the certificate files with the same inventory hostname you are going to use in Ansible. This is so we can easily identify which file goes to which host, eg.
myclient01.pfx
for inventory item myclient01
.
I built my role structure with:
$ ansible-role-init certs
certs ├── defaults ├── files ├── handlers ├── meta ├── tasks ├── templates ├── tests └── vars
I then copied my .pfx
and ca.crt
file into files
.
Protecting the Innocent
There is one part of this process that is going to require passwords for adding certificates to the .pki
keystore on the client. As we don’t like to keep plain-text passwords in any of our Git repositories I decided to use Ansible vault to protect them.
I found the easiest way to deal with the vault is to create a file in your ~/.ansible
folder called secret
and put the plain-text password for your vault in there. This password will be used to encrypt data you put into your role and to decrypt it as it is deployed.
Then edit your /etc/ansible/ansible.cfg
file and add a line to point to your password file:
vault_password_file = ~/.ansible/secret
I can then use it to create a variable with the password I used for my .pfx
files called easyrsa_secret
.
$ ansible-vault encrypt_string 'MySuperSecretKey' --name 'easyrsa_secret' easyrsa_secret: !vault | $ANSIBLE_VAULT;1.1;AES256 33616138643032396537383635313637393465343765633364306164363462373564666237316231 3565343837623334623564316439313936336437386435350a646434623163323137323135346334 30663430323262376435616465356366613739396333333634313139396538346136363833653766 6365626164336538360a626139303465386363316133636234376638633230653535623735326464 34316365646339643031663032326638326431613164323137383330313062623136 Encryption successful
Then copy the returned easyrsa_secret
yaml snippet and put it into vars/main.yml
. That’s it! Now when I refer to the {{ easyrsa_secret }}
in my role it will automatically be decrypted using my secret password, and my role is safe to commit to my repository.
Just make sure you don’t lose your
~/.ansible/secret
or you aren’t going to be able to decrypt the values!
Variables – vars/main.yml
--- easyrsa_pki: /home/easyrsa/pki/ easyrsa_secret: !vault | $ANSIBLE_VAULT;1.1;AES256 33303732313337343063363138383461663033316531356632303033323931346365613832383137 3163393438616238633537353163346438663237313463310a326134356537323732313335633862 33386639396336303563376338656461633365616361393339343061653433303832623835323830 6534633537636133340a303732316334306233393230376463653465653532376434383830643238 62363631663331383839653263386633646439613937643366323237313364613233 easyrsa_client_pki: /home/user/
easyrsa_pki
, is the location I initialised/created my easyrsa pki structure.
easyrsa_client_pki
, is the location on my remote client that holds the .pki
keystore for Chrome/Firefox.
Tasks – tasks/certificate-tasks.yml
--- # file: certificate-tasks.yml - name: Install libnss3-tools apt: name: libnss3-tools state: present - name: Copy Certificate to client copy: src: "files/{{ inventory_hostname }}.pfx" dest: "/tmp/{{ inventory_hostname }}.pfx" - name: Copy CA Certificate to client copy: src: "files/ca.crt" dest: "/tmp/ca.crt" - name: Create a file with the secret key in it lineinfile: path: /tmp/secret create: yes line: "{{ easyrsa_secret }}" - name: Add the CA Certificate to the client .pki keystore command: chdir: /tmp cmd: "/usr/bin/certutil -A -i ca.crt -n MyCA -t \"CT,C,T\" -d {{ easyrsa_client_pki }}.pki -f secret" register: stdout - name: Add the client .pkx public/private key pair to the client .pki keystore command: chdir: /tmp cmd: "/usr/bin/pk12util -i {{ inventory_hostname }}.pfx -n {{ inventory_hostname }} -d {{ easyrsa_client_pki }}.pki -w secret -k secret" - name: Remove the secret and certificate files now we are done file: path: - /tmp/secret - /tmp/ca.crt - "/tmp/{{ inventory_hostname }}.pfx" state: absent
What happens here is Ansible will ensure the client has the tools required for certificate management by installing libnss3-tools
. It will then copy the certificates to the clients /tmp
folder and create a file containing the secret
to use.
Next it will run certutil
to inject the CA certificate and then pk12util
to install the client public/private key pair. Before finally tidying up and removing the temporary files.