# SSH 免密登录

业务场景:

现在有两台服务器,服务器 A 和 服务器 B,要配置服务器 A 免密连接至服务器 B。

服务器 A 的 IP 地址为:192.168.202.205(用于免密连接至机器 B)

服务器 B 的 IP 地址为:192.168.202.206(被机器 A 免密连接)

# 检查是否已经生成公钥和私钥

首先,先检查服务器 A (主动连接到其他服务器的机器)是否已生成公钥和私钥。

ls ~/.ssh

如果出现以下提示,则说明当前用户还没有生成公钥和私钥。

[root@localhost ~]# ls ~/.ssh
ls: 无法访问/root/.ssh: 没有那个文件或目录

# 生成公钥和私钥

如果还没有生成公钥和私钥,则在服务器 A 上生成公钥和私钥。

生成的过程中要求你输入一些参数,一路回车(Enter)使用默认配置即可。

ssh-keygen

说明:如果之前已经生成过公钥和私钥了,那么在执行以上命令时会提示你之前已经生成过了,是否要覆盖原来的私钥。

注意:如果之前已经生成过了,千万不要重新生成,否则会导致之前配置过的免密登录机器全部失效!(除非私钥泄露了,或者一些安全原因需要重新生成,只有这种情况下才能去执行这个覆盖命令)

[root@localhost ~]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
/root/.ssh/id_rsa already exists.
Overwrite (y/n)?

参考执行日志:

[root@localhost ~]# 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:RdUjHP4i5lUKKEJE/JtSBroS3ddUy560UMsEhnRdmeg root@localhost.localdomain
The key's randomart image is:
+---[RSA 2048]----+
|   ++...++==+=   |
|   .o .o.Bo+= o  |
| . o.o.oo.O .... |
|. o ..=..=E+ +   |
| . . + oS * + .  |
|. . . o  o o .   |
| .   .    .      |
|                 |
|                 |
+----[SHA256]-----+

# 查看生成出来的公钥和私钥

默认情况下,ssh 的公钥和私钥会生成到 ~/.ssh 目录下,在服务器 A 执行以下命令:

ls ~/.ssh

这个时候,就可以看到生成出来两个文件了。

[root@localhost ~]# ls ~/.ssh
id_rsa  id_rsa.pub

文件说明:

id_rsa 是私钥,

id_rsa.pub 是公钥。

查看 id_rsa 文件,可以看到私钥文件的头和尾会有 RSA PRIVATE KEY 的标识符。

