加密安全-openssh服务

发布于:2024-04-28 ⋅ 阅读:(29) ⋅ 点赞:(0)

openssh服务

1、ssh配置

ssh第一次远程链接需要客户端输入yes,如下:

# 109节点第一次通过ssh链接106,需要手动输入yes
root@109:~$ ssh 192.168.31.106
The authenticity of host '192.168.31.106 (192.168.31.106)' can't be established.
ED25519 key fingerprint is SHA256:dZL40Ckk5dkI2n62NcUEU/+Vj6FENiqW/zjd3kZgopU.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

当手动输入yes后,109会获取到106的公钥文件:公钥位置在106节点的/etc/ssh/下,会有多个.pub结尾的公钥文件,109链接的时候会随机一个公钥文件。

109节点的获取106的公钥会记录在/root/.ssh/known_hosts中

# 109 /root/.ssh/下kknown_hosts文件中记录的从106节点获取的公钥文件
root@109:~$ cat .ssh/known_hosts
192.168.31.107 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMzMzsO8NhPpBateNHzqgyiSVC5ZLpTy8Eti4UKgwwAW
192.168.31.107 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGaR8Q20ByXq3DS1ozmY+8rPmA7MexsccZSLOQFY3h93WQfgj57EA/kuI/MXpBsWsiDUacVH+S71iZ6GfgZu7U8=
192.168.31.106 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILorL+gwGvbbIaFESCZZdc1z161XrYpFOrqaFH9oGRV8

106节点存放公钥的位置:

[root@192 ~]# cd /etc/ssh
[root@192 ssh]# ll
total 604
-rw-r--r--. 1 root root     581843 Apr 11  2018 moduli
-rw-r--r--. 1 root root       2276 Apr 11  2018 ssh_config
-rw-------. 1 root root       3907 Apr 11  2018 sshd_config
-rw-r-----. 1 root ssh_keys    227 Dec 16 10:47 ssh_host_ecdsa_key
-rw-r--r--. 1 root root        162 Dec 16 10:47 ssh_host_ecdsa_key.pub
-rw-r-----. 1 root ssh_keys    387 Dec 16 10:47 ssh_host_ed25519_key
-rw-r--r--. 1 root root         82 Dec 16 10:47 ssh_host_ed25519_key.pub
-rw-r-----. 1 root ssh_keys   1679 Dec 16 10:47 ssh_host_rsa_key
-rw-r--r--. 1 root root        382 Dec 16 10:47 ssh_host_rsa_key.pub

禁止首次连接的询问过程

场景:如果管理的主机较多,不想每个第一次链接都输入yes,只需要修改客户端配置文件/etc/ssh/ssh_config配置即可:

# 需要将StrictHostKeyChecking前的注释去掉,将ask改为no即可,如32行
root@109:/etc/ssh$ vim ssh_config
...
28 #   CheckHostIP no
 29 #   AddressFamily any
 30 #   ConnectTimeout 0
 31 # StrictHostKeyChecking ask
 32 StrictHostKeyChecking no
...

第二种修改方式:

# 直接使用sed命令进行修改,在客户端109上执行
root@109:~$ sed -i.bak '/StrictHostKeyChecking/s/.*/StrictHostKeyChecking no/' /etc/ssh/ssh_config

禁止root用户ssh登录

# 将PermitRootLogin改为no
[jinguc@CRM ~]$ sudo vim /etc/ssh/sshd_config
#LoginGraceTime 2m
PermitRootLogin no
#StrictModes yes

2、格式

# 一般习惯使用第一种
ssh [user@]host [COMMAND]
ssh [-l user] host [COMMAND]

注意:一般使用ssh user@主机IP时,如果省略user,则默认按照当前用户执行链接,如:

109连接106

# 109当前用户为root,省略user则默认使用root登录,需要输入106的root密码
root@109:~$ id
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:unconfined_t:s0-s0:c0.c1023
root@109:~$ ssh 192.168.31.106

如果109当前用户为app,在连接106的时候需要输入106app的密码,如果106没有app用,则连接失败。

3、常见选项

-p port:远程服务器监听的端口
-b 指定连接的源IP
-v 调试模式
-C 压缩方式
-X 支持x11转发
-t 强制伪tty分配,如:ssh -t remoteserver1 ssh -t remoteserver2   ssh   
remoteserver3
-o option   如:-o StrictHostKeyChecking=no
-i <file> 指定私钥文件路径,实现基于key验证,默认使用文件: ~/.ssh/id_dsa, 
~/.ssh/id_ecdsa, ~/.ssh/id_ed25519,~/.ssh/id_rsa等

范例:-t参数

场景:如果公司有台服务器106节点,无法直接通过公网登录,只能通过107进行登录,你只能通过109登录107,正常登录方式是先通过109ssh登录107,在通过107ssh登录106,太繁琐了,可以通过-t参数直接通过109登录106,只不过是需要依次输入107、106的密码,如下:

root@109:~$ ssh -t 192.168.31.107 ssh -t 192.168.31.106
root@192.168.31.107's password: 
root@192.168.31.106's password: 
Last login: Sun Mar  3 21:52:53 2024 from 192.168.31.107
# 查看IP地址,已经登录到目标106主机了
[root@192 ~]# ip a |grep 192.168.31
    inet 192.168.31.106/24 brd 192.168.31.255 scope global noprefixroute ens192

范例:远程执行命令

[root@centos6 ~]#ssh 10.0.0.8 "sed -i.bak 
'/StrictHostKeyChecking/s/.*/StrictHostKeyChecking no/' /etc/ssh/ssh_config"
root@10.0.0.8's password: 
[root@centos6 ~]#

范例:在远程主机运行本地shell脚本

# 当前主机为106
[root@192 shell]# hostname -I
192.168.31.106

# 脚本内容,获取当前主机IP
[root@192 shell]# cat test.sh 
#! /bin/bash
hostname -I

# 在107上执行106的脚本,当前主机为106
[root@192 shell]# ssh 192.168.31.107 /bin/bash < test.sh 
root@192.168.31.107's password: 
192.168.31.107

4、查看远程登录失败记录-lastb

通过lastb可以查看从服务端(远程端)登录服务器的登录记录,这里的记录全部是错误的记录,正常登录记录通过last进行查看。

例如:

在109节点未远程登录107的时候,可以查看107的记录

[root@192 ~]# lastb
btmp begins Sat Mar  2 23:57:47 2024

通过109节点登录107节点

# 109节点通过xfsd用户登录107,由于不知道密码,三次登录失败
root@109:~/.ssh$ ssh xfsd@192.168.31.107
xfsd@192.168.31.107's password: 
Permission denied, please try again.
xfsd@192.168.31.107's password: 
Permission denied, please try again.
xfsd@192.168.31.107's password: 

root@109:~/.ssh$ 

通过lastb查看109的登录记录,有三次登录记录

[root@192 ~]# lastb
xfsd     ssh:notty    192.168.31.109   Sun Mar  3 07:06 - 07:06  (00:00)    
xfsd     ssh:notty    192.168.31.109   Sun Mar  3 07:06 - 07:06  (00:00)    
xfsd     ssh:notty    192.168.31.109   Sun Mar  3 07:06 - 07:06  (00:00)    

btmp begins Sun Mar  3 07:06:17 2024

通过命令查看记录登录信息的文件

# 该文件为二进制文件,无法直接打开
[root@192 ~]# ll /var/log/btmp
-rw-------. 1 root utmp 1152 Mar  3 07:06 /var/log/btmp

# 可以通过lastb -f +文件打开
[root@192 ~]# cd /var/log
[root@192 log]# ll btmp
-rw-------. 1 root utmp 1152 Mar  3 07:06 btmp
[root@192 log]# lastb -f btmp
xfsd     ssh:notty    192.168.31.109   Sun Mar  3 07:06 - 07:06  (00:00)    
xfsd     ssh:notty    192.168.31.109   Sun Mar  3 07:06 - 07:06  (00:00)    
xfsd     ssh:notty    192.168.31.109   Sun Mar  3 07:06 - 07:06  (00:00)    

btmp begins Sun Mar  3 07:06:17 2024

例:

查看链接107节失败次数最多的前三个IP

查看链接失败的列表

