In trying to learn Ansible, I created a scenario that I'm having trouble implementing. Say I want to use the known_hosts module to add all SSH host keys to each member's /etc/ssh/ssh_known_hosts files in the group. I'm using 2.7 and trying to stay away from the with_
depreciated loop functions. I can get all the keys listed in debug, but I can't figure a way do it in a loop with the module. To understand how to do this generically I'm assuming that not all hosts will have all types of keys, so it needs to be dynamic. Here is what I have so far:
- name: SSH Host Keys Debug
debug:
msg: "Hostname: {{ hostvars[item].ansible_hostname }},
IP Address: {{ hostvars[item].ansible_eth0.ipv4.address }},
Keys: {{ hostvars[item] | select('match', '^ansible_ssh_host_key_.+_public') | map('extract', hostvars[item]) | list }}"
loop: "{{ groups['haproxy'] }}"
And then create a loop function that calls the module multiple times per host based on the number of keys it has.
- name: SSH Host Keys
become: true
known_hosts:
dest: /etc/ssh/ssh_known_hosts
name: "{{ item.ansible_hostname }}"
key: "{{ item.ansible_hostname }},{{ item.ansible_eth0.ipv4.address }} {{ item.<public_key> }}"
loop: <nested loop that provides hostname, ipv4_address and public_keys>
The facts include this interesting section:
...
"ansible_ssh_host_key_ecdsa_public": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDhGYjJS18MSCojIDLA9MTxITHpy+IOBFCHR+ZSZMyr5ek0r4RCK+zo6D1WZNs0dWcUB7IUJMThKcPpxdbrC0rk=",
"ansible_ssh_host_key_ed25519_public": "AAAAC3NzaC1lZDI1NTE5AAAAIBZjI7AJ5SHU31V6Vs9WTxLss/5gU/3pJJlTTzpJxcyr",
"ansible_ssh_host_key_rsa_public": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDH3OunSMQfaksqVxlLhKUyDUegaw6QuOiemgBWwwJypiDRshF0N2xQ6/RqHYA/gY+oDieIHzbs6OtxNt7JbSOwkjnKrYBkqzVQqtCtjpJ+pbzAcxdYwjfEYNlV/Fq41XrsFaWQgbQB57yS3dJVneheXskSc/mIwX3a2143X1CFLSz9krhwcNIWaAhZFMlV0ZqRSvH
DoiDZ4rQ4qQ4riaTm/NXjJzJjQqSiwUZUQdBtv88Ik1trQJUwKsYq2WZKiuv6yp/XVLL1/LLYQQJeH2GRqy8EI1TYRunrfHEo/D3T5QPsaJ1up/YNPtRP+H3dA68Ybwowb8m5A9IoAtHbHdEr",
...
The output from the debug is:
TASK [base_conf : SSH Host Keys Debug] ************************************************************************************************
task path: /home/rleblanc/code/ansible_learn/base_conf/tasks/main.yml:30
ok: [ansible-a] => (item=ansible-a) => {
"msg": "Hostname: ansible-a, IP Address: 192.168.99.48, Keys: ['AAAAB3NzaC1yc2EAAAADAQABAAABAQDH3OunSMQfaksqVxlLhKUyDUegaw6QuOiemgBWwwJypiDRshF0N2xQ6/RqHYA/gY+oDieIHzbs6OtxNt7JbSOwkjnKrYBkqzVQqtCtjpJ+pbzAcxdYwjfEYNlV/Fq41XrsFaWQgbQB57yS3dJVneheXskSc/mIwX3a2143X1CFLSz9krhwcNIWaAhZFMlV0ZqRSvHDoiDZ4rQ4qQ4riaTm/NXjJzJjQqSiwUZUQdBtv88Ik1trQJUwKsYq2WZKiuv6yp/XVLL1/LLYQQJeH2GRqy8EI1TYRunrfHEo/D3T5QPsaJ1up/YNPtRP+H3dA68Ybwowb8m5A9IoAtHbHdEr', 'AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDhGYjJS18MSCojIDLA9MTxITHpy+IOBFCHR+ZSZMyr5ek0r4RCK+zo6D1WZNs0dWcUB7IUJMThKcPpxdbrC0rk=', 'AAAAC3NzaC1lZDI1NTE5AAAAIBZjI7AJ5SHU31V6Vs9WTxLss/5gU/3pJJlTTzpJxcyr']"
}
Edit 1
Some pseudo code that accomplishes what I'd like for each host:
for host in groups['haproxy']:
for key in host.ansible_ssh_host_key_*_public:
<pass key to known_host module>
Possible Solution for Roles
As I was trying to do this in a role, I needed to adjust the accepted answer a bit. I'm putting it here for posterity.
- name: Generate Host key list per host
set_fact:
myhostkeys: >-
{{ (myhostkeys | default([]) + [{
'hostname': inventory_hostname,
'ip_addr': hostvars[inventory_hostname]['ansible_default_ipv4']['address'],
'type': item | regex_replace('ansible_ssh_host_key_([^_]+)_public', '\1'),
'key': hostvars[inventory_hostname][item]
}]) }}
loop: >-
{{ hostvars[inventory_hostname] | select('match', '^ansible_ssh_host_key_.*_public') | list }}
- name: Combine all host keys
set_fact:
hostkeys: >-
{{ (hostkeys | default([])) + hostvars[item]['myhostkeys'] }}
loop: >-
{{ ansible_play_hosts_all }}
- name: Add all host keys
become: true
known_hosts:
path: /etc/ssh/ssh_known_hosts
name: "{{ item.hostname }}"
key: "{{ item.hostname }},{{ item.ip_addr }} {{ keytype }} {{ item.key }}"
vars:
keytype: >-
{{ (item.type == 'ecdsa') |
ternary('ecdsa-sha2-nistp256', 'ssh-' ~ item.type) }}
loop: >-
{{ hostvars[inventory_hostname]['hostkeys'] }}
loop_control:
label: "Key: \"{{ item.hostname }},{{ item.ip_addr }} {{ keytype }} {{ item.key[:20] }}...\""