Ansible SSH private key in source control?
I have been developing an Ansible playbook for a couple of weeks, therefore, my experience with such technology is relatively short. Part of my strategy includes using a custom ansible_ssh_user
for provisioning hosts throughout the inventory, however, such user will need its own SSH key pair, which would involve some sort of a plan for holding/storing its correspondent private key. On a production environment, this playbook would be cloned/pulled and run inside a certain playbook node whose role is to provision the rest of the infrastructure.
At first, I was thinking to just put that private key inside the playbook git repository, but I am having second thoughts about it nonetheless, mostly because of somewhat obvious security reasons and common sense around it, hence the reason I need to consult you about this matter.
With this set on the table, here are the follow-up questions:
- In an Ansible-based development environment, is it sane/reasonable to hold a private SSH key in source control?
- Would this practice be advised only for development environments whereas another local git branch inside the playbook node would be then used to hold the actual production SSH private key?
- Would it be better to address this case scenario via Ansible Vault instead?, I have not ever used this before, but regardless of that I cannot yet tell whether this would be a proper case for using it.
- In your experience, what would be your approach around this in a production environment?, what would it be considered as the best practice in this particular scenario?
It's a bad idea to store any kind of plaintext secret in revision control, SSH private keys included. Instead, use ansible-vault to store the private key.
ansible-vault
can operate on any file type. Just encrypt the file with
ansible-vault encrypt /path/to/local/private_key
then install the key:
- name: Install a private SSH key
vars:
source_key: /path/to/local/private_key
dest_key: /path/to/remote/private_key
tasks:
- name: Ensure .ssh directory exists.
file:
dest: "{{ dest_key | dirname }}"
mode: 0700
owner: user
state: directory
- name: Install ssh key
copy:
src: "{{ source_key }}"
dest: "{{ dest_key }}"
mode: 0600
owner: user
Earlier versions of ansible-vault would only operate on variables defined in var files, so you had to do something like this:
ssh_key: |
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
key_file: /home/user/.ssh/id_rsa
Encrypt with ansible-vault:
ansible-vault encrypt /path/to/var_file
And install the key:
- name: Ensure .ssh directory exists.
file:
dest: "{{ key_file | dirname }}"
mode: 0700
owner: user
state: directory
- name: Install ssh key
copy:
content: "{{ ssh_key }}"
dest: "{{ key_file }}"
mode: 0600
owner: user
Thanks to all those below who improved the answer with their comments.
Since you are provisioning from scratch, you should generate the private/public key pair on the playbook node and then distribute the public key via the authorized_keys
module. This would eliminate the need to store a secret anywhere except on the host where it is needed. Here is a playbook to achieve this, which would be executed on the playbook node:
---
- hosts: 127.0.0.1
sudo: yes
gather_facts: no
tasks:
- name: create ansible_ssh_user locally
user: name=ansible_ssh_user generate_ssh_key=yes ssh_key_bits=2048 ssh_key_file=.ssh/id_rsa
- name: copy the generated public key to an accessible location for the next play
shell: cp ~ansible_ssh_user/.ssh/id_rsa.pub /tmp/ansible_ssh_user.pub
- hosts: all
sudo: yes
gather_facts: no
tasks:
- name: create ansible_ssh_user
user: name=ansible_ssh_user groups=group1,group2
- name: Add RSA public key to the remote host
authorized_key: user=ansible_ssh_user key="{{ lookup('file', '/tmp/ansible_ssh_user.pub') }}"
- hosts: 127.0.0.1
sudo: yes
gather_facts: no
tasks:
- name: remove public key from /tmp
shell: rm /tmp/ansible_ssh_user.pub
...