SSH 公钥认证机制与 Linux 登录 SSH 配置
SSH(Secure Shell)是一种用于安全远程登录和通信的网络协议,广泛应用于 Linux 服务器管理、远程命令执行、文件传输以及代码仓库访问等场景
OpenSSH 是 SSH 协议最常见的实现,包含 ssh/sshd 等核心组件,并提供 ssh-keygen、ssh-agent、ssh-add 等辅助工具,用于完成基于公钥的身份认证与密钥管理
一、SSH 认证机制
1.1 公钥/私钥体系
-
公钥(Public Key)
- 存放于目标端(通常为
~/.ssh/authorized_keys,具体取决于服务端AuthorizedKeysFile配置) - 用于验证客户端使用私钥签名的数据有效性
- 存放于目标端(通常为
-
私钥(Private Key)
- 保存在本地(如
~/.ssh/id_ed25519、id_rsa或自定义路径) - 用于对服务端发起的挑战(challenge)进行签名,以证明身份
- 保存在本地(如
SSH 客户端使用私钥生成签名,服务端用对应的公钥验证;验证通过即建立信任连接
1.2 多密钥尝试流程
SSH 并非仅使用单一私钥,而是按以下顺序尝试多个来源:
-
启动 SSH 客户端并读取配置文件
-
收集可用私钥:
- 已通过
ssh-add加载至ssh-agent的密钥(优先级最高) - 命令行
-i指定的私钥 ~/.ssh/config中配置的IdentityFile- 默认路径下的标准名称密钥(如
id_ed25519,id_rsa)
- 已通过
-
依次使用这些私钥对服务端 challenge 进行签名
-
服务端用对应公钥验证签名
-
任一匹配成功即完成认证;否则返回
Permission denied (publickey)
NOTE若自定义密钥未通过
ssh-add加载到ssh-agent,即使IdentityFile已配置,也可能因ssh-agent为空而认证失败
二、ssh-keygen:密钥生成与管理
2.1 核心功能
- 生成新的密钥对(
.pub公钥 + 私钥) - 为私钥设置或修改密码(passphrase)
- 从私钥导出公钥
- 转换密钥格式(OpenSSH ↔ PEM ↔ RFC4716)
- 生成主机密钥(Host Key)
2.2 密钥算法建议
| 算法 | 推荐度 | 说明 |
|---|---|---|
| Ed25519 | 强烈推荐 | 安全性高、密钥短、性能优、现代系统默认支持 |
| RSA (4096位) | 仅用于兼容旧系统 | 避免使用 2048 位以下 |
2.3 基本语法与常用选项
ssh-keygen [选项]| 选项 | 作用 |
|---|---|
-t <type> | 指定算法(ed25519,rsa) |
-b <bits> | RSA 密钥长度(建议 4096) |
-C "comment" | 添加注释(如邮箱、用途) |
-f <file> | 指定密钥保存路径 |
-N "pass" | 设置私钥密码(-N ""表示无密码) |
-p | 修改已有私钥密码 |
-y | 从私钥导出公钥 |
-e/-i | 公钥格式导出/导入 |
-o | 使用新 OpenSSH 私钥格式(更安全) |
-q | 静默模式 |
2.4 使用示例
以下示例展示 ssh-keygen 在常见使用场景下的典型用法
2.4.1 生成 Ed25519 密钥(推荐,默认路径)
ssh-keygen -t ed25519 -C "your_email@example.com"-
适用于 单一身份、默认配置 的场景
-
密钥默认生成在:
- 私钥:
~/.ssh/id_ed25519 - 公钥:
~/.ssh/id_ed25519.pub
- 私钥:
-
若文件已存在,
ssh-keygen会提示是否覆盖
2.4.2 生成 Ed25519 密钥并指定存放位置
ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/id_ed25519- 适用于 多账号 / 多用途密钥管理 场景(如 GitHub、服务器区分)
- 可配合
~/.ssh/config中的IdentityFile使用 - 不会影响已有默认密钥
2.4.3 生成 RSA 4096 位密钥(兼容旧系统)
ssh-keygen -t rsa -b 4096 -C "your_email@example.com" -f ~/.ssh/id_rsa -N ""-
仅在目标系统 不支持 Ed25519 时使用
-
-N ""表示私钥不设置密码(自动化场景常见) -
生成文件:
- 私钥:
~/.ssh/id_rsa - 公钥:
~/.ssh/id_rsa.pub
- 私钥:
2.4.4 修改已有私钥的密码(不影响公钥)
ssh-keygen -p -f ~/.ssh/id_rsa-
用于:
- 为无密码私钥补充 passphrase
- 定期轮换私钥密码
-
不会改变密钥内容,公钥仍然有效
2.4.5 从私钥重新导出公钥
ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub-
适用于:
- 公钥文件丢失
- 需要重新部署
authorized_keys
-
前提是私钥仍然存在
-
导出的公钥与原公钥完全一致
2.4.6 转换公钥格式(如 PEM)
ssh-keygen -e -f ~/.ssh/id_rsa.pub -m PEM-
用于与 非 OpenSSH 工具或旧系统 兼容
-
常见于:
- 某些老版本 SSH
- 第三方系统或设备
2.5 文件权限设置
OpenSSH 在使用基于公钥的身份认证时,会对相关目录和文件的权限进行严格检查,以防止私钥或授权文件被其他用户篡改或读取 除权限外,OpenSSH 也会校验文件/目录属主是否为目标用户或 root(取决于场景),属主异常同样可能导致认证失败
2.5.1 权限要求
-
~/.ssh目录:Terminal window chmod 700 ~/.ssh仅允许当前用户访问,防止他人向该目录注入恶意密钥。
-
私钥文件(如
id_ed25519、id_rsa):Terminal window chmod 600 ~/.ssh/id_*私钥必须仅对所有者可读写,否则 OpenSSH 会认为密钥不安全而拒绝使用。
-
authorized_keys文件:Terminal window chmod 600 ~/.ssh/authorized_keys防止其他用户向该文件写入未授权的公钥。
-
用户 home 目录:
- 不应设置为
777 - 通常要求为
755或更严格
如果 home 目录可被他人写入,OpenSSH 会认为认证环境不可信。
- 不应设置为
2.5.2 权限校验行为说明
-
权限检查发生在 认证阶段
-
校验逻辑由 SSH 客户端 / 服务端 执行:
- 客户端:检查私钥文件权限
- 服务端:检查用户 home、
.ssh及authorized_keys
-
一旦检测到权限过宽,认证流程会被中止
常见错误表现包括:
Permissions 0644 for 'id_rsa' are too openAuthentication refused: bad ownership or modes三、SSH Agent 与 ssh-add
3.1 ssh-agent 的作用
- 在内存中缓存私钥,避免重复输入 passphrase (如果设置了私钥密码)
- 提供统一接口供 SSH 客户端调用签名操作
- 增强安全性:私钥不直接暴露给客户端进程
- 支持多密钥集中管理
3.2 工作机制
-
启动后生成两个关键环境变量:
SSH_AUTH_SOCK:Unix 域套接字路径,用于通信SSH_AGENT_PID:agent 进程 ID
-
SSH 客户端通过这些变量与 agent 交互,请求签名
3.3 为何需要 ssh-add
- 将私钥显式加载到 agent 的内存中
- SSH 连接时优先从 agent 获取可用密钥
- 在使用非默认路径或多个密钥时,未加载则可能无法认证
建议配合
~/.ssh/config使用IdentitiesOnly yes,确保仅使用指定密钥
3.4 使用示例
3.4.1 Linux / macOS
# 启动 agenteval "$(ssh-agent -s)"
# 添加私钥ssh-add ~/.ssh/ssh-github
# 查看已加载密钥ssh-add -l
# 清空所有密钥ssh-add -D3.4.2 Windows(PowerShell)
Set-Service ssh-agent -StartupType AutomaticStart-Service ssh-agentssh-add $env:USERPROFILE\.ssh\ssh-github3.4.3 通过 ~/.ssh/config 指定密钥
通过 /.ssh/config 为特定主机指定端口、用户名与 IdentityFile,避免每次手动输入参数
Host github.com HostName ssh.github.com User git Port 443 IdentityFile ~/.ssh/ssh-github IdentitiesOnly yes加载后测试连接:
Terminal window ssh -T git@github.com
四、配置 Linux SSH 登录
NOTE目标:实现通过公钥认证登录 Linux 服务器 适用系统:Ubuntu、Debian、CentOS、Rocky、AlmaLinux 等
4.1 在客户端生成密钥对
# 推荐:Ed25519ssh-keygen -t ed25519 -C "your_email@example.com"
# 或兼容旧系统:RSA 4096ssh-keygen -t rsa -b 4096 -C "your_email@example.com"- 默认保存路径:
~/.ssh/id_ed25519(私钥)和id_ed25519.pub(公钥) - 可选设置 passphrase(提升安全性)
4.2 确保服务端安装并启用了 SSH
# Ubuntu / Debiansudo apt update && sudo apt install -y openssh-server
# CentOS / Rocky / Alma (8+)sudo dnf install -y openssh-server
# CentOS 7sudo yum install -y openssh-server
# 启动并启用开机自启sudo systemctl enable --now sshdsudo systemctl status sshd4.3 部署公钥至服务端
4.3.1 自动部署(使用 ssh-copy-id)
在客户端执行:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server_ip # user 为用户名,server_ip 为服务器 IP该命令会自动创建
~/.ssh/authorized_keys并设置正确权限(600)
4.3.2 手动部署
-
在客户端查看并复制公钥内容:
Terminal window cat ~/.ssh/id_ed25519.pub -
在服务端创建
~/.ssh/authorized_keys文件,并粘贴公钥内容Terminal window mkdir -p ~/.sshchmod 700 ~/.sshnano ~/.ssh/authorized_keys # 粘贴整行chmod 600 ~/.ssh/authorized_keys
4.4 配置 SSH 服务端参数
编辑 /etc/ssh/sshd_config文件,并修改参数
PubkeyAuthentication yesAuthorizedKeysFile .ssh/authorized_keysPermitRootLogin prohibit-password # 允许 root 使用密钥登录,禁止密码PasswordAuthentication yes # 暂时保留,便于调试TIP先保留密码登录,确认密钥认证成功后再禁用
重载配置(不中断现有连接):
sudo systemctl reload sshd4.5 验证连接
ssh -i ~/.ssh/id_ed25519 user@server_ip-
成功:直接进入 shell,无密码提示
-
失败:启用详细日志排查:
Terminal window ssh -v -i ~/.ssh/id_ed25519 user@server_ip
4.6 安全加固(可选)
编辑 /etc/ssh/sshd_config文件,并修改参数
PasswordAuthentication no # 完全禁用密码登录PermitRootLogin prohibit-password # 仅允许 root 使用密钥AllowUsers alice bob deploy # 限制可登录用户Port 2222 # 更改默认端口(减少扫描攻击)重载服务:
sudo systemctl reload sshd修改端口后需指定端口登录:
ssh -p 2222 -i ~/.ssh/id_ed25519 user@server_ip五、常用 SSH 客户端命令
| 命令 | 用途 |
|---|---|
ssh user@host | 登录远程主机 |
ssh -p 2222 user@host | 指定端口 |
ssh -i key user@host | 指定私钥 |
ssh -T git@github.com | 测试 GitHub SSH |
ssh -v user@host | 显示调试日志 |
scp file user@host:/path | 上传文件 |
scp user@host:/file . | 下载文件 |
rsync -avz -e ssh src/ user@host:/dst/ | 同步目录 |
ssh -L 8080:localhost:80 user@host | 本地端口转发 |
ssh -R 8080:localhost:80 user@host | 远程端口转发 |
ssh-agent bash | 启动带 agent 的 shell |
ssh-add key | 加载私钥到 agent |
ssh-add -l | 列出 agent 中密钥 |
ssh-add -D | 清空 agent |
六、常见问题排查
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
Permission denied (publickey) | authorized_keys权限错误 | chmod 600 ~/.ssh/authorized_keys |
| 仍提示输入密码 | 公钥未生效 /PubkeyAuthentication no | 检查sshd_config和公钥内容 |
无法写入.ssh目录 | 家目录权限过宽(如 777) | chmod 755 ~,.ssh设为 700 |
| 连接被拒 | SSH 未运行 / 防火墙阻断 | sudo ufw allow 22(或自定义端口) |
| Git 报错 Permission denied | 密钥未加载到 agent | ssh-add ~/.ssh/your_key |
非商业用途可以使用,但必须注明出处;
若有改编需采用相同许可协议发布。