Secure your vagrant boxes – replace ssh host keys

Vagrant is a cool piece of software that allows automatic deployment of development machines. It is even usefull to bring the result of development to production. In all cases, security should be a concern. Ready to use box templates often come with a default user (vagrant, password vagrant) and a well-known, insecure private ssh key for that user. This raises a security issue – everyone with network access to the machine can login using the credentials or the ssh key. While this issue is well known and addressed in many discussions (and solved with Vagrant 1.7 which by defautl replaces the keys), another similare issue still exists.

Most box images comes with a ssh host key that was created during the creation of the image. So most running machines will use that hostkey. Since it is well-known, an attacker could easily do a man-in-the-middle-attack to any remote ssh connection going to such a box. In development environments this may no problem (because most connections go from localhost to localhost). But starting with test/integration deployments, ssh connections are more likely to be remote.

My solution for this problem is pretty simple. Since I provision all my boxes with ansible, I use the following snipped to create fresh ssh host keys for each box I run:

# Secure ssh Server-Keys
- local_action: file name=data state=directory
  sudo: false
- local_action: file name=data/ssh-host-keys state=directory
  sudo: false
- name: Creating individual SSH keys for this box
  local_action: command ssh-keygen -t {{ item }} -N "" -f data/ssh-host-keys/ssh_host_{{ item }}_key
                creates=data/ssh-host-keys/ssh_host_{{ item }}_key
  with_items: [ 'dsa', 'ecdsa', 'rsa' ]
  sudo: false
- name: Copying individual SSH private keys for this box to /etc/sshd/
  copy: src=data/ssh-host-keys/ssh_host_{{ item }}_key
        dest=/etc/ssh_host_{{ item }}_key mode=0600
  with_items: [ 'dsa', 'ecdsa', 'rsa' ]
  notify: Restart sshd
- name: Copying individual SSH public keys for this box to /etc/sshd/
  copy: src=data/ssh-host-keys/ssh_host_{{ item }}_key.pub
        dest=/etc/ssh_host_{{ item }}_key.pub mode=0644
  with_items: [ 'dsa', 'ecdsa', 'rsa' ]
  notify: Restart sshd

This should be easy to adapt to other provisioners, including shell provisioner. What it does:

First the script ensires that a local directory data/ssh-host-keys exists. There the new keys will be stored. Placing the keys outside the box allows to keep them even if the box is destroyed/recreated.

If the individual box keys are not present, they are created using ssh-keygen. There are 3 different key algorithms (dsa, ecdsa, and rsa), for each a key pair is created. After this, the keys are copied to /etc/sshd/in the box. Ansible checks if the keys are actually changes and notifies the handler named „Restart sshd“ in this case. The handler restarts the SSH Server so that the new keys are used.

This should work with all base boxes for both, local and remote providers. To provide new keys, simply delete data/ssh-host-keys and run the provisioner again.