Friday, December 5, 2014

Ansible: Generating a SSH pub key file and uploading to other host to sync files from there

Update: check the comments for new workflows

Original from 19/May/2014... updated!

I found this workflow for our systems:

  1. Up the new box.
  2. Generate keys in that new box.
  3. "Fetch" the pub key from the new server to the ansible server.
  4. Copy that key to authorized_keys file of the other server (from ansible server).
  5. Execute a rsync from the new server without asking key to the other server.
My trick is:

It is working perfectly but i would like to know if another way is possible.


Update 06/Dec/2014:

Same workflow, new lines  (optimized?):

Similar but not equal :)


  1. - name: 'get'
    shell: cat "{{ some.dir + '/' + some.user + '/.ssh/' }}"
    delegate_to: "{{ master_first }}"
    register: id_rsa_pub
    changed_when: false

    - authorized_key: user="{{ some.user }}" key="{{ id_rsa_pub.stdout }}"

    #extra work
    - name: Get rid of SSH "Are you sure you want to continue connecting (yes/no)? BY NAME" query
    command: "{{ item }}"
    delegate_to: "{{ master_first }}"
    - sh -c 'ssh-keyscan -H {{ inventory_hostname }} >> {{ some.dir }}/{{ some.user }}/.ssh/known_hosts'
    - sh -c 'ssh-keyscan -H >> {{ some.dir }}/{{ some.user }}/.ssh/known_hosts'

    - name: Get rid of SSH "Are you sure you want to continue connecting (yes/no)? BY IP" query
    command: sh -c 'ssh-keyscan -H {{ hostvars[item].ansible_default_ipv4.address }} >> {{ some.dir }}/{{ some.user }}/.ssh/known_hosts'
    delegate_to: "{{ master_first }}"
    with_items: play_hosts

    1. "get rid of" update:
      - name: Get rid of SSH "Are you sure you want to continue connecting (yes/no)? BY NAME" query
      delegate_to: "{{ master_first }}"
      name={{ item }}
      key="{{ lookup('pipe', 'ssh-keyscan -t rsa {{ item }}') }}"
      - "{{ inventory_hostname }}"
      - ""

  2. Create ssh key (only when missing) for an existing user. Important: if the user doesn't exit, it will be created, which may not be desiderable:

    - name: postgresql user with ssh key
    generate_ssh_key: yes
    home: /var/lib/postgresql
    name: postgres

    Add key of remote hosts (name and IP) from two groups in the Ansible inventory, correctly reporting if added or already present:

    - name: add other node keys
    when: item != inventory_hostname
    shell: |
    ssh-keygen -f /var/lib/postgresql/.ssh/known_hosts -F {{ item }} && echo 'key present' ||
    ssh-keyscan -H -T 10 {{ item }} >> /var/lib/postgresql/.ssh/known_hosts &&
    ssh-keyscan -H -T 10 {{ hostvars[item].ansible_default_ipv4.address }} >> /var/lib/postgresql/.ssh/known_hosts
    register: result
    changed_when: not 'key present' in result.stdout
    - groups.dbslaves
    - groups.dbmaster

  3. New ideas in

  4. I used standard modules and delegate_to to come up with a pretty nice way of doing this:

    I want to create a user on my bastion server(s) and create a key pair for that user and upload the public key to the user's authorized keys on all of my web servers for example.

    First in my webservers role I make sure the user has been created:
    - name: Create web server admin user
    name: myadmin
    state: present

    Then in my bastion server role I want to create the admin user and generate a key pair at the same time (the registered variable will have the user's public key):
    - name: Create admin user with ssh key pair
    name: myadmin
    generate_ssh_key: yes
    state: present
    register: myadmin

    In that same bastion role I want to install the public key to all of my web servers (this is where the delegate_to comes in)
    - name: Install myadmin public key on every web server
    user: myadmin
    key: "{{ myadmin.ssh_public_key }}"
    delegate_to: "{{ item }}"
    with_items: "{{ groups['webservers'] }}"