# 查看链接失败情况,可以看到一共涉及4个IP链接
[root@192 log]# lastb -f btmp
gxy      ssh:notty    192.168.31.103   Sun Mar  3 07:47 - 07:47  (00:00)    
gxy      ssh:notty    192.168.31.105   Sun Mar  3 07:41 - 07:41  (00:00)    
gxy      ssh:notty    192.168.31.105   Sun Mar  3 07:41 - 07:41  (00:00)    
gxy      ssh:notty    192.168.31.105   Sun Mar  3 07:41 - 07:41  (00:00)    
gxy      ssh:notty    192.168.31.105   Sun Mar  3 07:41 - 07:41  (00:00)    
gxy      ssh:notty    192.168.31.105   Sun Mar  3 07:41 - 07:41  (00:00)    
gxy      ssh:notty    192.168.31.105   Sun Mar  3 07:41 - 07:41  (00:00)    
app      ssh:notty    192.168.31.106   Sun Mar  3 07:37 - 07:37  (00:00)    
app      ssh:notty    192.168.31.106   Sun Mar  3 07:37 - 07:37  (00:00)    
app      ssh:notty    192.168.31.109   Sun Mar  3 07:36 - 07:36  (00:00)    
app      ssh:notty    192.168.31.109   Sun Mar  3 07:36 - 07:36  (00:00)    
app      ssh:notty    192.168.31.109   Sun Mar  3 07:36 - 07:36  (00:00)    
xfsd     ssh:notty    192.168.31.109   Sun Mar  3 07:06 - 07:06  (00:00)    
xfsd     ssh:notty    192.168.31.109   Sun Mar  3 07:06 - 07:06  (00:00)    
xfsd     ssh:notty    192.168.31.109   Sun Mar  3 07:06 - 07:06  (00:00)
btmp begins Sun Mar  3 07:06:17 2024
# 统计行数,一共17条
[root@192 log]# lastb -f btmp |wc -l
17

统计链接失败次数最多的前三个IP

# 前三的IP分别为109的6次,105的6次,106的2次
[root@192 log]# lastb -f /var/log/btmp |awk '{print $3}'|sort |uniq -c |sort -nr |head -3
      6 192.168.31.109
      6 192.168.31.105
      2 192.168.31.106

5、基于密钥对验证(免密登录)

原理:在本机生成公钥和私钥,然后将公钥传到需要链接的主机中,

1、首先在客户端生成一个对密钥(ssh-keygen)

2、并将客户端的公钥ssh-copy-id拷贝到服务器

3、当客户端再次发送一个链接请求,包括IP、用户名

4、服务端得到客户端的请求后,会到authorized_keys中查找,如果有响应的IP和用户,就会随机生成一个字符串。

5、服务端将使用客户端拷贝过来的公钥进行加密,然后发送给客户端。

6、得到服务端发过来的消息后,客户端会使用私钥进行解密,然后将解密后的字符串发送给服务端。

7、服务端接受到客户端发过来的字符串后,跟之前的字符串进行对比,如果一致,就允许免密码登录。

登录方式:(A免密登录B)

在客户端(A)生成密钥对:

# 一般只需要执行ssh-keygen,rsa是加密方式,-P表示是否给密钥设置密码
ssh-keygen -t rsa [-p 'password'] [-f "~/.ssh/id_rsa"]

把公钥文件传输至远端服务器(B)对应用户的家目录

ssh-copy-id [-i [identity_file]] [user@]host

例:

192.168.31.105要免密登录192.168.31.106

在105节点生成密钥对

[root@192 ~]# ll .ssh
ls: 无法访问.ssh: 没有那个文件或目录
[root@192 ~]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
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:
SHA256:8pQeqUoI69iP764H75G81zb2b7ZBSMviJv2TopkonPE root@192.168.31.105
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|                 |
|          .      |
|         = o     |
|.     . S + .    |
| ooo . O o .     |
|...*= o.*  ..    |
|o.+oE=.=*.o o.   |
|..+XX.++ +o=o.   |
+----[SHA256]-----+
# 已经生成了密钥对
[root@192 ~]#
总用量 8
-rw-------. 1 root root 1679 310 22:44 id_rsa
-rw-r--r--. 1 root root  401 310 22:44 id_rsa.pub

传至106节点

# 传之前在106节点查看下在root目录下是否存在.ssh目录
[root@192 ~]# ll .ssh
ls: cannot access .ssh: No such file or directory

# 在105节点进行传输公钥文件到106节点
[root@192 ~]# ssh-copy-id root@192.168.31.106
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '192.168.31.106 (192.168.31.106)' can't be established.
ECDSA key fingerprint is SHA256:lpOhqq5qjk87p7qYvFOeOfWH7ii8ed3sJsvygU00Dv8.
ECDSA key fingerprint is MD5:d0:f9:5d:5c:76:f3:29:00:2c:1f:35:d4:80:01:a0:5f.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.31.106's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'root@192.168.31.106'"
and check to make sure that only the key(s) you wanted were added.

查看106节点是否收到105的公钥文件

[root@192 ~]# cat .ssh/authorized_keys 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDyb/VlU1BKSvyHCbr7D1INT6kG29areHQlojcn84L9F
ReavOcpWYCaQDSNw1fVX0ybvvKM4Du2flIb5GTEEnxMN/Jtrb7riabfKy3bzXRo2yxC6ouSObyZK+gA7B
NgZ313yWFez1JTXBC6WzD7ayDV9mkRStD0oHxt/9hSQKTEtRpSYTiJt3meLlQ/juMu9sFpGftNFDzObm/
HJBy7UOm3SezkLhX26mpQQki+Qu2wKcH12b0423Gt3rnMRXqZCN5VWF6ZA6GmKSERUkq1o8c+3AKGwxTF
Tvhkoe68+2uDGi/XUssqx9XT3axCLm6z0cQ9kDH+RUduwO37OqXu6PNN 
root@192.168.31.105

登录验证

在105节点登录106节点

# 105节点已经可以免密登录106节点了
[root@192 ~]# ssh 192.168.31.106
Last login: Sun Mar 10 10:03:37 2024 from gxymacbook-pro
[root@192 ~]# hostname -I
192.168.31.106

批量执行脚本

105节点已做106与107的免密,现在在105节点执行脚本,是其在106与107节点均能执行105节点的脚本。

# 105节点的脚本内容,就是一个获取IP地址的脚本
[root@192 ~]# cat shell/ip.sh 
#! /bin/bash
hostname -I

# 在105上批量执行,是其能在106与107上执行该脚本
[root@192 ~]# while read ip ;do ssh $ip bash < /root/shell/ip.sh; done </root/hosts
192.168.31.106 192.168.31.183 
192.168.31.107

对私钥口令进行加密

场景:如果免密做的是多台,如100台,服务器私钥(105的私钥)变得比较重要,如果一旦私钥被人窃取(如破解root密码后窃取),那么就相当于破解100台的密码,所以对私钥进行加密就变得格外需要。

加密口令

ssh-keygen -p

**注意:**如果已经生成密钥对了是否可以在进行加密,是可以的,只是对密钥加密的时候会提示你重新加密而已。

例:

场景:对上述实验中105节点的密钥进行加密。

# 对105节点的私钥进行加密
[root@192 ~]# ssh-keygen -p
Enter file in which the key is (/root/.ssh/id_rsa): # 提示要密码的私钥,直接回车
Enter new passphrase (empty for no passphrase): # 提示输入加密的密码,第一次加密显示没有密码
Enter same passphrase again: # 再次输入密码
Your identification has been saved with the new passphrase. # 加密完成

验证

# 登录106节点进行验证,输入设置的私钥密码
[root@192 ~]# ssh 192.168.31.106
Enter passphrase for key '/root/.ssh/id_rsa': 
Last login: Sun Mar 10 23:29:07 2024 from 192.168.31.105
[root@192 ~]# hostname -I
192.168.31.106

# 登录107节点验证
[root@192 ~]# ssh 192.168.31.107
Enter passphrase for key '/root/.ssh/id_rsa': 
Last login: Sun Mar 10 10:03:57 2024 from 192.168.31.161
[root@192 ~]# hostname -I
192.168.31.107

**思考:**当初通过密钥对(免密)的方式进行加密就是为了方便以后管理多台服务器时不在重复输入密码,但对密钥加密就又变成交互式的每次都需要输入密码了,这相当于又回到从前的尴尬场景了。如何解决这个问题呢?可以通过代理的方式管理,这样就不需要每次输入私钥的密码了,又能解决私钥被盗用后直接使用的风险。

启动代理

