[尝试学习Ansible时,我创建了一个实施困难的方案。假设我想使用known_hosts模块将所有SSH主机密钥添加到组中每个成员的/ etc / ssh / ssh_known_hosts文件中。我正在使用2.7,并试图远离with_
贬值的循环函数。我可以获得调试中列出的所有键,但是我找不到在模块循环中实现此功能的方法。为了一般地理解该操作,我假设并非所有主机都具有所有类型的密钥,因此它需要是动态的。这是我到目前为止的内容:
- 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>
事实包括这个有趣的部分:
...
"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",
...
调试的输出是:
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']"
}
一些完成每个主机所需的伪代码:
for host in groups['haproxy']:
for key in host.ansible_ssh_host_key_*_public:
<pass key to known_host module>
Ansible在嵌套循环中并不是很出色。我们可以解决这个问题,但这有点难看。 ecdsa
公钥使我们的生活变得复杂,因为尽管大多数密钥的类型在公钥文件中指定为ssh-<type>
,但对于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地址,但是添加起来应该不会太困难(将信息包括在第一步中生成的hostkeys
字典中,然后将其用于known_hosts模块的参数中) )。