Ansible, Git and SSH

When using Ansible to configure your servers from scratch and deploy your software you are likely to run into the issue of your hosts not knowing each other yet. Ideally you pregenerate your SSH keys, construct the authorized_keys and known_hosts files and distribute them appropriately. However sometimes, especially during development of your provisioning setup, you'll need something more flexible (and less secure).

For instance when using Ansible to checkout out your software from Git over SSH it will simply hang if the server hosting the repository is unknown to the server doing the checkout. Under the hood it is just SSH waiting for user input whether or not to accept a new host key. In Ansible 1.5 there will be a new option to the Git module called accept_hostkey to accept any new host keys. However if you are on version 1.4.x you will need to accept the host with a workaround.

A crude way is to unconditionally append the host key to the known_hosts file by means of:

- name: SSH | Add Git repo host key to known_hosts file
  shell: ssh-keyscan {{ git_repo }} >> ~/.ssh/known_hosts
  sudo_user: prov

But this will add a line with the same Git repo host key for each invocation of Ansible. A better solution is to use the register keyword to capture the output of the ssh-keyscan command and conditionally, by means of the lineinfile command, add it to the known_hosts file:

- name: SSH | Find Git repo SSH host key
  shell: ssh-keyscan {{ git_repo }}
  register: git_repo_host_key
  sudo_user: prov

- name: SSH | Add Git repo host key to known_hosts file
  lineinfile: create=yes dest=/home/prov/.ssh/known_hosts line='{{ git_repo_host_key.stdout }}' state=present
  sudo_user: prov

You might be wondering why I'm using git_repo_host_key.stdout instead of simply git_repo_host_key. As it is, the variable supplied to register will be assigned a dictionary. This dictionary can easily be inspected using the debug command:

- debug: var=git_repo_host_key

Which outputs:

ok: [nldas0002] => {
    "git_repo_host_key": {
        "changed": true,
        "cmd": "ssh-keyscan ",
        "delta": "0:00:00.043550",
        "end": "2014-02-17 12:34:08.922907",
        "invocation": {
            "module_args": "ssh-keyscan",
            "module_name": "shell"
        "item": "",
        "rc": 0,
        "start": "2014-02-17 12:34:08.879357",
        "stderr": "#  SSH-2.0-OpenSSH_5.5p1 Debian-6+squeeze2",
        "stdout": "  ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5Aeo/ADwJwG4qPy9uajLzc4R2YT2rsNXhyHhVbpwnOYN+ba4h+2oh5tg0nJDtyIrjrdTSr5ySBu8MUXtVD1lt0VrxgtUY6+MbgPAB0Xw1b+jDxxClPy4+NdQjX4e5BCQFDsGWGtqAJWnRw+YxFUICfUHFWUigmEBHT+CjegN0Ifjpl/wDQbj+ngMthPd1kE4mgFEO89U36B+2uG1h/rZH252RVEdknWBOSMuj69uXW8xqfTxVETIJNb7vfnvPkJGOjE6Or24JTRGzKgvUFvEW5WO+O/2BZqIKCHris7AVJNbZEge35v9S+6QHM/5the0eKFig7JjPFRiIKH8Tg3vJ",
        "stdout_lines": [
            "  ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5Aeo/ADwJwG4qPy9uajLzc4R2YT2rsNXhyHhVbpwnOYN+ba4h+2oh5tg0nJDtyIrjrdTSr5ySBu8MUXtVD1lt0VrxgtUY6+MbgPAB0Xw1b+jDxxClPy4+NdQjX4e5BCQFDsGWGtqAJWnRw+YxFUICfUHFWUigmEBHT+CjegN0Ifjpl/wDQbj+ngMthPd1kE4mgFEO89U36B+2uG1h/rZH252RVEdknWBOSMuj69uXW8xqfTxVETIJNb7vfnvPkJGOjE6Or24JTRGzKgvUFvEW5WO+O/2BZqIKCHris7AVJNbZEge35v9S+6QHM/5the0eKFig7JjPFRiIKH8Tg3vJ"
    "item": ""

The host key found by ssh-keyscan in written to standard output. register logically saves all standard output in the stdout key of the register variable. Hence the usage of git_repo_host_key.stdout.

Comments !