# 启用代理
[root@192 ~]# ssh-agent bash

# 钥匙通过命令添加给代理
[root@192 ~]# ssh-add
Enter passphrase for /root/.ssh/id_rsa: 
Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa)

验证:

# 登录106、107已经可以不在输入密码了
[root@192 ~]# ssh 192.168.31.106
Last login: Mon Mar 11 01:48:29 2024 from 192.168.31.105
[root@192 ~]# hostname -I
192.168.31.106

[root@192 ~]# ssh 192.168.31.107
Last login: Mon Mar 11 01:49:52 2024 from 192.168.31.105
[root@192 ~]# hostname -I
192.168.31.107

**存在的问题:**代理进程是随终端的,当终端退出后代理进程就不再了,如果想批量管理,还是需要输入密钥的加密密码。就是每次想批量管理,必须执行下命令(启动代理):ssh-agent bash

# 当前IP
[root@192 ~]# hostname -I
192.168.31.105 

# 执行退出命令,发现退出后IP仍是105,这是因为执行第一个exit是退出了代理工具
[root@192 ~]# exit
exit
[root@192 ~]# hostname -I
192.168.31.105 

# 代理进程已经不在了
[root@192 ~]# ps aux |grep agent
root     25300  0.0  0.0 112724   988 pts/0    S+   13:59   0:00 grep --color=auto agent

# 再次跳转106,仍需要输入105密钥的加密密码
[root@192 ~]# ssh 192.168.31.106
Enter passphrase for key '/root/.ssh/id_rsa': 
Last login: Mon Mar 11 01:56:46 2024 from 192.168.31.105
[root@192 ~]# hostname -I
192.168.31.106

**场景:**我们有时候不是固定在某一台电脑进行远程服务器的,可能在办公环境的不同电脑,也可能在家里的电脑,也可能借用其他同事的电脑,每次登录输入账号密码显然是不安全的,此时我们只需要在自己电脑上生成密钥对,将公钥上传到服务器,将私钥拷贝到U盘中,需要登录的以后调用U盘中的私钥即可实现登录。如果在别人的电脑上留的有私有文件,一定记得在使用完成后彻底删除该私钥文件。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

可以点击保存文件

在这里插入图片描述

此处可以将密钥导出后点击完成
在这里插入图片描述
上传导出后的公钥到服务器

通过xftp上传id_rsa_2048.pub到105服务器,上传后复制到authorized_keys文件中,如果没有该文件就创建一个。

# 105节点目录下并没有authorized_keys文件
[root@192 ~]# ll .ssh
总用量 12
-rw-------. 1 root root 1766 311 13:45 id_rsa
-rw-r--r--. 1 root root  401 310 22:44 id_rsa.pub
-rw-r--r--. 1 root root  352 310 23:06 known_hosts

# 上传公钥后直接将公钥内容输入到authorized_keys(该文件为新建文件,因为本机没有,如果存在追加即可)
[root@192 ~]# cat id_rsa_2048.pub > .ssh/authorized_keys

# 到此公钥导入完成
[root@192 ~]# ll .ssh
总用量 16
-rw-r--r--. 1 root root  380 311 14:21 authorized_keys
-rw-------. 1 root root 1766 311 13:45 id_rsa
-rw-r--r--. 1 root root  401 310 22:44 id_rsa.pub
-rw-r--r--. 1 root root  352 310 23:06 known_hosts

# 修改权限为600,authorized_keys的权限为600
[root@192 .ssh]# chmod 600 authorized_keys

# 查看公钥
[root@192 ~]# cat .ssh/authorized_keys 
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAtqAHuVR26OpUv5gUnrpwOEzuzM2Svcd2EFc1GvZWfct9DzKJiPSJ+9ew9qzSnwbiSdTs+YFQTUQUiOWkIH8aAVy2FGMooiMu07nhZakC6+6iIB1Ybj2Lco9sPJc8KJdo7H/o5bdbFY3PFPtj1OD/kjfteBvVBZIOpP1+e6GDDMz157Rhxn6AF3NTmtWgYragKirF52ZdZstwvjleItqxQ2KLf/HqndSpjkf9mXu77c7z9kcSDuPt6abAs01xdiAKKsIkT6uUbyohKexCbLsKDvoMZf9XOu1IoBDgnQP46Wd5ZEnlewjChRoP4stzqlYKrVLNqh3UVSi7h8oiLOMNbQ==[root@192 ~]#

进行密钥登录验证

将xshell中原来的基于用户密码的105节点删除,点击新增

在这里插入图片描述
输入IP,用户名输入root,方法选择公钥登录Public Key
在这里插入图片描述
点确定后双击105节点进行登录,此时会进行用户身份验证,用户密钥选择刚导出来的密钥文件,然后点击确定即可正常登录。

6、基于expect实现基于ssh的key部署

场景:如果项目上分配了100台主机加一个跳板机(linux系统),需要在跳板机上对这100台主机做免密配置,如果将跳板机的公钥手动一台一台拷贝到这100台主机,显然不是明智的选择,耗时耗力,这个时候我们就可以脚本实现一件部署。这里我以三台主机为例进行演示。

如:新分了三台主机,分别为:192.168.31.106、192.168.31.107、192.168.31.109,其中106节点是跳板机,需要对107与109做免密配置。

注意:操作之前一定要检查下106节点是否存在/root/.ssh目录,如果存在最后将其删除,因为里边可能会有已生成的密钥对,如果存在密钥对,脚本有可能执行不成功,执行前必须要删除密钥对,最后将.ssh目录删除。要保证107与109节点的密码一致,例子中的密码为Qwerdf2…

hosts.txt内容:

[root@192 shell]# cat hosts.txt
192.168.31.107
192.168.31.109

[root@192 shell]# ll
total 8
-rw-r--r--. 1 root root  30 Mar 14 09:38 hosts.txt
-rwxr-xr-x. 1 root root 651 Mar 14 10:12 push_ssh_key.sh

编写脚本

vim push_ssh_key.sh
#!/bin/bash

#set -x
# 这里边的密码是107、109节点的密码
PASS="Qwerdf12.."
hosts_file="hosts.txt"

# 安装 expect 包
rpm -q expect &> /dev/null || yum -y install expect &> /dev/null

# 生成 SSH 密钥,-t rsa:指定密钥的类型为RSA。RSA是一种非对称加密算法,
# -P "":指定私钥的密码为空。在这里,我们将私钥设置为空密码,这意味着生成的私钥不会有密码保护,可以直接使用而无需输入密码。
# -f /root/.ssh/id_rsa:指定生成的私钥文件的路径和名称。在这里,私钥将被保存在 /root/.ssh/ 目录下,并命名为 id_rsa。
ssh-keygen -t rsa -P "" -f /root/.ssh/id_rsa &> /dev/null && echo "ssh key is created"

# 读取 hosts.txt 文件中的 IP 地址,并进行 SSH 免密钥验证
while read IP ; do
    expect &> /dev/null <<EOF
        set timeout 20
        spawn ssh-copy-id -i /root/.ssh/id_rsa.pub root@$IP
        expect {
            "yes/no" { send "yes\n";exp_continue }
            "password" { send "$PASS\n" }
        }
        expect eof
EOF
    echo "$IP is ready"
done < "$hosts_file"

验证:

脚本执行完成后在106节点登录107、109节点验证。

# 验证可以正常从106节点跳转到107、109节点
[root@192 ~]# ssh 192.168.31.107
Last login: Thu Mar 14 10:17:23 2024 from 192.168.31.106
[root@192 ~]# hostname -I
192.168.31.107 
 [root@192 ~]# exit
logout
Connection to 192.168.31.107 closed.
[root@192 ~]# ssh 192.168.31.109
Last login: Thu Mar 14 22:17:13 2024 from 192.168.31.106
root@109:~$ hostname -I
192.168.31.109

7、其他ssh工具—scp

方式:

scp [options] [user@]host:/sourcefile /destpath
scp [options] /sourcefile [user@]host:/destpath
scp [options] [user@]host1:/sourcetpath [user@]host2:/destpath

常用选项:

-C 压缩数据流
-r 递归复制
-p 保持原文件的属性信息
-q 静默模式
-P PORT 指明remote host的监听的端口

8、其他ssh工具—rsync

rsync工具可以基于ssh和rsync协议实现高效率的远程系统之间复制文件,使用安全的shell连接做为传输方式,比scp更快,基于增量数据同步,即只复制两方不同的文件,此工具来自于rsync包。

