此脚本虽然是python脚本,但是里面调用了太多os.system命令(囧,哥的python太水了),只要懂shell脚本,就可用shell来完成自动配置ssh互信脚本。为何当初没有使用except,因为本公司的centos中没有携带except安装包,centos还是精简版,很多依赖包都没有。我不想太折腾。
我会一点python,使用python是理所当然的。原计划用python paramiko模块来实现密码放文件里登陆,但是paramiko安装编译需要gcc环境。精简的centos也没有,弄了半天,几十个依赖包弄得我头晕眼花,大小达到50M,不通用,懒得做了。
现在的这个脚本需要手动输入远程主机密码,不适用于成百上千台服务器部署ssh互信。在网上找了很久,确认ssh 不支持脚本输入密码。
由于我的业务上经常也就同时做10台以内的ssh互信,这个脚本就满足需求了。
1、不交互自动生成密钥文件
用ssh-keygen 的-f和-P参数,生成密钥不需要交互。如下:
rm -rf ~/.ssh/
/usr/bin/ssh-keygen -t rsa -f ~/.ssh/id_rsa -P ''
cp ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys
2、自动添加/etc/hosts中主机名与IP对应关系,并推送到远端主机
这个简单,手动配置或脚本配置都行。互信成功后,用脚本批量推送就行了。
3、推送密钥文件至远端主机
最简单的方法:scp -r /root/.ssh root@hostb:/root
但是咱公司精简的centos没有关闭selinux。拷贝过去还是不能无密码登陆(不信可自己测试)。如果采用输入两次密码,第一次登陆上去关闭selinux,第二次拷贝/root/.ssh过去也可以(不想梅开二度)。我采用的是另一种方法,只需输入一次密码即可。怎么实现的?见代码。
第一次登陆交互需要输入yes获取对端公钥
.ssh文件拷贝过去后,第一次登陆会让你输入yes接收公钥,而且,不止自己登陆对方要输入yes,每一台登陆远端主机都要输入yes,如果一共10台服务器,每台输入9次,共需要输入81次。这个怎么破?见代码。
[root@VueOS scripts]#python ssh_trust.py
Input node's info. Usage:hosta/192.168.0.101. Press Enter is complete.
Please input Node info: nodea/192.168.2.151
#获取节点信息,主机名与IP,生产中尽量使用主机名,方便以后环境迁移
check ip address success!
Please input Node info: nodeb/192.168.2.158
Please input Node info:
Are you sure you want to set ssh mutual trust? (yes/no) yes
#是否要设置互信?因为本次互信是我部署其它程序的前提。互信一次就能配置成功,程序可能多次失败,不需要每次运行都做互信。
Generating public/private rsa key pair.
Created directory '/root/.ssh'.
Your identification has been saved in/root/.ssh/id_rsa.
Your public key has been saved in/root/.ssh/id_rsa.pub.
The key fingerprint is:
79:97:67:36:e5:db:0d:4c:8e:20:63:a2:59:f6:bf:17root@VueOS
The key's randomart image is:
+--[ RSA 2048]----+
| |
| + + . . .|
| = + + . * o |
| o S . + O .|
| o .E+ o+|
| . . .o|
| .. |
| .. |
+-----------------+
#自动生成完密钥后,把密钥拷贝到其它节点
Scp ssh key file too another node...
The authenticity of host 'nodeb(192.168.2.158)' can't be established.
RSA key fingerprint isc6:2d:8e:e0:a1:e1:2e:c3:77:c7:1d:ef:92:7c:41:ba.
Are you sure you want to continueconnecting (yes/no)? yes
Warning: Permanently added'nodeb,192.168.2.158' (RSA) to the list of known hosts.
root@nodeb's password:
#输入远端节点密码
copy ssh file successful
Done
Warning: Permanently added'nodea,192.168.2.151' (RSA) to the list of known hosts.
local nodea RsaKey remote nodea issuccessful
local nodea RsaKey remote nodeb issuccessful
known_hosts 100% 802 0.8KB/s 00:00
hosts 100% 84 0.1KB/s 00:00
[root@VueOS scripts]#ssh nodeb
Last login: Fri Apr 4 15:34:06 2014 from 192.168.2.72
[root@VueOS ~]#exit
logout
Connection to nodeb closed.
[root@VueOS scripts]# ssh nodea
Last login: Fri Apr 4 11:55:58 2014 from hosta
[root@VueOS ~]# exit
Connection to nodea closed.
#如上所示,互信自动配置成功。
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<code>[root@VueOS scripts]</code><code># cat ssh_trust.py</code>
<code>#!/usr/bin/python</code>
<code>import</code> <code>datetime</code>
<code>import</code> <code>os,sys,time</code>
<code>import</code> <code>commands</code>
<code>#这个函数是校验IP合法性的。</code>
<code>def</code> <code>check_ip(ipaddr):</code>
<code> </code><code>import</code> <code>sys</code>
<code> </code><code>addr</code><code>=</code><code>ipaddr.strip().split(</code><code>'.'</code><code>)</code>
<code> </code><code>#print addr</code>
<code> </code><code>if</code> <code>len</code><code>(addr) !</code><code>=</code> <code>4</code><code>:</code>
<code> </code><code>print</code> <code>"check ip address failed!"</code>
<code> </code><code>sys.exit()</code>
<code> </code><code>for</code> <code>i </code><code>in</code> <code>range</code><code>(</code><code>4</code><code>):</code>
<code> </code><code>try</code><code>:</code>
<code> </code><code>addr[i]</code><code>=</code><code>int</code><code>(addr[i])</code>
<code> </code><code>except</code><code>:</code>
<code> </code><code>sys.exit()</code>
<code> </code><code>if</code> <code>addr[i]<</code><code>=</code><code>255</code> <code>and</code> <code>addr[i]></code><code>=</code><code>0</code><code>:</code>
<code> </code><code>pass</code>
<code> </code><code>else</code><code>:</code>
<code> </code><code>print</code> <code>"check ip address failed!"</code>
<code> </code><code>i</code><code>+</code><code>=</code><code>1</code>
<code> </code><code>else</code><code>:</code>
<code> </code><code>print</code> <code>"check ip address success!"</code>
<code>node_dict</code><code>=</code><code>{}</code>
<code>host_all</code><code>=</code><code>[]</code>
<code>host_ip_all</code><code>=</code><code>{}</code>
<code>#这个函数获取输入的节点信息,并校验输入的IP是否合法。</code>
<code>def</code> <code>get_nodes():</code>
<code> </code><code>while</code> <code>True</code><code>:</code>
<code> </code><code>node</code><code>=</code><code>raw_input</code><code>(</code><code>"""Input node's info. Usage: hosta/192.168.0.101. Press Enter is complete.</code>
<code>Please input Node info: """</code><code>)</code>
<code> </code><code>if</code> <code>len</code><code>(node)</code><code>=</code><code>=</code><code>0</code><code>:</code>
<code> </code><code>return</code> <code>2</code>
<code> </code><code>node_result</code><code>=</code><code>node.strip().split(</code><code>'/'</code><code>)</code>
<code> </code><code>host_ip_all[node_result[</code><code>0</code><code>]]</code><code>=</code><code>[node_result[</code><code>1</code><code>],'']</code>
<code> </code><code>#print node_result</code>
<code> </code><code>if</code> <code>len</code><code>(node_result[</code><code>0</code><code>])</code><code>=</code><code>=</code><code>0</code><code>:</code>
<code> </code><code>print</code> <code>"Hostname is failed!"</code>
<code> </code><code>check_ip(node_result[</code><code>1</code><code>])</code>
<code> </code><code>#node_dict[node_result[0]]=[node_result[1]]</code>
<code> </code><code>host_all.append(node_result[</code><code>0</code><code>])</code>
<code> </code><code>#print node_dict</code>
<code> </code><code>local_ip_status,local_ip_result</code><code>=</code><code>commands.getstatusoutput(</code><code>"""ifconfig |grep 'inet addr'|awk -F '[: ]+' '{print $4}' """</code><code>)</code>
<code> </code><code>local_ip</code><code>=</code><code>local_ip_result.split(</code><code>'\n'</code><code>)</code>
<code> </code><code>#print host_all</code>
<code> </code><code>if</code> <code>len</code><code>(host_all)</code><code>=</code><code>=</code><code>1</code><code>:</code>
<code> </code><code>if</code> <code>node_result[</code><code>1</code><code>] </code><code>in</code> <code>local_ip:</code>
<code> </code><code>pass</code>
<code> </code><code>else</code><code>:</code>
<code> </code><code>print</code> <code>"The first IP must be native IP."</code>
<code> </code><code>sys.exit()</code>
<code>#这个函数生成ssh密钥文件,简单的3条shell命令</code>
<code>def</code> <code>create_sshkey_file():</code>
<code> </code><code>os.system(</code><code>"rm -rf ~/.ssh/"</code><code>)</code>
<code> </code><code>os.system(</code><code>"/usr/bin/ssh-keygen -t rsa -f ~/.ssh/id_rsa -P '' "</code><code>)</code>
<code> </code><code>os.system(</code><code>"cp ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys"</code><code>)</code>
<code>#这个函数配置/etc/hosts文件</code>
<code>def</code> <code>add_etc_hosts():</code>
<code> </code><code>for</code> <code>i </code><code>in</code> <code>host_ip_all.keys():</code>
<code> </code><code>#print host_ip_all.keys()</code>
<code> </code><code>#判断/etc/hosts是否存在</code>
<code> </code><code>if</code> <code>os.path.exists(</code><code>'/etc/hosts'</code><code>):</code>
<code> </code><code>pass</code>
<code> </code><code>os.system(</code><code>"touch /etc/hosts"</code><code>)</code>
<code> </code><code>#删除掉原有主机名项,并添加新的对应关系</code>
<code> </code><code>os.system(</code><code>"sed -i '/%s/d' /etc/hosts"</code><code>%</code><code>i)</code>
<code> </code><code>#print i,host_ip_all[i][0]</code>
<code> </code><code>os.system(</code><code>''' echo '%s %s\r' >>/etc/hosts '''</code><code>%</code><code>(host_ip_all[i][</code><code>0</code><code>],i))</code>
<code> </code><code>#with open('/etc/hosts','ab') as f :</code>
<code> </code><code># f.write('%s %s\r'%(host_ip_all[i][0],i))</code>
<code>#拷贝ssh密钥文件</code>
<code>def</code> <code>scp_sshkey():</code>
<code> </code><code>#把/root/.ssh文件放在/tmp下,并开使其生效。</code>
<code> </code><code>os.system(</code><code>"sed -i /tmp/d /etc/exports"</code><code>)</code>
<code> </code><code>os.system(</code><code>"echo '/tmp *(rw)' >>/etc/exports"</code><code>)</code>
<code> </code><code>os.system(</code><code>"exportfs -r"</code><code>)</code>
<code> </code><code>os.system(</code><code>"cp -a /root/.ssh /tmp"</code><code>)</code>
<code> </code><code>os.system(</code><code>"chmod 777 /tmp"</code><code>)</code>
<code> </code><code>os.system(</code><code>"/etc/init.d/iptables stop"</code><code>)</code>
<code> </code><code>os.system(</code><code>"chmod 777 /tmp/.ssh/id_rsa"</code><code>)</code>
<code> </code><code>os.system(</code><code>"chmod 777 /tmp/.ssh"</code><code>)</code>
<code> </code><code>print</code> <code>'Scp ssh key file too another node...'</code>
<code> </code><code>print</code> <code>host_all[</code><code>1</code><code>:]</code>
<code> </code><code>localhost</code><code>=</code><code>host_all[</code><code>0</code><code>]</code>
<code> </code><code>local_ip</code><code>=</code><code>host_ip_all[localhost][</code><code>0</code><code>]</code>
<code> </code><code>#输入一次密码,登陆上去后执行了N条命令,挂载nfs,拷贝.ssh,修改权限,卸载等等。</code>
<code> </code><code>for</code> <code>i </code><code>in</code> <code>host_all[</code><code>1</code><code>:]:</code>
<code> </code><code>os.system(</code><code>'''/usr/bin/ssh %s "/bin/umount -lf /mnt >/dev/null 2 &>1;/bin/mount %s:/tmp /mnt ;rm -rf /root/.ssh;mkdir /root/.ssh;sleep 3; /bin/cp -a /mnt/.ssh/* /root/.ssh/ ;echo 'copy ssh file successful';/bin/chmod 600 /root/.ssh/id_rsa;/bin/chmod 700 /root/.ssh;/bin/umount -lf /mnt "'''</code><code>%</code><code>(i,local_ip))</code>
<code> </code><code>print</code> <code>"Done"</code>
<code>#测试ssh互信是否成功</code>
<code>def</code> <code>test_sshkey(host):</code>
<code> </code><code>for</code> <code>host_n </code><code>in</code> <code>host_all:</code>
<code> </code><code>try</code><code>:</code>
<code> </code><code>#to gain public key</code>
<code> </code><code>#使用StrictHostKeyChecking跳过公钥接收提示。并远程执行命令,连上了自然会输出成功信息。</code>
<code> </code><code>os.system(</code><code>''' ssh -o "StrictHostKeyChecking no" %s "echo -e local %s RsaKey remote %s is successful" '''</code><code>%</code><code>(host_n,host_all[</code><code>0</code><code>],host_n))</code>
<code> </code><code>except</code><code>:</code>
<code> </code><code>print</code> <code>"\033[31mlocal %s RsaKey remote %s is fail.\033[0m"</code><code>%</code><code>(host_all[</code><code>0</code><code>],host_n)</code>
<code>else</code><code>:</code>
<code> </code><code>#全部测试完成后,把known_hosts文件拷贝到所有主机。一台服务器获取了所有公钥,那拷贝到远端自然是所有节点都有对方公钥了。</code>
<code> </code><code>for</code> <code>host_m </code><code>in</code> <code>host_all[</code><code>1</code><code>:]:</code>
<code> </code><code>#copy ~/.ssh/known_hosts file to another host...</code>
<code> </code><code>os.system(</code><code>"""/usr/bin/scp ~/.ssh/known_hosts %s:~/.ssh/known_hosts"""</code><code>%</code><code>host_m)</code>
<code> </code><code># copy hosts file to another host...</code>
<code> </code><code>os.system(</code><code>"""/usr/bin/scp /etc/hosts %s:/etc/hosts """</code><code>%</code><code>host_m)</code>
<code>#函数执行部分</code>
<code>get_nodes()</code>
<code>a</code><code>=</code><code>raw_input</code><code>(</code><code>"Are you sure you want to set ssh mutual trust? (yes/no) "</code><code>).strip()</code>
<code>#提示一下,做不做互信要让用户选择。</code>
<code>if</code> <code>a</code><code>=</code><code>=</code><code>"yes"</code><code>:</code>
<code> </code><code>create_sshkey_file()</code>
<code> </code><code>add_etc_hosts()</code>
<code> </code><code>scp_sshkey()</code>
<code> </code><code>test_sshkey(</code><code>'192.168.2.73'</code><code>)</code>
<code>elif</code> <code>a</code><code>=</code><code>=</code><code>"no"</code><code>:</code>
<code>#输入no就代表互信已做好了。接下来执行别的代码。</code>
<code> </code><code>pass</code>
<code> </code><code>print</code> <code>'Byebye,Please input yes or no.'</code>
<code> </code><code>sys.exit()</code>
<code></code>