[root@localhost ~]# cat ~/.ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAxTF2b+i+i1rya2AUtEdxLfCX6WiUj4Qr2KxQzJtQbiPUd1ec
JItacCc6h5IJjFDkelHuAvSfb5aMDZAOCmTtbIqeGGmkVA5zC5HyZBMeaswBjpj/
miAF/ndV9ebuq3jbuQ61JkfxYOAseX6Ovbu9HarQfOUef7ot5Irg2wDxfQobeYHz
7k33D3PcNVqEfPbpFWwYdKGxrJtqh9A8WAeX1EIrgPKndhqQ+ikHnuQcNKjvNGJ+
jgIxs99Q2cdXI93b0NOz3SvwayFZt2VxV8j0qwThfvqGrld26eg6XcDBCTCnwBtK
DXjuh/Bnr0dI5Q/4DTL1Z2lpEE1Ny/SeTmkAVQIDAQABAoIBADEgRHhWzHmdO72i
XyYWkky2nrHoevJSJDZDn5GJs/zscjcVHXJBQVOlgkBaEoThdjo/BQO5e6rqH5QV
aloOkNO0qPQ+BVFnlCOyxWdHGBHVJyImXa9BAR1HD6RGVvljD6JH1rtluu2+i3Xt
IJSGG/QzJOOolPOPJ3XDX4dP8dmLZXbD5KUMmlhiIJanafldJ2rD2tZLdxbTr6me
qQsTkQEnIYdBvo4yp99dWaWj03B/kSWPS6tqq1zlMlguahIycgywaiFIfk1mBw2L
r7FymXl6F2ipXUcdl6v5cNNuQPG/Xws7LhEW3Jpd+Tp3/ZvHvnImlyBph2hQJt4F
Ygw/s2ECgYEA+nFKIT2tOr0skfa3bCWx742Ozhhcy88zmUKYN4bZyalLKJDXqajp
057IeC+AfdxTIJm5E95XNdgTn146Yeb+YJTwx5SElgLZCDQ75fCCrgcm9ldujbm0
xhXHYZJ5Y5gdjOS9j4jx83AHWpBYbYuGqXHKr9LoBUYpdASjEPe43d0CgYEAyZGs
0T+TDo+T/qw0q3s0d7SQAyA6NtBVEp4x+MeCwYDO7IKUWqQbTfwa0UYQ7GCJFbF3
9biln/eyTelbuGA45eJVTuGtJTlZMr12gv9AdcWJpI2n0gAFWYwgRRQ8BdcMqfRn
IbNY91enhF9fXz/tFpHrrYENcT7BeXDThNCRsNkCgYA7sqGfBtqyM8HaEVtrthiS
J8YwrnIASyXblJpAMi7b+TTnOI+P66nBPgo/S+NvHQPbs4kAiXF0bktPI+D60Vs1
nos+p9JrB8bAQ+M7Tnd4EFBjTDgYJHpI9YwPYCD7cpkoqqXc/yHdi4jVN688fZPd
9DgCbV3NVAoxk6FjPAmfKQKBgHk+zAINyKpAiRfug7wGXxgGH34R25JvHE0XpR1s
/OTiUxWGsjAXeGkfVQ4+pB1bL/pBhtPiXpXri3A8BzTPhEobK49IRjsW1OWle2zu
ltqAmPvHTYQPCSjFFgAXXMdyhKaSYZqu47vcGOKR768+p6Ek4uu5rdlJk102FbVV
M915AoGAMiG3xhSS3Ne3cVBWvNogCi5EU8y8O+ojjd+Tn/UzuidCzwkBG9wSIWDB
IUNngjC/SZtKuQl2RPBu8A/nnwOmhb38key0xj7y9B4mKVO+zsL2CqaiETHnYARu
gwyRKfv5tasnQpJh7+THOLCKI7NjHt8E6/t5hqrOOV7ijAAd+Gs=
-----END RSA PRIVATE KEY-----

查看 id_rsa.pub 文件,可以看到以 ssh-rsa 开头,其中 rsa 是默认的加解密算法。

[root@localhost ~]# cat ~/.ssh/id_rsa.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFMXZv6L6LWvJrYBS0R3Et8JfpaJSPhCvYrFDMm1BuI9R3V5wki1pwJzqHkgmMUOR6Ue4C9J9vlowNkA4KZO1sip4YaaRUDnMLkfJkEx5qzAGOmP+aIAX+d1X15u6reNu5DrUmR/Fg4Cx5fo69u70dqtB85R5/ui3kiuDbAPF9Cht5gfPuTfcPc9w1WoR89ukVbBh0obGsm2qH0DxYB5fUQiuA8qd2GpD6KQee5Bw0qO80Yn6OAjGz31DZx1cj3dvQ07PdK/BrIVm3ZXFXyPSrBOF++oauV3bp6DpdwMEJMKfAG0oNeO6H8GevR0jlD/gNMvVnaWkQTU3L9J5OaQBV root@localhost.localdomain

# 方式一:使用 ssh-copy-id 复制公钥到被控机器

注意:使用 ssh-copy-id 的方式需要知道被控机器的用户名和密码!

现在要实现服务器 A 免密连接至服务器 B,所以需要把服务器 A (192.168.202.205)的公钥复制给服务器 B(192.168.202.206),在将来如果使用私钥加密一段东西,然后服务器 B 使用公钥可以解开,那就可以完成身份验证进行登录了。