**注意:**通信两端主机都需要安装 rsync软件。

rsync  -av /etc server1:/tmp #复制目录和目录下文件
rsync  -av /etc/ server1:/tmp #只复制目录下文件

常见选项

-n 模拟复制过程
-v 显示详细过程
-r 递归复制目录树
-p 保留权限
-t 保留修改时间戳
-g 保留组信息
-o 保留所有者信息
-l 将软链接文件本身进行复制(默认)
-L 将软链接文件指向的文件复制
-u 如果接收者的文件比发送者的文件较新,将忽略同步
-z 压缩,节约网络带宽
-a 存档,相当于-rlptgoD,但不保留ACL(-A)和SELinux属性(-X)
--delete 源数据删除,目标数据也自动同步删除

安装rsync

[root@192 ~]# yum install -y rsync

# 查看版本
[root@192 data]# rsync --version
rsync  version 3.1.2  protocol version 31
Copyright (C) 1996-2015 by Andrew Tridgell, Wayne Davison, and others.
Web site: http://rsync.samba.org/
Capabilities:
    64-bit files, 64-bit inums, 64-bit timestamps, 64-bit long ints,
    socketpairs, hardlinks, symlinks, IPv6, batchfiles, inplace,
    append, ACLs, xattrs, iconv, symtimes, prealloc

rsync comes with ABSOLUTELY NO WARRANTY.  This is free software, and you
are welcome to redistribute it under certain conditions.  See the GNU
General Public Licence for details.

8.1、不同主机之间的数据同步

例:

在192.168.31.106同步文件到192.168.31.109,目录名都为data,106与107已做免密,并且两个节点都安装了rsync,同步前我们先生成一些测试数据。

# 192.168.31.106
[root@192 data]# dd if=/dev/zero of=test1 bs=1M count=10
[root@192 data]# dd if=/dev/zero of=test2 bs=1M count=10
[root@192 data]# dd if=/dev/zero of=test3 bs=1M count=10

[root@192 data]# ll
total 30720
-rw-r--r--. 1 root root 10485760 Mar 14 22:27 test1
-rw-r--r--. 1 root root 10485760 Mar 14 22:28 test2
-rw-r--r--. 1 root root 10485760 Mar 14 22:28 test3

# 192.168.31.107 data目录为空
[root@192 data]# ll
total 0

进行数据同步

# 在106节点执行
[root@192 data]# rsync -av /data 192.168.31.107:/data
sending incremental file list
data/
data/test1
data/test2
data/test3

sent 31,465,191 bytes  received 77 bytes  20,976,845.33 bytes/sec
total size is 31,457,280  speedup is 1.00

# 在107节点查看同步数据
[root@192 data]# ll
total 0
drwxr-xr-x. 2 root root 45 Mar 14 22:28 data
[root@192 data]# tree
.
└── data
    ├── test1
    ├── test2
    └── test3

1 directory, 3 files

**注意:**从同步过程来看,106节点同步的命令中写的是/data目录,并不是/data/,所以同步的时候会将目录及目录下的文件全部同步过去。

我们将107节点的/data目录下的所有内容删掉从新同步。

# 删除107节点/data下的所有内容
[root@192 data]# rm -rf *
[root@192 data]# ll
total 0

# 再次同步,在106上执行,这次目录改为/data/
[root@192 data]# rsync -av /data/ 192.168.31.107:/data
sending incremental file list
./
test1
test2
test3

sent 31,465,178 bytes  received 76 bytes  12,586,101.60 bytes/sec
total size is 31,457,280  speedup is 1.00

# 107节点查看同步数据
[root@192 data]# ll
total 30720
-rw-r--r--. 1 root root 10485760 Mar 14 22:27 test1
-rw-r--r--. 1 root root 10485760 Mar 14 22:28 test2
-rw-r--r--. 1 root root 10485760 Mar 14 22:28 test3
[root@192 data]# tree
.
├── test1
├── test2
└── test3

0 directories, 3 files

**注意:**从同步过程来看,106节点同步是用的是/data/,是加了“/”的,可以看到本次同步结果是直接将106 data目录下的所有数据同步到了107节点,并未包含106的data目录。目录后加“/”与不加是有区别的。

只同步已更新的文件-u参数

更新test1文件,test2、test3保持不变

# 106节点
# 在test1文件后追加一个空行,发现多了一个字节
[root@192 data]# echo >> test1 
[root@192 data]# ll
total 47104
-rw-r--r--. 1 root root 10485761 Mar 14 22:54 test1
-rw-r--r--. 1 root root 10485760 Mar 14 22:28 test2
-rw-r--r--. 1 root root 10485760 Mar 14 22:28 test3

再次同步验证

# 106同步
[root@192 data]# rsync -auv /data/ 192.168.31.107:/data
sending incremental file list
test1

sent 14,274 bytes  received 19,505 bytes  22,519.33 bytes/sec
total size is 31,457,281  speedup is 931.27

# 107
[root@192 data]# ll
total 30724
-rw-r--r--. 1 root root 10485761 Mar 14 22:54 test1
-rw-r--r--. 1 root root 10485760 Mar 14 22:28 test2
-rw-r--r--. 1 root root 10485760 Mar 14 22:28 test3

从106的同步过程看,只同步了test1。

8.2、单台主机内部不同目录之间的数据同步

如:

主机内部同步/home/gxy/test数据到/home/gxy/test2

[gxy@106-server ~]$ sudo rsync -avz /home/gxy/test/ /home/gxy/test2
sending incremental file list
./
01/
01/a.txt
01/b.txt
02/
02/c.txt

sent 319 bytes  received 88 bytes  814.00 bytes/sec
total size is 29  speedup is 0.07

8.3、 rsync的日志记录

rsync 是一个用于在 Unix 和类 Unix 系统之间同步文件和目录的工具,它本身没有直接提供日志记录功能。然而,你可以使用一些技巧来实现日志记录:

  1. 通过重定向输出到日志文件:你可以将 rsync 的输出重定向到一个文件中,以便记录同步过程中的输出信息。例如:

    rsync -avz /source/path/ /destination/path/ > rsync_log.txt
    

    这将把 rsync 命令的输出保存到名为 rsync_log.txt 的文件中。

  2. 使用 -log-file 选项rsync 提供了 -log-file 选项,你可以使用它来指定一个日志文件来记录同步过程中的输出信息。例如:

    rsync -avz --log-file=rsync_log.txt /source/path/ /destination/path/
    

    这会将 rsync 命令的输出记录到名为 rsync_log.txt 的文件中。

  3. 结合 tee 命令tee 命令可以将输出既发送到标准输出,又保存到文件中。这可以在命令行中实现比较复杂的日志记录需求。例如:

    rsync -avz /source/path/ /destination/path/ | tee rsync_log.txt
    

    这将会在终端上显示 rsync 命令的输出,并将其同时追加到名为 rsync_log.txt 的文件中。

9、ssh服务配置

配置文件:/etc/ssh/sshd_config(服务端)

常见参数:

Port 22   # 服务端口
#AddressFamily any
#ListenAddress 0.0.0.0    # 默认情况下22端口会监听在当前主机的所有IP,每个IP的22端口都可
# 以链接,如果在生成中某台服务器有两个IP,一个外网IP,一个内网IP,而你只想让内网IP通过ssh端口
# 进行链接,可以把这个地址绑定在内网IP上,格式:ListenAddress 内网IP
#ListenAddress ::

# 这个三个是私钥路径
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key

# Ciphers and keying
#RekeyLimit default none

# Logging
#SyslogFacility AUTH
#LogLevel INFO

# Authentication:

#LoginGraceTime 2m   # 宽限期2分钟,如果在登录的时候该输入密码或者输入yes的时候,什么也不
# 操作,但是这个时间也是占用系统资源的,如果打开该选项,2分钟无上述任何操作会断开链接(仅在链接
# 过程中) 

#PermitRootLogin prohibit-password
PermitRootLogin yes  # 是否允许root用户登录 
#StrictModes yes  # 检查.ssh/文件的所有者,权限等,如果不符合要求就不让登录
#MaxAuthTries 6  # 最多允许连几次,这地方写的是6次,其实连接3次就会退出,
# 通过man sshd_config查看官方解释:指定每个连接允许的最大身份验证尝试次数。
# 一旦失败次数达到一半值,会记录其他故障。 默认值为 6。
#MaxSessions 10  # 同一连接的最大会话数,如一个窗口是一个连接,如果是复制终端后成了两个窗口,
# 仍然是一个链接,只不过是两个会话,也就是最多只能复制10个窗口终端
#PubkeyAuthentication yes  # 基于key验证
#PermitEmptyPasswords no  # 空密码连接
PasswordAuthentication yes  # 基于用户名和密码连接
GatewayPorts no   # 网关功能

