利用 SSH 的用户配置文件 Config 管理 SSH 会话

通常我们如果需要连接远程服务器,一般都会是下面的命令:

1
ssh user@www.example.com -p port

但是如果我们有许多台服务器,而且需要记住很多的密码,非常的繁琐。

幸好ssh提供了一个非常优雅的方式来解决这个问题。那就是通过配置ssh的配置文件config来管理ssh会话。

使用SSH配置文件

ssh 配置文件一般分为两种:

  1. 用户的配置文件,一般在${HOME}/.ssh/config, 如果该文件不存在,可以手动创建。
  2. 系统全部用户的配置文件,一般在/etc/ssh/ssh_config

配置文件可分为多个配置区段,每个配置区段使用”Host”来区分。我们可以在命令行中输入不同的Host来加载不同的配置段。

配置项

  1. Host 别名
  2. HostName 主机名
  3. Port 端口
  4. User 用户名
  5. IdentityFile 密钥文件的路径
  6. IdentitiesOnly 只接受SSH key 登录
  7. PreferredAuthentications 强制使用Public Key验证

示例:

1
2
3
Host example #ssh别名
HostName www.example.com # 可以是域名 也可以是 ip地址
User root # 用户名

然后,就可以直接用一下命令登录:

1
ssh example

但是,对于我这种在自己电脑上,不想输入密码,直接输入别名就可以登录可不可以呢,也是可以的。这里就需要介绍一下ssh远程登录的流程:


SSH 远程登录的流程

当本机发起登录请求时,SSH 会依次执行以下几个主要步骤:

  1. 通过远程主机公钥 hash,确认远程主机身份;
  2. 若通过,远程主机验证登录身份,例如:提示输入远程主机目标用户的口令;
  3. 本地主机将用户键入的口令,使用远程主机的公钥加密,并发送给远程主机;
  4. 远程主机使用上述公钥对应的私钥,对得到的密文进行解密;
  5. 远程主机验证解密后的口令;
  6. 若通过,则建立 SSH 连接,成功登录。

下面我们来验证这一过程,我们通过ssh来登录一下本机:

1
2
3
4
5
[root@localhost ~]# ssh root@localhost
The authenticity of host 'localhost (::1)' can't be established.
ECDSA key fingerprint is SHA256:VH4PWpUX+zS1vZQ8HjEWHTU+JboaIl91jkzZ4lFnCnU.
ECDSA key fingerprint is MD5:2c:eb:01:27:70:e4:d1:06:1e:06:61:a6:d4:76:02:39.
Are you sure you want to continue connecting (yes/no)?

ssh提会示我们验证远程主机的身份,翻译一下大概就是:

1
#无法验证主机 ‘localhost (127.0.0.1)’ 的真实性。ECDSA  MD5密钥指纹为 2c:eb:01:27:70:e4:d1:06:1e:06:61:a6:d4:76:02:39.。ECDSA  SHA256密钥指纹为VH4PWpUX+zS1vZQ8HjEWHTU+JboaIl91jkzZ4lFnCnU 你是否要继续连接?(yes/no)

我们直接输入yes,回车:会出现下面警告

1
Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.

为了下次自动地验证远程主机的身份,本地主机会将远程主机的公钥指纹保存下来。新出现的提示,翻译如下。

1
#警告:已将 ‘localhost’ (ECDSA) 永久地加入已知主机列表之中。

在输入远程主机目标用户的口令之后(无终端回显),本地主机会将输入的口令以远程主机提供的密钥加密并发送给远程主机。待远程主机解密并验证通过后,即提示成功登录。

那么,具体来说,本地主机将这一信息保存在哪里了呢?答案是当前用户的 ${HOME}/.ssh/known_hosts 文件当中。我们可以执行 exit 命令,退出远程主机;而后使用 cat 命令可以查看${HOME}/.ssh/known_hosts的中远程主机信息。如下图:

使用公钥验证身份

现在我们考虑下一个问题:除去输入远程主机用户口令的方式,是否还有其他方式能够验证登录者的身份?

对于身份认证来说,通常有三种手段:

  1. 你知道的(例如账户口令);
  2. 你独有的(例如网银的 U 盾);
  3. 你身上的(例如指纹)。

