一个计算机技术爱好者与学习者

0%

好好学Linux:使用PSSH批量管理Linux进阶篇

1. 前言

《使用PSSH批量管理Linux》一文中,学习了pssh的基本用法,实际上已经涵盖了pssh的大部分内容。

本文主要记录利用pssh和expect脚本来解决一些实际问题,就算是进阶篇了。

2. 批量添加密钥

《添加密钥认证访问》一节中,已经写清楚了挨个给客户机添加密钥的方法。但是,在客户机数量非常多的时候,挨个添加也很麻烦,写个脚本吧!(假设所有客户机用户都是test,密码都是123456)

参考无密钥登录的自动脚本实现expect - 自动交互脚本

2.1. 基线版本

1、新建脚本addkey.sh,内容为:

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/expect 
set timeout 60
set password 123456

spawn ssh-copy-id -i /home/test/.ssh/id_rsa.pub -p 22 test@192.168.56.101
expect "install the new keys"
send "\r"
expect "password:"
send "$password\r"
expect eof

2、执行脚本
chmod a+x addkey.sh

./addkey.sh

注意:

  • 如果密码是六个空格,那么set password " "即可。
  • expect "install the new keys"这里其实是不需要交互的,但是密码会直接出现在这里,所以加一个回车。

2.2. 升级版本

在使用ssh-copy-id命令的时候,有两种情况,一种是直接输入密码,就像基线版本;另一种情况是会先提示添加主机到known_hosts。

1、新建脚本addkey.sh,主要目的是测试,内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/expect 
set timeout 60
set password 123456

spawn ssh-copy-id -i /home/test/.ssh/id_rsa.pub -p 22 test@192.168.56.101
expect {
#first connect, no public key in ~/.ssh/known_hosts
"Are you sure you want to continue connecting (yes/no)?" {
send "yes\r"; exp_continue
}
#already has public key in ~/.ssh/known_hosts
"install the new keys" {
send "\r"; exp_continue
}
"password:" {
send "$password\r"; exp_continue
}
"Now try logging into the machine" {
#it has authorized, do nothing!
; exp_continue
}
}

2、执行脚本
chmod a+x addkey.sh

./addkey.sh

2.3. 批量版本

1、升级脚本,新建addkeys.sh,内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/expect 
set timeout 60
set password 123456

for {set i 101} {$i < 201} {incr i} {
spawn ssh-copy-id -i /home/test/.ssh/id_rsa.pub -p 22 test@192.168.56.$i
expect {
#first connect, no public key in ~/.ssh/known_hosts
"Are you sure you want to continue connecting (yes/no)?" {
send "yes\r"; exp_continue
}
#already has public key in ~/.ssh/known_hosts
"install the new keys" {
send "\r"; exp_continue
}
"password:" {
send "$password\r"; exp_continue
}
"Now try logging into the machine" {
#it has authorized, do nothing!
; exp_continue
}
}
}

2、执行脚本
chmod a+x addkeys.sh

./addkeys.sh

2.4. 批量删除

添加完密钥之后,发现部分机器不能免密登录。检查客户机中的authorized_keys文件,发现添加了两次密钥。于是决定删除重新添加。

1、管理机新建脚本delkeys.sh

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/expect 
set timeout 30
set password 123456

for {set i 101} {$i < 201} {incr i} {
spawn ssh test@192.168.56.$i "rm /home/test/.ssh/authorized_keys"
expect {
"password:" { send "$password\r"}
"No route to host" { send "\r" }
}
}

2、执行脚本
chmod a+x delkeys.sh

./delkeys.sh

注意,执行完之后检查一下最后一台客户机,也许会删除失败,不知道为什么。

2.5. 批量修改权限

删除后重新添加,依然无法登录,后来发现,是目录权限的问题。用户目录权限是750,~/.ssh权限是700, ~/.ssh/authorized_keys权限是600。

1、权限修改脚本chmods.sh

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/expect 
set timeout 30
set password 123456