# 这两个选项配合起来使用,实现多长时间不操作会断开,第一个是每隔多少秒检查一次,第二个是检查几
# 次,如每隔10s检查一次,一共检查三次,如果三次都没有任何操作,就会断开这个ssh连接。
ClientAliveInterval 10   #单位:秒
ClientAliveCountMax 3    #默认3
UseDNS yes  # 提高速度可以改成no
GSSAPIAuthentication yes  # 提高速度可以改成no
MaxStartups   # 未认证连接最大值,默认是10,就是ssh+IP后该输入密码没有输入,一直不操作

# 以下可以限制可登录用户的办法:
AllowUsers user1 user2 user3
DenyUsers user1 user2 user3
AllowGroups g1 g2
DenyGroups g1 g2

范例:设置ssh 空闲60s 自动注销

Vim /etc/ssh/sshd_config
ClientAliveInterval     60
ClientAliveCountMax   0
Service sshd restart
#注意:新开一个连接才有效

范例:解决ssh登录缓慢的问题

vim /etc/ssh/sshd_config
UseDNS no
GSSAPIAuthentication no
systemctl restart sshd

范例:在 ubuntu 上启用root 远程ssh登录

#修改sshd服务配置文件
vim /etc/ssh/sshd_config 
#PermitRootLogin prohibit-password 注释掉此行
PermitRootLogin yes 修改为下面形式
systemctl restart sshd

ssh服务的最佳实践

  • 建议使用非默认端口
  • 禁止使用protocol version 1
  • 限制可登录用户
  • 设定空闲会话超时时长
  • 利用防火墙设置ssh访问策略
  • 仅监听特定的IP地址
  • 基于口令认证时,使用强密码策略,比如:tr -dc A-Za-z0-9_ < /dev/urandom | head -c 12|
    xargs
  • 使用基于密钥的认证
  • 禁止使用空密码
  • 禁止root用户直接登录
  • 限制ssh的访问频度和并发在线数
  • 经常分析日志

10、ssh其他相关工具

10.1、挂载远程ssh目录-sshfs

由EPEL源提供,目前CentOS8 还没有提供,可以利用ssh协议挂载远程目录。

[root@centos7 ~]#yum install fuse-sshfs
[root@centos7 ~]#sshfs 10.0.0.8:/data /mnt
[root@centos7 ~]#df /mnt
Filesystem     1K-blocks   Used Available Use% Mounted on
10.0.0.8:/data  52403200 398576  52004624   1% /mnt

10.2、自动登录ssh工具-sshpass

由EPEL源提供,ssh登陆不能在命令行中指定密码。sshpass的出现,解决了这一问题。sshpass用于非交互SSH的密码验证,一般用在sh脚本中,无须再次输入密码(本机known_hosts文件中有的主机才能生效)。它允许你用 -p 参数指定明文密码,然后直接登录远程服务器,它支持密码从命令行、文件、环境变量中读取。

格式:

sshpass [option] command parameters

常见选项

-p password #后跟密码它允许你用 -p 参数指定明文密码,然后直接登录远程服务器
-f filename #后跟保存密码的文件名,密码是文件内容的第一行。
-e #将环境变量SSHPASS作为密码

范例:

109节点通过无交互的方式登录106节点

# 109节点安装sshpass
root@109:~$ yum -y install sshpass

# 确定下是否需要存在106的公钥,通过连接发现109并没有106的公钥,正常登录是需要输入yes进行交互
root@109:~$ ssh 192.168.31.106
The authenticity of host '192.168.31.106 (192.168.31.106)' can't be established.
ED25519 key fingerprint is SHA256:dZL40Ckk5dkI2n62NcUEU/+Vj6FENiqW/zjd3kZgopU.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

# 为了保险可以将109的 .ssh 目录删除
root@109:~$ rm -rf .ssh

# 通过sshpass非交互式登录106节点,登录成功,用的是-p参数
root@109:~$ sshpass -p Qwerdf12.. ssh -o StrictHostKeyChecking=no root@192.168.31.106
Warning: Permanently added '192.168.31.106' (ED25519) to the list of known hosts.
Last login: Sun Mar 17 09:07:35 2024 from 192.168.31.103
[root@106-server ~]# hostname -I
192.168.31.106

# 通过sshpass非交互式登录106节点,登录成功,用的是-f参数
root@109:~$ echo "Qwerdf12.." > pass.txt
root@109:~$ sshpass -f pass.txt ssh -o StrictHostKeyChecking=no root@192.168.31.106
Last login: Wed Mar 20 03:58:37 2024 from 192.168.31.109
[root@106-server ~]# hostname -I
192.168.31.106

# 通过sshpass非交互式登录106节点,登录成功,通过将密码写入变量中实现
root@109:~$ sshpass -e ssh root@192.168.31.106 hostname -I
192.168.31.106

**注意:**109节点必须先配置epel源,因为该工具来自于epel源。

10.2.1、手动免密

从109节点免密跳转到106节点

# 109节点获取密钥对
root@109:~$ ssh-keygen
Generating public/private ed25519 key pair.
Enter file in which to save the key (/root/.ssh/id_ed25519): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_ed25519
Your public key has been saved in /root/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:nqhw2NBnedz5wJ2TH+rsxLGzppjZdLzRd8SOcz8hwwc root@109
The key's randomart image is:
+--[ED25519 256]--+
|                 |
|                 |
|                 |
|   .   o o o E . |
|  . . + S = B o o|
|   + o + . = @ B |
|  o o . o . @ O *|
|   o .   * =.= =o|
|    .   + o+*   o|
+----[SHA256]-----+

拷贝公钥到目标主机

# 109操作
root@109:~$ ssh-copy-id 192.168.31.106
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_ed25519.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.31.106's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh '192.168.31.106'"
and check to make sure that only the key(s) you wanted were added.

登录验证

root@109:~$ ssh 192.168.31.106
Last login: Wed Apr  3 10:29:41 2024 from 192.168.31.109

[root@106-server ~]# hostname -I
192.168.31.106

10.2.2、批量免密

范1:批量部署多台主机基于key验证脚本(实现多台免密登录)脚本详解参考:shell/脚本实例/批量部署多台主机基于key验证脚本

部署前验证

# 验证前删除得到各节点公钥
root@109:~$ rm -rf .ssh

# 验证登录,发现在登录前都必须登录验证并输入密码
root@109:~$ ssh 192.168.31.105
The authenticity of host '192.168.31.105 (192.168.31.105)' can't be established.
ED25519 key fingerprint is SHA256:ve+VVuYsG6n7WbsSgO56Ju+XI3S/u3RUjBxPVFLPmps.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? ^C
root@109:~$ ssh 192.168.31.106
The authenticity of host '192.168.31.106 (192.168.31.106)' can't be established.
ED25519 key fingerprint is SHA256:dZL40Ckk5dkI2n62NcUEU/+Vj6FENiqW/zjd3kZgopU.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? ^C
root@109:~$ ssh 192.168.31.107
The authenticity of host '192.168.31.107 (192.168.31.107)' can't be established.
ED25519 key fingerprint is SHA256:FdLvo9PG4PIyq5xRgMoZuY4frP3WaUdliSIeWXjMppM.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? ^C

编写脚本文件

root@109:~/shell$ vim sshpass.sh
#!/bin/bash
# 将多行字符串转换为数组
# set -x
IFS=$'\n' read -d '' -r -a hosts_array <<< "
192.168.31.105
192.168.31.106
192.168.31.107
"

PASS=Qwerdf12..
ssh-keygen -P "" -f /root/.ssh/id_rsa &> /dev/null

# 恢复rpm包检查安装代码,根据实际环境选择适当的包管理器
if ! command -v sshpass &> /dev/null; then
    yum -y install sshpass &> /dev/null || apt-get update && apt-get install -y sshpass
fi

for i in "${hosts_array[@]}"; do
    sshpass -p "$PASS" ssh-copy-id -o StrictHostKeyChecking=no -i /root/.ssh/id_rsa.pub "$i" 2>&1 | tee -a /var/log/sshpass.log &