# 复制公钥给被控机器 B

在服务器 A 上执行以下命令,把服务器 A 的公钥复制给被控服务器 B:

ssh-copy-id root@192.168.202.206

第一次连接至新的服务器,会询问是否要继续连接,输入 yes 即可:

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.202.206's password:

完整执行日志如下:

[root@localhost ~]# ssh-copy-id root@192.168.202.206
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '192.168.202.206 (192.168.202.206)' can't be established.
ECDSA key fingerprint is SHA256:7blhRI+3Hv46USkbiAmg12Q7+MD2grXVBVfU9TWcK7U.
ECDSA key fingerprint is MD5:2e:92:53:d2:0e:8f:ef:db:87:a7:5f:d6:5e:28:df:b2.
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.202.206's password: 

Number of key(s) added: 1

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

# 在被控机器 B 上检查是否复制成功

在被控机器 B 上执行 ls ~/.ssh,可以看到多了一个 authorized_keys 文件,如果没有看到这个文件,说明没有复制成功。

[root@localhost ~]# ls ~/.ssh
authorized_keys

查看文件里的内容:

cat ~/.ssh/authorized_keys

可以看到,里面的内容就是服务器 A 的公钥。

[root@localhost ~]# cat ~/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFMXZv6L6LWvJrYBS0R3Et8JfpaJSPhCvYrFDMm1BuI9R3V5wki1pwJzqHkgmMUOR6Ue4C9J9vlowNkA4KZO1sip4YaaRUDnMLkfJkEx5qzAGOmP+aIAX+d1X15u6reNu5DrUmR/Fg4Cx5fo69u70dqtB85R5/ui3kiuDbAPF9Cht5gfPuTfcPc9w1WoR89ukVbBh0obGsm2qH0DxYB5fUQiuA8qd2GpD6KQee5Bw0qO80Yn6OAjGz31DZx1cj3dvQ07PdK/BrIVm3ZXFXyPSrBOF++oauV3bp6DpdwMEJMKfAG0oNeO6H8GevR0jlD/gNMvVnaWkQTU3L9J5OaQBV root@localhost.localdomain

既然 ssh-copy-id 命令的作用就是把服务器 A 的公钥复制到被控机器 B 的 authorized_keys 文件下,那我直接在被控机器 B 上手动把公钥复制进去不就好了吗?对的,当我们不知道被控机器的密码的时候,但是又需要实现免密登录,就可以用这种方式。

# 测试是否可以免密连接至被控机器 B

接下来,在服务器 A 上测试是否可以免密连接至服务器 B:

ssh root@192.168.202.206

看到以下提示,说明免密登录配置成功了。

[root@localhost ~]# ssh root@192.168.202.206
Last login: Thu May 12 15:57:22 2022 from 192.168.202.205

# 方式二:在被控机器 B 上手动创建 authorized_keys 文件

通过 ssh-copy-id 命令本质上还是在被控机器上的 authorized_keys 文件写入服务器 A 的公钥,所以当我们不知道被控机器 B 的服务器用户名密码的时候,可以使用这种方式在被控机器 B 上添加服务器 A 的公钥。

# 查看服务器 A 的公钥

在主动连接至其他服务器 A 的公钥上执行以下命令,查看公钥:

cat ~/.ssh/id_rsa.pub

执行日志如下:

[root@localhost ~]# cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCfavmVZPKDzhwQIgeXdsQOmzVwcHjOaVCaiECef8bLTVLjeTZK6V5gjxHxrs9YFwxq/XJFy085VVYIpeCwaCfDj9rH94AKTVnE612hO9xLRnnNp+HEKi+LQG+zQ3I1tTeSAUZHhMiWIsOe2g3ic9q2Ccj++n3/bLbdgWVBfyrnd09E1vfXa1QlLtgUqCBcEVCwHxvufw0/5Zn42OzVPAJ9WgOqREF+Yz7q1TErbDNjyqnaT9b9519/4x9uUrcG26iP1qV0bg97kW4HmQmH1G7cEr7pWGP1eI55ACV2p47AAMYE9ug250qLGxLBuC99jQcnHgbMzsPJslq5D5GGcTlf root@localhost.localdomain