for {set i 101} {$i < 201} {incr i} {
spawn ssh test@192.168.56.$i -t "sudo chmod 750 /home/test/ && sudo chmod 700 /home/test/.ssh && sudo chmod 600 /home/test/.ssh/authorized_keys"
expect {
"password:" { send "$password\r"; exp_continue }
"password for test" { send "$password\r"; exp_continue }
"No route to host" { send "\r" }
}
}

2、执行脚本
chmod a+x chmods.sh

./chmods.sh

2.6. 修改StrictModes

设置完权限,依然无法免密登录,猜测是StrictModes的问题。

1、编辑sshd_config
sudo vi /etc/ssh/sshd_config

2、找到StrictModes yes,改成StrictModes no

3、重启sshd,sudo service ssh restart

然后,依然失败。

2.7. 调试

1、不服,进行ssh登录调试,ssh -v test@192.168.56.102或者ssh -vvv test@192.168.56.102

1
2
3
4
5
6
7
8
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Offering RSA public key: /home/test/.ssh/id_rsa
debug1: Authentications that can continue: publickey,password
debug1: Trying private key: /home/test/.ssh/id_dsa
debug1: Trying private key: /home/test/.ssh/id_ecdsa
debug1: Trying private key: /home/test/.ssh/id_ed25519
debug1: Next authentication method: password

一番折腾,失败,失败,失败。。。

2、参考ssh免密登录失败问题排查思路,在客户机查看日志,cat /var/log/auth.log

调试方法:
(1)客户机执行tail -f /var/log/auth.log
(2)管理机执行ssh -v test@192.168.56.102

然而,各种尝试依然失败,失败,失败。。。

3、然后找到一篇重建home分区后出现的ssh公钥认证失败问题,猜测是SElinux的问题,于是在客户机执行:

sudo apt-get install policycoreutils

restorecon -r -vv /home/

然而,依然没有用。

2.8. 使用dsa密钥

1、生成dsa密钥
ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa

2、添加公钥到客户机
ssh-copy-id -i /home/test/.ssh/id_dsa.pub -p 22 test@192.168.56.102

3、管理机测试登录
ssh test@192.168.56.102

依然失败。换一个管理机重新添加密钥,依然失败,看来确实是客户机的锅。好吧,放弃了,不玩了!

3. 设置sudo免密

以上,假设已经实现了批量添加密钥,也就是实现了所有客户机的免密登录。但是,在客户机执行sudo命令的时候,会提示输入密码,也是很麻烦,所以接下来设置sudo免密执行。

1、管理机新建脚本addsudo.sh,内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/expect 
set timeout 10
set password 123456

for {set i 101} {$i <= 200} {incr i} {
spawn ssh test@192.168.56.$i -t "sudo -i"
expect "password for test:"
send "$password\r"
expect "*#"
send "echo test ALL = NOPASSWD: ALL >> /etc/sudoers \r"
expect "*#"
send "exit\r"
}

2、执行脚本
chmod a+x addsudo.sh

./addsudo.sh

4. 批量修改密码

《批量修改密码》一节中,我们采用的修改密码的方式是给所有的客户机都安装expect,然后发送脚本到客户机并执行脚本。给每台机器安装expect,不是一个好的做法。不妨参照设置sudo免密,在管理机执行脚本,虽然无法并行,但是胜在不需要给客户机安装expect。

不过,这次我们换一种脚本写法,使用bash脚本循环调用expect脚本。这种写法更好,更加稳定。因为在expect脚本中写循环语句,有些字符串会不显示,影响执行效果。

1、新建expect脚本m-chpasswd.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/expect 
set timeout 10
set newpassword 12345678
set i [lindex $argv 0]

spawn ssh test@192.168.56.$i -t "sudo passwd test"
expect "Enter new UNIX password:"
send "$newpassword\r"
expect "Retype new UNIX password:"
send "$newpassword\r"
expect "closed"
send "\r"
expect eof