done

wait

给执行权限并执行脚本

root@109:~/shell$ chmod +x sshpass.sh 
root@109:~/shell$ ./sshpass.sh

再次验证登录情况

# 验证已经可以正常登录各节点主机
root@109:~$ ssh 192.168.31.105
Last login: Wed Mar 20 22:05:35 2024 from 192.168.31.109
[root@192 ~]# exit
登出
Connection to 192.168.31.105 closed.
root@109:~$ ssh 192.168.31.106
Last login: Wed Mar 20 10:04:45 2024 from 192.168.31.109
[root@106-server ~]# exit
logout
Connection to 192.168.31.106 closed.
root@109:~$ ssh 192.168.31.107
[root@192 ~]# hostname -I
192.168.31.107

范例2:批量部署多台主机基于key验证脚本(实现多台免密登录)脚本详解参考:shell/脚本实例/批量部署多台主机基于key验证脚本,第二种写法

创建hosts文件

root@109:~/shell$ vim /root/shell/hosts
192.168.31.105
192.168.31.106
192.168.31.107

编写脚本

root@109:~/shell$ vim sshpass.sh
#!/bin/bash
PASS=Qwerdf12..
# 检查并安装sshpass(取消注释)
rpm -q sshpass &> /dev/null || yum -y install sshpass &> /dev/null

# 从hosts文件读取IP地址列表到数组
IFS=$'\n' read -d '' -r -a hosts_array <<< "$(cat /root/shell/hosts)"

# 生成无密码的SSH密钥对
ssh-keygen -P "" -f /root/.ssh/id_rsa &> /dev/null

# 并发执行ssh-copy-id命令(这里假设你确实需要并发处理,但请根据实际情况调整并发数量)
for i in "${hosts_array[@]}"; do
    sshpass -p "$PASS" ssh-copy-id -o StrictHostKeyChecking=no -i /root/.ssh/id_rsa.pub $i &> /dev/null &
done

# 等待所有后台任务完成
wait

登录验证

root@109:~$ ssh 192.168.31.106
Last login: Wed Mar 20 10:07:39 2024 from 192.168.31.109
[root@106-server ~]# hostname -I
192.168.31.106 192.168.31.183 
[root@106-server ~]# exit
logout
Connection to 192.168.31.106 closed.
root@109:~$ ssh 192.168.31.105
Last failed login: Wed Mar 20 22:38:55 CST 2024 from 192.168.31.105 on ssh:notty
There were 7 failed login attempts since the last successful login.
Last login: Wed Mar 20 22:07:28 2024 from 192.168.31.109
[root@192 ~]# hostname -I
192.168.31.105 
[root@192 ~]# exit
登出
Connection to 192.168.31.105 closed.
root@109:~$ ssh 192.168.31.107
Last login: Wed Mar 20 10:07:47 2024 from 192.168.31.109
[root@192 ~]# hostname -I
192.168.31.107

验证登录成功

10.2.3、批量修修改主机root密码为随机密码通

编写脚本:在109节点编写脚本:vim change_root_password.sh

#! /bin/bash
HOSTS="
192.168.31.106
192.168.31.107
"
PASS=Qwerdf12..
rm -rf /root/shell/pass.txt
for i in $HOSTS; do
{
# 利用openssl生成随机密码,大小写字母+数字
NEW_PASS=`openssl rand -base64 9`

# 这条命令主要是考虑密码强度不够,在生成的随机密码后拼接了“ @ ”特殊符号
# NEW_PASS=`openssl rand -base64 9 | tr -d '\n' | tr -d '\r' | sed 's/$/@/'`
sshpass -p $PASS ssh -o StrictHostKeyChecking=no $i "echo $NEW_PASS |passwd --stdin root"
echo $i:$NEW_PASS >> /root/shell/pass.txt
}&
done

执行脚本

root@109:~/shell$ ./change_root_password.sh 
Changing password for user root.
passwd: all authentication tokens updated successfully.
Changing password for user root.
passwd: all authentication tokens updated successfully.

查看新生成的密码

root@109:~/shell$ cat pass.txt 
192.168.31.107:Q05DriBUeXCZ
192.168.31.106:xAvQN1zgo7ub

进行登录验证

root@109:~/shell$ ssh 192.168.31.106
root@192.168.31.106's password: 
Last failed login: Tue Apr  2 22:51:53 EDT 2024 from 192.168.31.103 on ssh:notty
There were 2 failed login attempts since the last successful login.
Last login: Tue Apr  2 22:48:21 2024 from 192.168.31.103
[root@106-server ~]# hostname -I
192.168.31.107 

10.3、轻量化自动化运维工具 pssh

EPEL源中提供了多个自动化运维工具,该工具来自与pssh

  • pssh:基于python编写,可在多台服务器上执行命令的工具,也可实现文件复制,提供了基于
    ssh和scp的多个并行工具,项目:http://code.google.com/p/parallel-ssh/, CentOS8上目前没提
  • pdsh:Parallel remote shell program,是一个多线程远程shell客户端,可以并行执行多个远程
    主机上的命令。 可使用几种不同的远程shell服务,包括rsh,Kerberos IV和ssh,项目: https://
    pdsh.googlecode.com/
  • mussh:Multihost SSH wrapper,是一个shell脚本,允许使用命令在多个主机上通过ssh执行命
    令。 可使用ssh-agent和RSA/DSA密钥,以减少输入密码,项目:http://www.sourceforge.net/p
    rojects/mussh

注意:pssh默认是基于key验证的,如果想基于传统的密码验证,需要加上-A参数。

pssh命令选项如下:

-H:主机字符串,内容格式”[user@]host[:port]-h file:主机列表文件,内容格式”[user@]host[:port]” 
-A:手动输入密码模式
-i:每个服务器内部处理信息输出
-l:登录使用的用户名
-p:并发的线程数【可选】
-o:输出的文件目录【可选】
-e:错误输出文件【可选】
-t:TIMEOUT 超时时间设置,0无限制【可选】
-O:SSH的选项
-P:打印出服务器返回信息
-v:详细模式
--version:查看版本

安装

# pssh是基于epel源的,所有安装之前必须先配置好epel源
yum install -y pssh

-A 参数 手动输入密码模式

范例:在109上通过pssh命令远程在106上执行命令

# 不用-A参数直接使用会报错,pssh默认是基于key验证的
root@109:~/shell$ pssh -H 192.168.31.106 hostname -I
[1] 15:00:35 [FAILURE] 192.168.31.106 Exited with error code 255

# 加上-A参数,输入106的密码,执行成功
root@109:~/shell$ pssh -H 192.168.31.106 -A hostname -I
Warning: do not enter your password if anyone else has superuser
privileges or access to your account.
Password: 
[1] 15:01:04 [SUCCESS] 192.168.31.106

如果109之前并没有链接过106,也就是说109没有106的公钥,通过-A参数也是无法执行成功的,如下:

# 第一次链接需要输入也是,这个地方直接C掉
root@109:~$ ssh 192.168.31.106
The authenticity of host '192.168.31.106 (192.168.31.106)' can't be established.
ED25519 key fingerprint is SHA256:dZL40Ckk5dkI2n62NcUEU/+Vj6FENiqW/zjd3kZgopU.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? ^C

# 通过pssh进行远程执行命令验证,直接报错了
root@109:~$ pssh -H 192.168.31.106 -A hostname -I
Warning: do not enter your password if anyone else has superuser
privileges or access to your account.
Password: 
[1] 15:17:29 [FAILURE] 192.168.31.106 Exited with error code 255

为了解决这个问题,我们需要修改下ssh的配置文件ssh_config,如下:

vim /etc/ssh/ssh_config
# 将这一行注释取消,修改ask为no
# StrictHostKeyChecking ask

# 修改后如下:
StrictHostKeyChecking no

验证是否可行

# 验证前先删除109的.ssh目录
cd /root
rm -rf .ssh

root@109:~$ pssh -H 192.168.31.107 -A hostname -I
Warning: do not enter your password if anyone else has superuser
privileges or access to your account.
Password: 
[1] 15:33:37 [SUCCESS] 192.168.31.107

通过pssh在多主机执行命令

root@109:~$ pssh -H "192.168.31.107 192.168.31.106" -A hostname -I
Warning: do not enter your password if anyone else has superuser
privileges or access to your account.
Password: 
[1] 15:55:29 [SUCCESS] 192.168.31.106
[2] 15:55:29 [SUCCESS] 192.168.31.107