其中,公钥为:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCfavmVZPKDzhwQIgeXdsQOmzVwcHjOaVCaiECef8bLTVLjeTZK6V5gjxHxrs9YFwxq/XJFy085VVYIpeCwaCfDj9rH94AKTVnE612hO9xLRnnNp+HEKi+LQG+zQ3I1tTeSAUZHhMiWIsOe2g3ic9q2Ccj++n3/bLbdgWVBfyrnd09E1vfXa1QlLtgUqCBcEVCwHxvufw0/5Zn42OzVPAJ9WgOqREF+Yz7q1TErbDNjyqnaT9b9519/4x9uUrcG26iP1qV0bg97kW4HmQmH1G7cEr7pWGP1eI55ACV2p47AAMYE9ug250qLGxLBuC99jQcnHgbMzsPJslq5D5GGcTlf root@localhost.localdomain

# 在被控服务器 B 上写入服务器 A 的公钥

mkdir -p ~/.ssh && echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCfavmVZPKDzhwQIgeXdsQOmzVwcHjOaVCaiECef8bLTVLjeTZK6V5gjxHxrs9YFwxq/XJFy085VVYIpeCwaCfDj9rH94AKTVnE612hO9xLRnnNp+HEKi+LQG+zQ3I1tTeSAUZHhMiWIsOe2g3ic9q2Ccj++n3/bLbdgWVBfyrnd09E1vfXa1QlLtgUqCBcEVCwHxvufw0/5Zn42OzVPAJ9WgOqREF+Yz7q1TErbDNjyqnaT9b9519/4x9uUrcG26iP1qV0bg97kW4HmQmH1G7cEr7pWGP1eI55ACV2p47AAMYE9ug250qLGxLBuC99jQcnHgbMzsPJslq5D5GGcTlf root@localhost.localdomain" >> ~/.ssh/authorized_keys

由于 vi 命令不能创建目录,所以需要先把 .ssh 目录创建出来。

而且,echo 命令要使用追加符号 >>,而不要使用覆盖 > 符号,因为被控服务器可能被多台服务器所连接,直接覆盖写入会导致其他的服务器的免密登录失效。

# 验证是否可以免密连接至被控服务器 B

在被控服务器 B 上添加好服务器 A 的公钥以后,就可以实现免密登录了。

在服务器 A 上执行以下命令,看一下免密登录是否配置成功。

ssh root@192.168.202.206

看到以下提示,说明配置成功了。

[root@localhost ~]# ssh root@192.168.202.206
Last login: Thu May 12 16:29:51 2022 from 192.168.202.205

# 无法实现免密登录的排查思路

首先,检查被控服务器 B 上是否有服务器 A 的公钥。

在远程至其他服务器上的服务器 A 上执行以下命令,查看公钥:

cat ~/.ssh/id_rsa.pub

执行命令如下,可以看到公钥为:

[root@localhost ~]# cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCfavmVZPKDzhwQIgeXdsQOmzVwcHjOaVCaiECef8bLTVLjeTZK6V5gjxHxrs9YFwxq/XJFy085VVYIpeCwaCfDj9rH94AKTVnE612hO9xLRnnNp+HEKi+LQG+zQ3I1tTeSAUZHhMiWIsOe2g3ic9q2Ccj++n3/bLbdgWVBfyrnd09E1vfXa1QlLtgUqCBcEVCwHxvufw0/5Zn42OzVPAJ9WgOqREF+Yz7q1TErbDNjyqnaT9b9519/4x9uUrcG26iP1qV0bg97kW4HmQmH1G7cEr7pWGP1eI55ACV2p47AAMYE9ug250qLGxLBuC99jQcnHgbMzsPJslq5D5GGcTlf root@localhost.localdomain

