Skip to content

SSH 密钥对的使用

SSH 密钥对是用于安全地进行 SSH(Secure Shell)协议认证的一种方式。SSH 是一种网络协议,用于在网络上安全地进行远程登录和执行命令。密钥对由两个部分组成:私钥公钥

  • 私钥(Private Key): 私钥是保存在用户本地计算机上的机密文件,用于对远程服务器进行身份验证。用户必须谨慎保管私钥,因为它是授权用户访问远程服务器的关键。

  • 公钥(Public Key): 公钥是与私钥配对的非机密文件,可以在远程服务器上存储。与私钥相关联的公钥允许远程服务器验证用户身份。当用户通过 SSH 连接到远程服务器时,其本地计算机上的私钥与服务器上存储的公钥进行匹配,从而完成身份验证。

SSH 密钥对的工作原理基于非对称加密算法。当用户生成密钥对时,系统使用数学原理生成一对相关联的密钥。数据使用公钥加密后,只有拥有相应私钥的用户才能解密它。这种方法增强了安全性,因为即使公钥被泄露,攻击者也无法逆向计算出私钥。

使用 SSH 密钥对有助于提高安全性,避免了传统密码登录的一些弱点,如中间人攻击和密码猜测。

生成密钥对

生成 SSH 密钥对通常使用 ssh-keygen 命令。

bash
# 语法
ssh-keygen [选项]
# 语法
ssh-keygen [选项]

其中,[选项] 可以是一系列的命令行选项,用于指定 ssh-keygen 的行为。以下是一些常见的选项:

  • -t 指定密钥的类型。常见的类型包括 "rsa"(默认),"dsa","ecdsa" 和 "ed25519"。例如,-t rsa 将生成 RSA 密钥。

  • -b 指定密钥的位数。例如,-b 2048 将生成一个 2048 位的密钥。默认值取决于密钥类型。

  • -C 添加注释。注释将作为标识符嵌入到生成的公钥中,可以帮助你识别密钥的用途。

  • -f 指定密钥文件的路径。可以使用此选项来为生成的密钥文件指定自定义的文件名和路径。默认生成路径为 ~/.ssh/ 下。

  • -N 设置密码。如果指定了密码,私钥文件将被加密,并且在使用私钥时需要提供密码。

  • -q 静默模式。在此模式下,ssh-keygen 不会显示生成密钥的进度信息。

  • -A 生成所有支持的密钥类型的密钥。

  • -f 指定密钥文件的路径。

示例:

bash
# 生成默认的 RSA 密钥(2048位)
ssh-keygen

# 生成指定类型的密钥(例如,Ed25519)
ssh-keygen -t ed25519

# 生成指定位数的 RSA 密钥
ssh-keygen -b 4096

# 生成带注释的密钥
ssh-keygen -C "your_email@example.com"

# 生成密钥文件并指定路径
ssh-keygen -f /path/to/custom_key
# 生成默认的 RSA 密钥(2048位)
ssh-keygen

# 生成指定类型的密钥(例如,Ed25519)
ssh-keygen -t ed25519

# 生成指定位数的 RSA 密钥
ssh-keygen -b 4096

# 生成带注释的密钥
ssh-keygen -C "your_email@example.com"

# 生成密钥文件并指定路径
ssh-keygen -f /path/to/custom_key

注意

实际使用时可能会有其他选项和用法,具体取决于你的需求和系统环境。可以使用 man ssh-keygen 命令来查看 ssh-keygen 的手册页以获取更详细的信息。

日常使用最多的场景是生成 Git 托管平台(Github、Gitlab、Gitee 等)所需的 SSH 密钥对。通过我们会选择使用默认的 RAS 加密方式以及默认的位数(2048 位),额外指定下 -C 为自己的邮箱。

bash
ssh-keygen -C "your_email@example.com"
ssh-keygen -C "your_email@example.com"

回车几次后,~/.ssh/ 下会多出两个文件:id_rsaid_rsa.pub,分别是私钥和公钥。公钥是用于放在 Git 托管平台的。

在 Git 托管平台添加了公钥后,可以通过以下命令测试 SSH 连接:

bash
# 语法
ssh -T git@[域名]

# 以 Github 为例
ssh -T git@github.com
# 语法
ssh -T git@[域名]

# 以 Github 为例
ssh -T git@github.com

场景拆分

根据不同的场景使用不同的 SSH 密钥对是一种良好的安全习惯,尤其是在需要对不同的系统、服务或者权限进行访问时。这被称为密钥对的"密钥分离"或"密钥标签"。

场景区分的原因好好处如下:

  1. 最小化权限原则: 每个密钥对都代表着一组访问权限。通过为不同的场景生成不同的密钥对,你可以最小化系统中的特权,以便在需要时精确控制对资源的访问。

  2. 降低风险: 如果你在多个场景下都使用相同的密钥对,那么一旦私钥被泄露,攻击者就可以获取到所有相关场景的访问权限。通过使用不同的密钥对,即使某个密钥对受到威胁,其他场景的安全性仍然得到保障。

  3. 审计和跟踪: 使用不同的密钥对可以更轻松地进行审计和跟踪。你可以根据不同的密钥对来追踪特定用户或服务在系统中的活动,从而更好地了解和监控系统访问情况。

  4. 精细控制访问: 某些场景可能需要更高级别的权限,而另一些场景可能只需要较低级别的权限。通过为不同的场景生成不同的密钥对,你可以根据需要分配适当级别的权限,并确保用户或服务只能访问其需要的资源。