注意:这个地方只让输入一个密码,也就意味着两台主机的密码必须一致。不过可以通过免密后进行。

-i 参数 每个服务器内部处理信息输出

# 正常不加 -i 参数的情况,不显示详细信息,只显示主机的状态(成功或者失败)
root@109:~$ pssh -H "192.168.31.107 192.168.31.106" -A hostname
Warning: do not enter your password if anyone else has superuser
privileges or access to your account.
Password: 
[1] 17:27:22 [SUCCESS] 192.168.31.106
[2] 17:27:22 [SUCCESS] 192.168.31.107

# 加 -i 参数后会显示详细信息
root@109:~$ pssh -H "192.168.31.107 192.168.31.106" -A -i hostname
Warning: do not enter your password if anyone else has superuser
privileges or access to your account.
Password: 
[1] 17:23:34 [SUCCESS] 192.168.31.107
192.168.31.107
[2] 17:23:34 [SUCCESS] 192.168.31.106
106-server

基于key验证

# 基于key验证首先需要做109到106和107的免密,免密步骤参考10.2.1与10.2.2部分内容,不需要-A了
root@109:~$ pssh -H 192.168.31.106 -i hostname
[1] 22:42:28 [SUCCESS] 192.168.31.106
106-server

-h 参数 file:主机列表文件

通过pssh实现多主机上执行命令,如果主机较多可以用这种方法

# 已做从109到106的免密了
root@109:~/test$ pssh -h /root/test/hosts -i hostname
[1] 22:54:21 [SUCCESS] 192.168.31.106
106-server
[2] 22:54:21 [SUCCESS] 192.168.31.107
192.168.31.107

批量创建用户账号

# 免密已做
root@109:~/test$ pssh -h /root/test/hosts -i useradd app
[1] 23:00:22 [SUCCESS] 192.168.31.106
[2] 23:00:22 [SUCCESS] 192.168.31.107

# 验证是否创建成功
root@109:~/test$ pssh -h /root/test/hosts -i getent passwd app
[1] 23:01:50 [SUCCESS] 192.168.31.106
app:x:1002:1002::/home/app:/bin/bash
[2] 23:01:50 [SUCCESS] 192.168.31.107
app:x:1001:1001::/home/app:/bin/bash

批量创建目录

# 109节点
root@109:~/test$ pssh -h /root/test/hosts -i mkdir /root/20240403
[1] 23:06:53 [SUCCESS] 192.168.31.106
[2] 23:06:53 [SUCCESS] 192.168.31.107

# 如果有一台主机存在该目录,则会报错
root@109:~/test$ pssh -h /root/test/hosts -i mkdir /root/20240403
[1] 23:06:05 [SUCCESS] 192.168.31.106
[2] 23:06:05 [FAILURE] 192.168.31.107 Exited with error code 1
Stderr: mkdir: cannot create directory ‘/root/20240403’: File exists

# 查看创建好的目录是否存在
root@109:~/test$ pssh -h /root/test/hosts -i ls -l /root
[1] 23:07:16 [SUCCESS] 192.168.31.106
total 4
drwxr-xr-x. 2 root root       6 Apr  3 11:07 20240403
-rw-------. 1 root root    1761 Dec 16 10:47 anaconda-ks.cfg
[2] 23:07:16 [SUCCESS] 192.168.31.107
total 4
drwxr-xr-x. 2 root root    6 Apr  3 11:07 20240403
-rw-------. 1 root root 1508 Jan  2 08:57 anaconda-ks.cfg

-o 参数 -e 参数(重定向)

场景:可以将执行结果输出到某个指定的文件中,可以将正确的日志和错误的日志分开存放不同路径

# 在109上执行ll操作,发现有报错,我们查询下日志,-0是正确日志存放位置,-e是错误的日志存放位置
root@109:~/test$ pssh -h /root/test/hosts -o /opt -e /data ls -l /root/shell
[1] 10:24:36 [FAILURE] 192.168.31.107 Exited with error code 2
[2] 10:24:36 [SUCCESS] 192.168.31.106

# 查询错误日志发现是107上并无该目录
root@109:/opt$ cat /data/192.168.31.107
ls: cannot access /root/shell: No such file or directory

# 在107上进行验证,发现并无shell目录
[root@192 ~]# ll
total 4
drwxr-xr-x. 2 root root    6 Apr  3 11:07 20240403
-rw-------. 1 root root 1508 Jan  2 08:57 anaconda-ks.cfg

**注意:**每次操作的日志会覆盖上次的日志,就是每次只会显示最近的一次输出日志。

变量必须用单引号引起来(双引号不行)

# 不加引号显示本机的变量
root@109:~$ pssh -h /root/test/hosts -o /opt -i echo $HOSTNAME
[1] 10:39:20 [SUCCESS] 192.168.31.106
109
[2] 10:39:20 [SUCCESS] 192.168.31.107
109

# 双引号仍显示的是本机的
root@109:~$ pssh -h /root/test/hosts -o /opt -i "echo $HOSTNAME"
[1] 10:39:35 [SUCCESS] 192.168.31.106
109
[2] 10:39:35 [SUCCESS] 192.168.31.107
109

# 单引号显示是目标主机的
root@109:~$ pssh -h /root/test/hosts -o /opt -i 'echo $HOSTNAME'
[1] 10:39:45 [SUCCESS] 192.168.31.106
106-server
[2] 10:39:45 [SUCCESS] 192.168.31.107
192.168.31.107

**注意:*不仅仅是变量有这种情况, 也是需要用单引号引起来的。

10.4、pscp.pssh命令

pscp.pssh功能是将本地文件批量复制到远程主机

包来源pssh,来源于epel源

root@109:~$ rpm -ql pssh
/usr/bin/pnuke
/usr/bin/prsync
/usr/bin/pscp.pssh
/usr/bin/pslurp
/usr/bin/pssh

pscp.pssh选项

-v 显示复制过程
-r 递归复制目录

范例:远程批量执行本地脚本

# 109的脚本内容
root@109:~/shell$ cat test.sh 
#! /bin/bash
hostname

# 给脚本执行权限
root@109:~/shell$ chmod +x test.sh

# 将本地的脚本复制到远程主机的shell目录中
root@109:~/shell$ pscp.pssh -h /root/shell/hosts -v /root/shell/test.sh /root/test/
[1] 11:42:25 [SUCCESS] 192.168.31.106
[2] 11:42:25 [SUCCESS] 192.168.31.107

# 查看拷贝结果
root@109:~/shell$ pssh -h /root/shell/hosts -i ls -l /root/test/
[1] 11:44:13 [SUCCESS] 192.168.31.106
total 4
drwxr-xr-x. 2 root root 32 Mar 26 04:34 01
drwxr-xr-x. 2 root root 19 Mar 26 04:35 02
-rwxr-xr-x. 1 root root 22 Apr  3 23:43 test.sh
[2] 11:44:13 [SUCCESS] 192.168.31.107
total 4
-rwxr-xr-x. 1 root root 22 Apr  3 23:43 test.sh

# 批量执行远程主机的脚本
root@109:~/shell$ pssh -h /root/shell/hosts -i /root/test/test.sh
[1] 14:57:05 [SUCCESS] 192.168.31.106
106-server
[2] 14:57:05 [SUCCESS] 192.168.31.107
192.168.31.107

10.5、pslurp命令

pslurp功能是将远程主机的文件批量复制到本地

pslurp [-vAr] [-h hosts_file] [-H [user@]host[:port]] [-l user] [-p par][-o 
outdir] [-e errdir] [-t timeout] [-O options] [-x args] [-X arg] [-L localdir] 
remote local(本地名)

包来源pssh,来源于epel源

root@109:~$ rpm -ql pssh
/usr/bin/pnuke
/usr/bin/prsync
/usr/bin/pscp.pssh
/usr/bin/pslurp
/usr/bin/pssh

pslurp选项

-L 指定从远程主机下载到本机的存储的目录,local是下载到本地后的名称
-r 递归复制目录

**原理:**从目标主机拉到本地的目录的过程中,如拉取目标主机文件到本地/opt下,首先它会先在/opt目录下创建一个目录,目录名为远程主机的IP地址,然后将文件放入到这个目录下,如果不这样做的话,它从多个主机拉取相同文件就会重复,最后只剩下一个文件,并且你不清楚这个文件是那台主机过来的。

