Ansible 如何包含组中所有主机的所有主机密钥
在尝试学习Ansible的过程中,我创建了一个难以实现的场景。假设我想使用known_hosts模块将所有SSH主机密钥添加到组中每个成员的/etc/SSH/SSH_known_hosts文件中。我使用的是2.7,并试图使用折旧循环函数远离Ansible 如何包含组中所有主机的所有主机密钥,ansible,Ansible,在尝试学习Ansible的过程中,我创建了一个难以实现的场景。假设我想使用known_hosts模块将所有SSH主机密钥添加到组中每个成员的/etc/SSH/SSH_known_hosts文件中。我使用的是2.7,并试图使用折旧循环函数远离。我可以获得debug中列出的所有键,但我无法找到一种方法在与模块的循环中实现它。为了理解如何一般地做到这一点,我假设并非所有主机都具有所有类型的键,因此它需要是动态的。以下是我到目前为止的情况: - name: SSH Host Keys Debug
。我可以获得debug中列出的所有键,但我无法找到一种方法在与模块的循环中实现它。为了理解如何一般地做到这一点,我假设并非所有主机都具有所有类型的键,因此它需要是动态的。以下是我到目前为止的情况:
- 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'] }}"
然后创建一个循环函数,根据模块拥有的键数,在每个主机上多次调用该模块
- 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>
调试的输出为:
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']"
}
编辑1
一些伪代码实现了我对每个主机的期望:
for host in groups['haproxy']:
for key in host.ansible_ssh_host_key_*_public:
<pass key to known_host module>
Ansible并不擅长嵌套循环。我们可以解决这个问题,但有点难看。ecdsa
公钥使我们的生活变得复杂,因为对于大多数密钥,公钥文件中的类型指定为ssh-
,而对于ecdsa
密钥,显然是ecdsa-sha2-nistp256
以下是我的想法:
---
- hosts: all
tasks:
# In this first task, we construct for each host in the `all` group
# a list of dictionaries that contain information about the ssh
# hostkeys, extracted from the `ansible_ssh_host_key_*` variables.
#
# We are looping over all variables (and values) for this host for which
# the variable name starts with `ansible_ssh_host_key`.
- set_fact:
hostkeys: >-
{{ (hostkeys|default([])) + [{
'hostname': inventory_hostname,
'type': item.key|regex_replace('ansible_ssh_host_key_([^_]+)_public', '\1'),
'key': item.value
}] }}
loop: >-
{{ hostvars[inventory_hostname]|
dict2items|
selectattr('key', 'match', '^ansible_ssh_host_key_')|list }}
- hosts: localhost
gather_facts: false
tasks:
# Now we take those per-host lists and construct one combined list
# with all the information.
- set_fact:
hostkeys: "{{ (hostkeys|default([])) + hostvars[item].hostkeys }}"
loop: "{{ groups.all }}"
- hosts: all
gather_facts: false
tasks:
# Finally, on each host, we write a known_hosts file containing all the
# host keys. I'm using an alternate path here because I didn't want
# to actually write to /etc/ssh/known_hosts on my system.
- known_hosts:
path: "/tmp/hosts-{{ inventory_hostname }}"
name: "{{ item.hostname }}"
key: "{{ item.hostname }} {{ keytype }} {{ item.key }}"
vars:
keytype: >-
{{ (item.type == 'ecdsa')|
ternary('ecdsa-sha2-nistp256', 'ssh-' ~ item.type) }}
loop: "{{ hostvars.localhost.hostkeys }}"
loop_control:
label: "{{ item.hostname }} {{ keytype }} {{ item.key[:20] }}..."
我没有在这里讨论ip地址,但是添加ip地址应该不会太困难(在第一步生成的hostkeys
字典中包含该信息,然后在known_hosts模块的参数中使用该信息)。谢谢。我想知道是否需要执行中间步骤并将其保存在变量中。因为我是在角色中使用它的,所以我需要对它进行一些调整。我也有一些错误,hostvars不是dict2items的dict,我不能让角色在localhost上只运行一次,但是我可以让它为每个主机存储,所以它看起来已经足够好了。
- 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] }}...\""
---
- hosts: all
tasks:
# In this first task, we construct for each host in the `all` group
# a list of dictionaries that contain information about the ssh
# hostkeys, extracted from the `ansible_ssh_host_key_*` variables.
#
# We are looping over all variables (and values) for this host for which
# the variable name starts with `ansible_ssh_host_key`.
- set_fact:
hostkeys: >-
{{ (hostkeys|default([])) + [{
'hostname': inventory_hostname,
'type': item.key|regex_replace('ansible_ssh_host_key_([^_]+)_public', '\1'),
'key': item.value
}] }}
loop: >-
{{ hostvars[inventory_hostname]|
dict2items|
selectattr('key', 'match', '^ansible_ssh_host_key_')|list }}
- hosts: localhost
gather_facts: false
tasks:
# Now we take those per-host lists and construct one combined list
# with all the information.
- set_fact:
hostkeys: "{{ (hostkeys|default([])) + hostvars[item].hostkeys }}"
loop: "{{ groups.all }}"
- hosts: all
gather_facts: false
tasks:
# Finally, on each host, we write a known_hosts file containing all the
# host keys. I'm using an alternate path here because I didn't want
# to actually write to /etc/ssh/known_hosts on my system.
- known_hosts:
path: "/tmp/hosts-{{ inventory_hostname }}"
name: "{{ item.hostname }}"
key: "{{ item.hostname }} {{ keytype }} {{ item.key }}"
vars:
keytype: >-
{{ (item.type == 'ecdsa')|
ternary('ecdsa-sha2-nistp256', 'ssh-' ~ item.type) }}
loop: "{{ hostvars.localhost.hostkeys }}"
loop_control:
label: "{{ item.hostname }} {{ keytype }} {{ item.key[:20] }}..."