然后,在被控服务器 B 上查看已授权的公钥:

cat ~/.ssh/authorized_keys

可以看到,被控服务器 B 中有服务器 A 的公钥,这个时候是正常的。

[root@localhost ~]# cat ~/.ssh/authorized_keys 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCfavmVZPKDzhwQIgeXdsQOmzVwcHjOaVCaiECef8bLTVLjeTZK6V5gjxHxrs9YFwxq/XJFy085VVYIpeCwaCfDj9rH94AKTVnE612hO9xLRnnNp+HEKi+LQG+zQ3I1tTeSAUZHhMiWIsOe2g3ic9q2Ccj++n3/bLbdgWVBfyrnd09E1vfXa1QlLtgUqCBcEVCwHxvufw0/5Zn42OzVPAJ9WgOqREF+Yz7q1TErbDNjyqnaT9b9519/4x9uUrcG26iP1qV0bg97kW4HmQmH1G7cEr7pWGP1eI55ACV2p47AAMYE9ug250qLGxLBuC99jQcnHgbMzsPJslq5D5GGcTlf root@localhost.localdomain

如果,检查完以上后还是没办法连接,可以检查下文件权限。

查看服务器 A 的文件权限:

ls -l ~/.ssh/

执行日志如下:

[root@localhost ~]# ls -l ~/.ssh/
总用量 12
-rw-------. 1 root root 1675 512 16:18 id_rsa
-rw-r--r--. 1 root root  408 512 16:18 id_rsa.pub
-rw-r--r--. 1 root root  177 512 16:28 known_hosts

可以看到,私钥文件 id_rsa 只有拥有者才有读和写的权限,其他群组和用户都没有任何读写执行权限。而公钥文件 id_rsa.pub 和记录已确认连接其他服务器的 known_hosts 所有人都可以读,但是只有拥有者才可以写,并且所有人都不能执行。

如果文件权限不对,需要执行以下命令修改文件权限:

chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub
chmod 644 ~/.ssh/known_hosts

说明:r=4,w=2,x=1

查看被控服务器 B 的文件权限:

ls -l ~/.ssh

执行日志如下:

[root@localhost ~]# ls -l ~/.ssh
总用量 4
-rw-r--r--. 1 root root 408 512 16:29 authorized_keys

可以看到,authorized_keys 文件的权限只有拥有者才有写入权限,其他用户、群组只有读的权限,并且所有用户和群组都没有执行权限。

如果文件权限不对,执行以下命令修改文件权限:

chmod 644 ~/.ssh/authorized_keys

被控服务器的文件权限有问题是最致命的,因为你在连接的时候看不到任何的错误提示!而且一般都是这个问题导致的免密连接不成功。

# 具体错误的解决方案

# WARNING: UNPROTECTED PRIVATE KEY FILE!

这是因为,私钥文件设置了 777,可以被所有人访问到,太不安全了,所以被安全策略阻止了,不能远程访问。

[root@localhost ~]# ssh root@192.168.202.206
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0777 for '/root/.ssh/id_rsa' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "/root/.ssh/id_rsa": bad permissions
root@192.168.202.206's password: 
Permission denied, please try again.
root@192.168.202.206's password: 
Permission denied, please try again.
root@192.168.202.206's password: 
Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).

解决方案:修改文件权限

chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub
chmod 644 ~/.ssh/known_hosts

# ssh 免密登录的缺点

虽然,ssh 免密登录非常方便,但是也不是绝对的安全的。

当我们修改了用户的密码的时候,ssh 公钥依然有效,所以一旦配置好了 ssh 之后,修改用户的密码对 ssh 是没有影响的,而一旦 ssh 密钥泄露,就可以被伪造进行登录了!

在网络安全中,这也是种后门,可以通过这个方式来检查服务器是否被留后门。

参考资料:

SSH 三步解决免密登录 (opens new window)