How to generate host SSH keys via ansible?

Solution 1:

As far as I know the only reason why you would need to pipe a 'y' to ssh-keygen, is if your command is replacing an existing file. In my opinion this is not a good way to do something from a configuration management tool.

You should adjust your tasks to make them idempotent. Specifically if you add the creates: filename to your command, then the new keys will only be created when they don't already exist, instead of being replaced each time you run that playbook.

---
- hosts: all
  become: true
  gather_facts: false

  tasks:
  - name: Generate /etc/ssh/ RSA host key
    command : ssh-keygen -q -t rsa -f /etc/ssh/ssh_host_rsa_key -C "" -N ""
    args:
      creates: /etc/ssh/ssh_host_rsa_key

  - name: Generate /etc/ssh/ DSA host key
    command : ssh-keygen -q -t dsa -f /etc/ssh/ssh_host_dsa_key -C "" -N ""
    args:
      creates: /etc/ssh/ssh_host_dsa_key

  - name: Generate /etc/ssh/ ECDSA host key
    command : ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -C "" -N ""
    args:
      creates: /etc/ssh/ssh_host_ecdsa_key

If for some reason you wanted to replace those keys for example if they were too old or something you might want to add another task to remove them. Here is a simple delete

- file:
    state: absent:
    path: "{{item}}"
  loop:
  - /etc/ssh/ssh_host_rsa_key
  - /etc/ssh/ssh_host_dsa_key
  - /etc/ssh/ssh_host_ecdsa_key

If you wanted to delete files generated before a certain time, you could use the stat module to retrieve details about this files, and setup when conditions to selectively remove them if they were older then a certain date or something.

Solution 2:

The ansible command module does not pass commands through a shell. This means you can't use shell operators such as the pipe, and that is why you are seeing the pipe symbol in the output. As far as ansible is concerned, it has executed the command echo with all of the rest of the line as arguments to echo.

If you need the command line processed by a shell, use shell instead of command.

And, there ought to be a better way to regenerate ssh host keys, but I can't find one right now...


Solution 3:

Use the special module for this task:

- name: Generate an OpenSSH keypair with the default values (4096 bits, rsa)
  openssh_keypair:
    path: /home/youruser/.ssh/id_rsa
    owner: youruser
    group: youruser

- name: Fix owner of the generated pub key
  file:
    path: /home/youruser/.ssh/id_rsa.pub
    owner: youruser
    group: youruser

Solution 4:

Another option is to use user module. Positive side of this is that you'll get an idempotent task. Here is an example how to generate ssh keys on localhost:

- name: Generate ssh keys
  local_action:
    module: "user"
    name: "{{ lookup('env','USER') }}"
    generate_ssh_key: true
    ssh_key_type: "{{ item.0 }}"
    ssh_key_bits: "{{ item.1 }}"
    ssh_key_file: "{{ playbook_dir }}/{{ item.0 }}_{{ item.1 }}_key"
  with_together:
  - [ 'rsa', 'dsa' ]
  - [ 2048, 1024 ]
  loop_control:
    label: "{{ item.0 }}_{{ item.1 }}_key"

- name: Copy generated ssh keys to remote machine
  copy:
    src: "{{ playbook_dir }}/{{ item.0 }}_{{ item.1 }}_key"
    dest: "/etc/ssh/ssh_host_{{ item.0 }}_key{{ item.1 }}"
  with_nested:
  - [ 'rsa', 'dsa' ]
  - [ '', '.pub' ]
  notify:
  - Restart sshd
  loop_control:
    label: "/etc/ssh/ssh_host_{{ item.0 }}_key{{ item.1 }}"