Securing SSL Certificates Using Ansible Vault

Here is how to secure your SSL Certificates using Ansible Vault:

1. Create a file to hold your secrets – secrets.yml

2. Put the .crt and .pub files in secrets.yml as variables:


private_ssl_key: |

public_ssl_key: |
  -----END PRIVATE KEY-----

If you have xclip installed, you can use it to copy files directly to your clipboard:

cat filename | xclip -selection clipboard

Note that when you paste the keys into secrets.yml, you need to indent the keys.

3. Create the SSL files on the virtual machine:

- name: install SSL private key
  copy: content="{{ private_ssl_key }}"
        dest={{ ssl_dest_dir }}/{{ application_name }}.crt

- name: install SSL public key
  copy: content="{{ public_ssl_key }}"
        dest={{ ssl_dest_dir }}/{{ application_name }}.key

4. Setup Nginx:

server {
    listen      80;
    server_name {{ nginx_server_name }};
    return      301 https://$host$request_uri;

server {
   listen              443;
   server_name         {{ nginx_server_name }};
   ssl on;
   ssl_certificate     {{ ssl_dest_dir }}/{{ application_name }}.crt;
   ssl_certificate_key {{ ssl_dest_dir }}/{{ application_name }}.key;


5. Add secrets.yml to your playbook vars.

6. Notice, secrets.yml is not encrypted yet. Test this setup to make sure things are working. DO NOT PUT secrets.yml UNDER VERSION CONTROL YET.

I do local testing using Vagrant. I connect to the website via the IP address This is not the domain name that my SSL certificate is for. So how to test locally? The simplest thing to do is to click on the x-ed out lock on the browser address bar and at least confirm that the browser used the correct SSL certificate, but found that did not match.

Or if you want to get fancy, you can edit the /etc/hosts file and point that IP address to the domain name that your SSL certificate covers. If you have a wildcard SSL certificate, this works well because you can create a domain name that will not interfere with the production domain name. For example:

If your certificate is for a single domain name, altering /etc/hosts might lead to errors if you forget to delete the domain name when you want to test the site on a remote server. If you decide to go with this, to be on the safe side, you might want to install an extension to your browser so that you can check the IP address of the domain name. For Chrome, I use ivpfoo.

7. If everything works, then encrypt secrets.yml:

ansible-vault encrypt secret_vars.yml

8. I use Vagrant to configure a local VM. To decrypt the file you need to add this to your Vagrantfile:

# Ansible provisioner.
  config.vm.provision "ansible" do |ansible|
    ansible.playbook = "ansible-django-stack/vagrant.yml"
    ansible.host_key_checking = false
    ansible.verbose = "v"
    ansible.ask_vault_pass = true

9. Confirm  things still work with Vagrant

10. Add encrypted secret_vars.yml to version control and push to repo (e.g. Bitbucket)

11. Run Ansible to configure live server.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s