# 测试在有相同文件名的文件是去创建同名目录
root@109:/opt$ ll
total 4
-rw-r--r--. 1 root root  8 Apr  4 15:36 192.168.31.106
drwx--x--x. 4 root root 28 Feb  4 15:37 containerd

root@109:/opt$ mkdir 192.168.31.106
mkdir: cannot create directory ‘192.168.31.106’: File exists

范例:

批量下载目标主机的文件

# 批量下载目标服务器的redhat-releas文件至/opt下,并更名为version,发现上述报错了,参考原理
root@109:~$ pslurp -h /root/shell/hosts -L /opt /etc/redhat-release version
[1] 15:24:54 [FAILURE] 192.168.31.106 Exited with error code 1
[2] 15:24:54 [FAILURE] 192.168.31.107 Exited with error code 1

# 查看opt有相同名的文件,导致的系统无法创建该目录,继而报错
root@109:~$ ll /opt
total 8
-rw-r--r--. 1 root root 11 Apr  4 10:39 192.168.31.106
-rw-r--r--. 1 root root 15 Apr  4 10:39 192.168.31.107
drwx--x--x. 4 root root 28 Feb  4 15:37 containerd

# 将同名的文件删除后再次测试成功
root@109:/opt$ rm -rf 192*
root@109:/opt$ pslurp -h /root/shell/hosts -L /opt /etc/redhat-release version
[1] 15:41:34 [SUCCESS] 192.168.31.106
[2] 15:41:34 [SUCCESS] 192.168.31.107

# 查看是否拉取成功
root@109:/opt$ ll
total 0
drwxr-xr-x. 2 root root 21 Apr  4 15:41 192.168.31.106
drwxr-xr-x. 2 root root 21 Apr  4 15:41 192.168.31.107
drwx--x--x. 4 root root 28 Feb  4 15:37 containerd
root@109:/opt$ tree
.
├── 192.168.31.106
│   └── version
├── 192.168.31.107
│   └── version
└── containerd
    ├── bin
    └── lib

5 directories, 2 files

11、dropbear

由Matt Johnston所开发的Secure Shell软件。Dropbear是一个相对较小的SSH服务器和客户端。它运行在一个基于POSIX的各种平台。 Dropbear是开源软件,在麻省理工学院式的许可证。 Dropbear是特别有用的“嵌入”式的Linux(或其他Unix)系统,如无线路由器,期望在存储器与运算能力有限的情况下取代OpenSSH,尤其是嵌入式系统。

dropbear可以在升级openssh的时候进行安装,这样即使在sshd服务挂掉也不会影响通过ssh user@ip -p dropbear端口这种方式连接

官网:http://matt.ucc.asn.au/dropbear/dropbear.html

范例:编译安装dropbear

# 安装相关包:
root@109:~/package$ yum install gcc zlib-devel

# 下载
root@109:~/package$ wget http://matt.ucc.asn.au/dropbear/releases/dropbear-
2019.78.tar.bz2
# 解压
root@109:~/package$ tar -xf dropbear-2022.83.tar.bz2
root@109:~/package$ cd dropbear-2022.83
root@109:~/package/dropbear-2022.83$ ./configure --prefix=/apps/dropbear --sysconfdir=/etc/dropbear
root@109:~/package/dropbear-2022.83$  make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp"
root@109:~/package/dropbear-2022.83$ make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" install
root@109:/$ tree /apps/dropbear/
/apps/dropbear/
├── bin
│   ├── dbclient
│   ├── dropbearconvert
│   ├── dropbearkey
│   └── scp
├── sbin
│   └── dropbear
└── share
    └── man
        ├── man1
        │   ├── dbclient.1
        │   ├── dropbearconvert.1
        │   └── dropbearkey.1
        └── man8
            └── dropbear.8

6 directories, 9 files

# 配置环境变量
root@109:~/package/dropbear-2022.83$ echo 'PATH=/apps/dropbear/sbin:/apps/dropbear/bin:$PATH' > /etc/profile.d/dropbear.sh

# 在/etc下创建dropbear目录,这个是上边执行configure时定义存放私钥的路径,需要手动创建
root@109:~$  mkdir /etc/dropbear

# 生成私钥文件
root@109:~/package/dropbear-2022.83$ pwd
/root/package/dropbear-2022.83
root@109:~/package/dropbear-2022.83$ /root/package/dropbear-2022.83/dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key -s 2048
Generating 2048 bit rsa key, this may take a while...
Public key portion is:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCIaryyBV+bIvz7EEGHAEjymPxsEwD30uXHhpVRDcCxpr0319ntZoew9XqDnJBpYuYDspfm3G/jomBOHeIPZHYPYJEcAMl+HPc0r9WnU2qQavXhl0WOmItgz84C3LL3yBPIrG0DteEjwQgY8ywZTajmUCaeM3nveiZNKcLBaplEKErKjhT62/TvYkIbBKzWA9VD8T0HXgVLv0pigIZQ8oOLFLpLsMz8BI96XtFXf++QHDvNp41EggibZacR5/jqkdWVCItkLoFBI6PG/OzkvrBFhsudjUtCWR7iQu56QC7qxVMPD02O1+Wvkd2PaiyFmOqEDeEdyip5rlzf0Vchn06p root@109
Fingerprint: SHA256:q32uJsSd/3OQnvryETfuh9X2jhCPSAAG0CI6JyLo9JQ

# 查看私钥已生成
root@109:~/package/dropbear-2022.83$ tree /etc/dropbear
/etc/dropbear
└── dropbear_rsa_host_key

# 启动服务,因为dropbear默认也是启动22端口,和系统openssh的冲突了,手动指定端口,如2222,先查看2222端口是在使用
root@109:~$ ss -ntl
State      Recv-Q Send-Q         Local Address:Port                        Peer Address:Port              
LISTEN     0      128                        *:22                                     *:*                  
LISTEN     0      128                       :::22                                    :::*                  
LISTEN     0      128                       :::23                                    :::*

# 前台启动dropbear
dropbear -p :2222 -FE
# 后台运行
[root@centos8 ~]#dropbear -p :2222

# 后台启动(一般生产环境会采用后台启动的方式),2222已经处于监听状态
root@109:/apps/dropbear/sbin$ ss -ntl
State      Recv-Q Send-Q         Local Address:Port                        Peer Address:Port              
LISTEN     0      128                        *:2222                                   *:*                  
LISTEN     0      128                        *:22                                     *:*                  
LISTEN     0      128                       :::2222                                  :::*                  
LISTEN     0      128                       :::22                                    :::*                  
LISTEN     0      128                       :::23                                    :::*

# 测试,从105节点进行连接测试,已经成功了
[root@192 ~]# ssh 192.168.31.109 -p 2222
The authenticity of host '[192.168.31.109]:2222 ([192.168.31.109]:2222)' can't be established.
RSA key fingerprint is SHA256:q32uJsSd/3OQnvryETfuh9X2jhCPSAAG0CI6JyLo9JQ.
RSA key fingerprint is MD5:89:19:5a:8d:e6:bf:fd:14:58:a2:f3:97:83:7f:99:0f.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[192.168.31.109]:2222' (RSA) to the list of known hosts.
root@192.168.31.109's password: 
root@109:~$ hostname -I
192.168.31.109

注意: 如果要升级openssh时用dropbear,在一台上编译好后需要直接将/apps/dropbear目录打包,将下载好所在编译目录(/root/package/dropbear)打包,将这个两个包上传到要升级的服务器对应的目录解压。

  • 在创建/etc/dropbear目录,如果目标主机没有/root/package目录也需要提前创建。
  • 在/root/package/dropbear-2022.83执行生成密钥对的命令:/root/package/dropbear-2022.83/dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key -s 2048,注意对应版本和路径
  • 密钥生成后可以启动服务了,启动前先查看要启动的端口是否被占用,如ss -ntl查看2222端口,启动服务:cd /apps/dropbear/sbin,执行./dropbear -p :2222
  • 通过其他主机链接测试:ssh root@目标主机IP -p 2222,如果提示没有路由之类的报错,先查看目标地址的防火墙是否启动着,如果启动需要关闭防火墙,查看状态:systemctl status firewalld,关闭防火墙:systemctl stop firewalld,再次通过ssh进行链接测试。

网站公告

今日签到

点亮在社区的每一天
去签到