基于Ansible配置SSH无密码登录

背景

某些系统要求一组节点任何两节点之间配置SSH无密码登录,比如HDFS,原因是运行start-dfs.sh这样的脚本时,会通过ssh到其它节点执行命令。某些情况下,运维上也需要这样的配置。

对于我个人而言,这样的需求并不多,更多地是通过某一台console角色的机器对其它节点进行操作,比如说关键字批量查找日志批量查看进程启动时间等。使用Ansible做日志关键字查找,这种很Low的方式被李小者同学鄙视过,应该用日志系统代替,深以为然。

习惯把SSH无密码登录称为SSH打通,所以下文中提到打通一词,都代指SSH无密码登录

实现步骤

  1. 准备console角色的机器
  2. 利用Ansibleauthorized_key模块打通console节点和group中每一个节点
  3. 调用ssh-keygengroup中每一个节点上生成public key
  4. 收集group中每一个节点的public key到本地文件
  5. 再次利用Ansibleauthorized_key模块将上面收集到的public keys分发到group中每一个节点
  6. 关闭group中每一个节点两两之间的StrictHostKeyChecking

进行到第5步时已经可以实现无密码登录了,但是在建立ssh连接的时侯,会有以下prompt:

The authenticity of host * can’t be established.
RSA key fingerprint is *.
Are you sure you want to continue connecting (yes/no)?

所以增加了最后一步。

代码

详见Github

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# usage:
# ansible-playbook -i hosts ssh_nopass.yml -e "hosts=daily user=sel-fish"
- hosts: "{{ hosts }}"
vars:
- sshpubs_rslt: "{{ lookup('env', 'PWD') + '/sshpubs.rslt' }}"
tasks:
- name: Deliver My SSH key to Each Node
authorized_key:
user: "{{ user }}"
key: "{{ lookup('file', lookup('env', 'HOME') + '/.ssh/id_rsa.pub') }}"
key_options: ""
state: present
exclusive: no
- name: Generate SSH keys
shell: ssh-keygen -b 2048 -t rsa -q -N '' -f "{{ ansible_env.HOME }}/.ssh/id_rsa"
args:
creates: "{{ ansible_env.HOME }}/.ssh/id_rsa"
- name: Grab SSH keys
shell: cat "{{ ansible_env.HOME }}/.ssh/id_rsa.pub"
register: ssh_pub
# - debug:
# var: ssh_pub.stdout
- local_action: command bash -c 'rm -rf {{ sshpubs_rslt }}'
- local_action: command bash -c 'echo {{ ssh_pub.stdout }} >> {{ sshpubs_rslt }}'
- name: Deliver Grabbed SSH keys to Each Node
authorized_key:
user: "{{ user }}"
key: "{{ lookup('file', sshpubs_rslt) }}"
key_options: ""
state: present
exclusive: no
- name: turn off StrictHostKeyChecking
blockinfile:
dest: "{{ ansible_env.HOME }}/.ssh/config"
marker: "# {mark} ANSIBLE MANAGED BLOCK {{ hostvars[item]['inventory_hostname'] }}"
insertafter: EOF
create: yes
block: |
Host {{ hostvars[item]['inventory_hostname'] }}
StrictHostKeyChecking no
with_items:
- "{{ groups[hosts] }}"
- local_action: command bash -c 'rm -rf {{ sshpubs_rslt }}'

Ansible相关

  • authorized_key,添加public key,注意的点是exclusive建议使用默认的值no,如果设置成yes会删除(homedir)+/.ssh/authorized_keys中其它的public key
  • blockinfile,在文件中添加一块内容,通过marker来做可重入
  • local_action,ansible的这个文档中有提到local_action,但是没有单独的章节来介绍。可能是因为我上述的做法不太标准,持续寻找更标准的方法。
  • register,可用来存储task的返回到变量中,提供给其它task使用,包括stderrstdout

引用

[1] http://www.shellhacks.com/en/HowTo-Disable-SSH-Host-Key-Checking
[2] http://stackoverflow.com/questions/30662069/how-can-i-pass-variable-to-ansible-playbook-in-the-command-line
[3] http://stackoverflow.com/questions/26638180/write-variable-to-a-file-in-ansible
[4] http://stackoverflow.com/questions/26732241/ansible-save-registered-variable-to-file