linux - 将每个节点的 ssh key 授权给集群中所有节点的最佳方式
问题描述
我想创建一个集群基础设施,每个节点都通过 shh 与其他节点通信。我想使用 ansible 创建一个幂等剧本/角色,可以在集群初始化或新节点添加到集群时执行。我能够想到 2 个场景来实现这一目标。
第一个场景
task 1
从节点获取 ssh 密钥(可能将其分配给变量或写入文件)。- 然后在本地
task 2
执行的循环遍历其他节点并使用获取的密钥授权第一个节点。
此场景支持自由策略。无需等待所有主机即可执行任务。但它也要求所有节点都有相关的用户和公钥。因为如果您在同一个 playbook 中创建用户(由于免费策略),当task 2
开始运行时,可能会有未在集群中的其他节点上创建的用户。
尽管我是自由策略的忠实拥护者,但由于效率原因,我没有实施这种方案。它为节点集群建立连接。
第二个场景
task 1
按顺序从所有节点获取 ssh 密钥。然后将每个写入一个文件,该文件的名称根据ansible_hostname
.- 然后在本地
task 2
执行的循环遍历其他节点并授权所有密钥。
此场景仅支持线性策略。由于线性策略,您可以在同一剧本中创建用户,所有用户将在task 1
开始运行之前创建。
我认为这是一个有效的场景。它只为节点集群建立连接。我确实实现了它,我把我写的片段。
---
- name: create node user
user:
name: "{{ node_user }}"
password: "{{ node_user_pass |password_hash('sha512') }}"
shell: /bin/bash
create_home: yes
generate_ssh_key: yes
- name: fetch all public keys from managed nodes to manager
fetch:
src: "/home/{{ node_user }}/.ssh/id_rsa.pub"
dest: "tmp/{{ ansible_hostname }}-id_rsa.pub"
flat: yes
- name: authorize public key for all nodes
authorized_key:
user: "{{ node_user }}"
key: "{{ lookup('file', 'tmp/{{ item }}-id_rsa.pub')}}"
state: present
with_items:
- "{{ groups['cluster_node'] }}"
- name: remove local public key copies
become: false
local_action: file dest='tmp/' state=absent
changed_when: false
run_once: true
也许我可以使用lineinfile而不是fetch但除此之外我不知道这是否是正确的方法。当集群大小变大时需要很长时间(因为线性策略)。有没有更有效的方法可以使用?
解决方案
当 Ansible 循环通过 authorized_key 时,它将(大致)执行以下任务:
- 在控制节点上创建一个临时的authorized_key python脚本
- 将新的 authorized_key python 脚本复制到被管节点
- 使用适当的参数在受管节点上运行 authorized_key python 脚本
随着受管节点数量的增加,这增加了 n 2 ;有 1000 个盒子,这个任务每个盒子执行 1000 次。
我很难找到能够正确解释幕后情况的特定文档,所以我建议运行一个示例脚本来感受一下:
- hosts: all
tasks:
- name: do thing
shell: "echo \"hello this is {{item}}\""
with_items:
- alice
- brian
- charlie
这应该使用三重详细标志 ( -vvv
) 运行,并将输出通过管道传输到./ansible.log
(ex. ansible-playbook example-loop.yml -i hosts.yml -vvv > example-loop-output.log
)。搜索这些日志将有助于了解您的脚本如何随着检索到的列表的command.py
增加而扩展。sftp
"{{ groups['cluster_node'] }}"
对于小型集群,这种低效率是完全可以接受的。但是,在大型集群上可能会出现问题。
现在,该authorized_key
模块本质上只是生成一个 authorized_keys 文件,其中包含 a)已存在于 authorized_keys 中的密钥和 b)集群上每个节点的公钥。我们可以在控制节点上构建authorized_keys文件并将其部署到每个盒子上,而不是在每个盒子上重复生成authorized_keys文件。
可以使用assemble生成 authorized_keys 文件本身;这将获取所有收集的密钥并将它们连接到一个文件中。但是,如果我们只是synchronize
或copy
这个文件结束,我们将清除任何添加到授权密钥的非集群密钥。为了避免这种情况,我们可以使用blockinfile。blockinfile
可以管理 Ansible 添加的集群密钥。我们将能够在删除过时的密钥的同时添加新密钥。
- hosts: cluster
name: create node user and generate keys
tasks:
- name: create node user
user:
name: "{{ node_user }}"
password: "{{ node_user_pass |password_hash('sha512') }}"
shell: /bin/bash
create_home: yes
generate_ssh_key: yes
- name: fetch all public keys from managed nodes to manager
fetch:
src: "/home/{{ node_user }}/.ssh/id_rsa.pub"
dest: "/tmp/keys/{{ ansible_host }}-id_rsa.pub"
flat: yes
become: yes
- hosts: localhost
name: generate authorized_keys file
tasks:
- name: Assemble authorized_keys from a directory
assemble:
src: "/tmp/keys"
dest: "/tmp/authorized_keys"
- hosts: cluster
name: update authorized_keys file
tasks:
- name: insert/update configuration using a local file
blockinfile:
block: "{{ lookup('file', '/tmp/authorized_keys') }}"
dest: "/home/{{ node_user }}/.ssh/authorized_keys"
backup: yes
create: yes
owner: "{{ node_user }}"
group: "{{ node_group }}"
mode: 0600
become: yes
照原样,这个解决方案不容易与角色兼容;角色被设计为只处理主机的单个值(主机、组、组集等),上述解决方案需要在组和本地主机之间切换。
我们可以用 来解决这个问题delegate_to
,尽管它对于大型集群可能会有些低效,因为集群中的每个节点都会尝试组装authorized_keys。根据 ansible 项目的整体结构(以及从事该项目的团队的规模),这可能是理想的,也可能不是理想的;使用 浏览大型脚本时delegate_to
,很容易错过本地正在执行的某些操作。
- hosts: cluster
name: create node user and generate keys
tasks:
- name: create node user
user:
name: "{{ node_user }}"
password: "{{ node_user_pass |password_hash('sha512') }}"
shell: /bin/bash
create_home: yes
generate_ssh_key: yes
- name: fetch all public keys from managed nodes to manager
fetch:
src: "/home/{{ node_user }}/.ssh/id_rsa.pub"
dest: "/tmp/keys/{{ ansible_host }}-id_rsa.pub"
flat: yes
- name: Assemble authorized_keys from a directory
assemble:
src: "/tmp/keys"
dest: "/tmp/authorized_keys"
delegate_to: localhost
- name: insert/update configuration using a local file
blockinfile:
block: "{{ lookup('file', '/tmp/authorized_keys') }}"
dest: "/home/{{ node_user }}/.ssh/authorized_keys"
backup: yes
create: yes
owner: "{{ node_user }}"
group: "{{ node_group }}"
mode: 0600
become: yes
推荐阅读
- django - 尝试在已部署的 Heroku 应用程序上访问 Django /admin 时,在生产页面未找到错误
- python - 将 Scipy 模块 0.18 版本更新为 1.2.1 版本
- c# - C# 非通用 ISet 接口
- c# - 漂亮地递归打印集合
- opencv - opencv 是否在高斯模糊上使用了一些加速技术(即 opencl)?
- c++ - 对 enum 和 typedef 结构进行正确的位打包
- ansible - 将脚本变量的值传递给剧本输出
- javascript - Symfony Forms - 根据选择动态添加/删除字段
- java - Spring boot,事务性与调度一起使用
- hyperledger-fabric - Hyperledger Fabric 链码可以调用外部本地应用程序/二进制文件吗?