2、新建bash脚本loop-passwd.sh

1
2
3
4
5
6
7
8
#!/bin/bash
for ((i=101;i<=200;i++))
do
echo "begin..."
echo $i
./m-chpasswd.sh $i
echo "end..."
done

3、执行脚本
chmod a+x m-chpasswd.sh

chmod a+x loop-passwd.sh

./loop-passwd.sh

5. 批量修改hosts

《批量修改hostname》一节中,我们给三台机器设置了主机名,比较简单。现在假设我们有100台机器需要管理,IP为192.168.56.101-200,现在要给它们设置主机名,同时修改它们的/etc/hosts文件,方便使用主机名相互寻找。

5.1. 自动生成hosts

1、在管理机新建脚本makehosts.sh,内容为:

1
2
3
4
5
6
7
8
9
#!/bin/bash

echo "127.0.0.1 localhost" > /home/test/hosts
NUM=101
while [ $NUM -lt 201 ]
do
echo "192.168.56.$NUM vk$NUM" >> /home/test/hosts
NUM=`expr $NUM + 1`
done

2、执行脚本
sudo chmod a+x makehosts.sh

./makehosts.sh

3、替换hosts
sudo cp hosts /etc/hosts

PS:添加一条新的记录到 /etc/hosts ,sudo bash -c "echo 192.168.56.201 vk201 >> /etc/hosts"

5.2. 修改客户机hosts

1、拷贝hosts文件到客户机
pscp -h hosts.txt ./hosts /home/test

2、替换hosts文件
pssh -h hosts.txt -i "sudo cp /home/test/hosts /etc/hosts"

6. 后记

本文在写作之前,思路很明确,以为可以半天搞定,没想到遇到了一个大坑:部分机器无法免密登录。大大小小试了十几种解决办法,未果,折腾了一整天,还是无奈放弃。

设置sudo免密时还有一个方案,就是写一个脚本发送到客户机,在客户机执行修改/etc/sudoers文件。但是要求所有客户机都安装了expect,这个很麻烦,不如在管理机操作。

7. 20180614更新

今天,突然冒出一个想法,如果换一个用户呢?不再用test,而是使用test2用户。于是,进行了测试。

1、客户机新建test2用户
sudo useradd -m test2 -s /bin/bash

sudo passwd test2

根据需要给予sudo权限,sudo adduser test2 sudo

2、管理机添加免密登录
ssh-copy-id -i .ssh/id_rsa.pub -p 22 test2@192.168.56.102

3、测试登录
ssh test2@192.168.56.102

登录成功!!!

那么,如果我删除test用户,再添加新的test用户,是不是也可以呢?

1、客户机删除test用户
sudo userdel -r test
提示userdel: user test is currently used by process 62901

2、查看最近登录情况
wlast

并没有人在使用这个账号,那就继续想办法删除。

3、使用vipw
sudo vipw,找到test用户那行,删除。

sudo vipw -s,找到test用户那行,删除。

4、删除test目录
cd /home && sudo rm -rf test

5、新建test用户
sudo useradd -m test -g test -s /bin/bash

sudo passwd test

sudo adduser test sudo

7、管理机添加免密登录
ssh-copy-id -i .ssh/id_rsa.pub -p 22 test@192.168.56.102

8、测试登录
ssh test@192.168.56.102

登录成功!!!问题完美结局,不过确实很麻烦。

如果,单纯地拷贝其他客户机的整个test用户目录呢?假设客户机A的IP为192.168.56.102,已经配置完成,可以免密登录;客户机B的IP为192.168.56.103,不可以免密登录。

1、删除客户机B的test目录下所有文件
rf -rf ./*

rf -rf ./.*

2、拷贝配置好的客户机A的test目录到客户机B
scp test@192.168.56.102:~/.* .

scp test@192.168.56.102:~/.ssh/* .ssh/

3、在管理机测试登录
ssh test@192.168.56.103

登录成功!!!这个方法明显更好,nice。