在 SSH 协议中,信道的安全是通过非对称加密保证的。事实上,非对称加密需要持有私钥。因此,私钥这件事情本身,也可以认为是一种「你独有的」东西。考虑到,在 SSH 登录成功之前,在不完整的信道中,从本地主机向远程主机通信是安全的(因为有远程主机的公钥可用于加密),而远程主机可以用持有的私钥解密本地主机发来的信息。(例如口令登录验证的过程)。类似的过程也可以反过来用:

  1. 本地主机生成一对非对称密钥;
  2. 本地主机将公钥交付远程主机;
  3. 远程主机在收到登录请求时,使用上述公钥加密一串无害的随机信息;
  4. 本地主机将接收到的密文,以本地持有的私钥解密,而后通过远程主机的公钥再进行加密;
  5. 远程主机使用相应私钥解密,并与上述随机信息进行比对;
  6. 若一致,则认可登录者的身份,许可登录。

在这个过程中,远程主机对比一来一回前后随机信息的一致性,验证了本地主机确实持有一个安全介质——本地主机生成的私钥。因此,这就不需要输入远程主机的用户口令了。

为此,我们首先需要生成一对密钥。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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.test
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.test.
Your public key has been saved in /root/.ssh/id_rsa.test.pub.
The key fingerprint is:
SHA256:HBwt+Cid0XQwZtZf0f370Xz657UzYJJAPYn0/Ayp9SY root@localhost.localdomain
The key's randomart image is:
+---[RSA 2048]----+
| +X=+ . .o.|
| o=o*=+. . o|
| . =+. B.. .|
| . +..oo * .|
| . S..E.= .o|
| ooo o+|
| o ..=|
| .o=|
| +*|
+----[SHA256]-----+

ssh-keygen OpenSSH 的一部分,它用于生成供SSH使用的密钥。默认情况下,ssh-keygen 生成的是 RSA 密钥(本机上是 2048 位 RSA),并将私钥保存在 ${HOME}/.ssh/id_rsa 当中。为了避免与已有的密钥冲突,这里我们另存为 id_rsa.test。随后,ssh-keygen 要求我们为生成的私钥设置口令(passphrase)。这一口令是对私钥进行保护的口令,可以留空。这样一来,我们就生成了一对 RSA 密钥。其中,私钥保存在 /root/.ssh/id_rsa.test 而公钥保存在 /root/.ssh/id_rsa.test.pub

接下来,我们需要将生成的密钥交付给远程主机。为此,我们需要使用 ssh-copy-id 这一命令。

1
2
3
4
5
6
7
8
9
10
ssh-copy-id -i /root/.ssh/id_rsa.test root@www.example.com

/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@www.example.com password:

Number of key(s) added: 1

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

ssh-copy-id 会将 ~/.ssh/id_rsa.test 对应的公钥,交付给 root@www.example.com。在这个过程中,我们需要输入用户 root 在远程主机 www.example.com上的口令。注意,此处我们使用了 -i 参数,指定了需要交付的密钥。若是省略 -i 参数,则 ssh-copy-id 会将默认的密钥 ~/.ssh/id_rsa 对应的公钥交付给远程主机。

之后,我们就可以「免密登录」了。同样,我们需要使用 -i 参数指定所需使用的私钥。

1
ssh -i ~/.ssh/id_rsa.test root@www.example.com

类似上面提到过的 ~/.ssh/known_hosts,保存这类公钥也有一个特定的文件:远程主机目标用户的 ${HOME}/.ssh/authorized_keys。登录远程主机后,我们可以查看刚刚添加的公钥和我们生成的id_rsa.test.pub是一样的。

若是你的机器不支持 ssh-copy-id,也可以直接将公钥信息写入远程主机目标用户的 ${HOME}/.ssh/authorized_keys 当中。


回到我们之前的问题,如果我们想免密登录的话,那么我们就需要在配置文件下新增一段,新增之后的配置文件为:

1
2
3
4
Host example #登录别名
HostName www.example.com #登录的主机 或者ip
User root # 登录用户
IdentityFile ~/.ssh/id_rsa #登录用到的公钥

现在直接登录就可以使用ssh example直接登录,不再输入密码。

参考文章


利用 SSH 的用户配置文件 Config 管理 SSH 会话
https://randzz.cn/ab81cb4da963/利用-ssh-的用户配置文件-config-管理-ssh-会话/
作者
Ezreal Rao
发布于
2019年5月27日
许可协议