尽管在某些情况下使用相同的密钥对可能更方便,但根据不同的场景区分不同的密钥对可以提高系统的安全性和灵活性,减少潜在的风险和安全漏洞。

生成不同场景的 SSH 密钥

以区分私人项目和团队项目为例。

  1. 生成私人的 SSH 密钥对
bash
ssh-keygen -C "wxc@personal.com" -f ~/.ssh/id_rsa_personal
ssh-keygen -C "wxc@personal.com" -f ~/.ssh/id_rsa_personal

~/.ssh/ 下生成:id_rsa_personalid_rsa_personal.pub

  1. 生成团队的 SSH 密钥对
bash
ssh-keygen -C "wxc@team.com" -f ~/.ssh/id_rsa_team
ssh-keygen -C "wxc@team.com" -f ~/.ssh/id_rsa_team

~/.ssh/ 下生成:id_rsa_teamid_rsa_team.pub

  1. 添加 SSH 密钥到 ssh-agent

ssh-agent 是一个用于管理 SSH 密钥的身份验证代理程序。默认生成的 id_rsa 私钥会被自动添加到代理程序中,无需手动运行 ssh-add 命令。而非默认生成的密钥对只有添加代理程序才能起作用,否则实际使用时需要手动指定密钥,比较麻烦。

bash
# 确保 `ssh-agent` 正在运行:
eval "$(ssh-agent -s)"

# 添加私人密钥
ssh-add ~/.ssh/id_rsa_personal

# 添加团队密钥
ssh-add ~/.ssh/id_rsa_team
# 确保 `ssh-agent` 正在运行:
eval "$(ssh-agent -s)"

# 添加私人密钥
ssh-add ~/.ssh/id_rsa_personal

# 添加团队密钥
ssh-add ~/.ssh/id_rsa_team
  1. 查看是否添加成功

以下命令二选一:

bash
# 显示已经加载到 SSH agent 中的私钥的 fingerprint(指纹)信息。
ssh-add -l

# 显示已经加载到 SSH agent 中的公钥。
ssh-add -L
# 显示已经加载到 SSH agent 中的私钥的 fingerprint(指纹)信息。
ssh-add -l

# 显示已经加载到 SSH agent 中的公钥。
ssh-add -L

Mac 系统 SSH 密钥的持久化

提示

在 Mac 系统中,ssh-agent 在重启后,非默认的密钥会丢失,所以每次电脑重启后,或者有时候重新打开终端的时候,都需要重新添加非默认的密钥。

手动重新添加密钥的方式,略显繁琐。所以得想办法持久化非默认的 SSH 密钥。

在 Mac 系统中,可以选择 ~/.bash_profile~/.zshrc 中埋入自动添加 SSH 密钥到代理程序的脚本:

bash
# ===> 持久化 ssh 代理
if [ -z "$SSH_AUTH_SOCK" ]; then
    # 如果代理不存在,则启动代理
    eval "$(ssh-agent -s)"
fi
if ! ssh-add -l | grep -q "$(ssh-keygen -lf /Users/wxc/.ssh/id_rsa_personal | awk '{print $2}')"; then
    # 如果 id_rsa_personal 不在代理中,则添加到代理
    ssh-add /Users/wxc/.ssh/id_rsa_personal
fi
if ! ssh-add -l | grep -q "$(ssh-keygen -lf /Users/wxc/.ssh/id_rsa_team | awk '{print $2}')"; then
    # 如果 id_rsa_team 不在代理中,则添加到代理
    ssh-add /Users/wxc/.ssh/id_rsa_team
fi
# <=== 持久化 ssh 代理
# ===> 持久化 ssh 代理
if [ -z "$SSH_AUTH_SOCK" ]; then
    # 如果代理不存在,则启动代理
    eval "$(ssh-agent -s)"
fi
if ! ssh-add -l | grep -q "$(ssh-keygen -lf /Users/wxc/.ssh/id_rsa_personal | awk '{print $2}')"; then
    # 如果 id_rsa_personal 不在代理中,则添加到代理
    ssh-add /Users/wxc/.ssh/id_rsa_personal
fi
if ! ssh-add -l | grep -q "$(ssh-keygen -lf /Users/wxc/.ssh/id_rsa_team | awk '{print $2}')"; then
    # 如果 id_rsa_team 不在代理中,则添加到代理
    ssh-add /Users/wxc/.ssh/id_rsa_team
fi
# <=== 持久化 ssh 代理

而在 Windows 系统中使用 ssh-add 将密钥添加到 Windows 凭据管理器后,该密钥应该在系统重启后仍然有效。但是如果你更改了用户密码,你可能需要重新运行 ssh-add 来更新存储的密码。这是因为 Windows 凭据管理器与用户密码关联。

Last updated: