When you’re using Ansible or any other configuration management tool, you might come in contact with deploying SSL certificates sooner or later. While deploying public SSL certificates isn’t a security issue at all, the deployment of private keys become more critical – at least if you want to deploy them securely.
The problem with private keys
The word private already explains a lot, because private keys should be held private – in any case. But if you’re working in a new fancy environment with a lot of automation and configuration management in place, you might ask yourself:
How can I deploy and configure my SSL encrypted application in a most automated way?
Fortunately in Ansible there are several options available.
Option 1: Check only for file permissions
The most simple option is to skip the whole deployment of the certificates and private keys via Ansible. Instead of deploying the certificate, just make sure the files are in place and the permissions are correct:
--- - name: make sure SSL certificate is existing and secured file: state: file path: '{{ item.path }}' owner: root group: root mode: '{{ item.mode }}' with_items: - path: /path/to/my/cert.pem mode: '0644' - path: /path/to/my/key.pem mode: '0600'
You’ll benefit of an error message when the certificate isn’t installed while you’re deploying your application. Of course Ansible will also correct the file permissions, if you’ve installed your certificate manually and forgot to set the permissions.
Unfortunately you’ve to install the certificate manually, because it isn’t stored in the Ansible SCM repository at all.
Option 2: Copy the certificate with Ansible on-demand
However it can be annoying if you’ve to deploy several servers and everything is automated, except for the freaking certificates. So there’s a workaround with an “on-demand” task via ansible command:
# Copy certificate ansible -m copy -a "src=certificate.pem dest=/path/to/my/certificate.pem owner=root group=root mode=0644" webservers # Copy private key ansible -m copy -a "src=key.pem dest=/path/to/my/key.pem owner=root group=root mode=0600" webservers
With the commands above you can simply copy your certificate and private key to all the webservers out there. Depending on your ansible configuration, you might also have to use the -i (inventory) and -s (sudo) flag.
Unfortunately you still have to copy the certificates to your Ansible control node and execute the commands manually before you’re running your application deployment play. Just make sure you delete the certificate after the deployment from your control node, or at least set the correct permissions so only authorised users can read it.
Option 3: Deploy certificates after prompting for vars
However there’s another alternative which is a mix of the options above. You still use the task from option 1, but instead of the file module you’re using the copy module from option 2. Then instead of defining a fix src, we’re using a variable:
--- - name: make sure SSL certificate is existing and secured copy: src: '{{ item.src }}' path: '{{ item.path }}' owner: root group: root mode: '{{ item.mode }}' no_log: true with_items: - src: '{{ ssl_certificate }}' path: /path/to/my/cert.pem mode: '0644' - src: '{{ ssl_private_key }}' path: /path/to/my/key.pem mode: '0600'
Then prompt the user for the certificate and private key paths in the playbook.
--- - hosts: roles: - my_app vars_prompt: ssl_certificate: Enter path to SSL certificate ssl_private_key: Enter path to SSL private key
This is the most secure option if you’re removing the certs from your control node after the deployment. Unfortunately it’s not fully automated because you’ve to prompt the user for the paths.
Option 4: Deploy certificates via Ansible play
Of course the automated deployment of credentials or private keys would be really nice, though security is really important. You shouldn’t even think about storing credentials or private keys in an unprotected format in your config management SCM repository out there like other did. Just don’t even think about it – don’t do it – never – seriously, forget it!
Anyway if you want to use automated deployments of certificates and private keys, you might have to store them in your Ansible SCM repository as well. As I already mentioned, don’t store the unprotected! Ansible introduced the Vault in version 1.5, which is a nice piece to keep your sensitive data private. Vaults are like variable files, but they’re encrypted.
First of all, create a new vault or edit an existing one:
# Create a new vault ansible-vault create certificate.yml # Edit an existing vault ansible-vault edit certificate.yml
Now add the certificate and private keys as variables:
--- ssl_certificate: | -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- ssl_private_key: | -----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----
Make sure the vault is loaded, either via vars_files directive in your playbook or via include_vars statement in your role/tasks:
--- - hosts: roles: - my_app vars_files: - vars/certificate.yml
--- - include_vars: certificate.yml
Install the certificate and private key via copy module:
--- - name: make sure SSL certificate is installed copy: content: '{{ ssl_certificate }}' dest: /path/to/my/cert.pem owner: root group: root mode: 0644 - name: make sure SSL private key is installed copy: content: '{{ ssl_private_key }}' dest: /path/to/my/key.pem owner: root group: root mode: 0600 no_log: true
When you now run the ansible-playbook command, you’ve to set the –ask-vault-pass or –vault-password-file FILE CLI argument:
ansible-playbook play.yml --ask-vault-pass
With the setup you can deploy certificates within your playbook. The nice thing about variable files is, that they can be stored anywhere, so you’re not forced to store everything in your Ansible SCM repository. Of course if you need your Ansible installation to be portable (i.e. for multiple control nodes) you’ve to store your vault in the repository or any other shared storage. But if you’re using only one single control node, you can store your certificate vault outside of your repository as well.
Conclusion
The most secure way is to keep your key really private, so options 1, 2 or 3 might be the “most secure” options. Though it can be annoying.
If you’re looking forward to deploy sensitive data like private keys via Ansible in an automated way, I’ll go with option 3. You might store your data in the Ansible SCM repository, but at least everything is encrypted.
13 Comments