SSH
SSH 是远程登录和 Git 传输常用的加密协议。本页介绍密钥生成、ssh-agent、1Password SSH agent、commit 签名,以及把 Windows 配置为 SSH 服务端。
配置#
以下配置互相独立,按需选用。
生成 SSH 密钥#
生成一把 Ed25519 密钥,把 your_email@example.com 换成自己的邮箱:
在 Windows 上启动 ssh-agent#
Windows 需要先启动 ssh-agent 服务才能添加密钥:
通过 HTTPS 端口连接 GitHub#
在 ~/.ssh/config 里加上:
配置代理#
在 ~/.ssh/config 的 Host 块里加上:
使用 1Password SSH agent#
私钥只保存在 1Password 里,不落盘。SSH 认证和 commit 签名都由 1Password 的 agent 提供,每次使用需生物识别授权:
磁盘上只留公钥,供 ssh 在 agent 里定位对应私钥。
在 ~/.ssh/config 里加上:
写法要点:
- 通配段放在文件末尾。 ssh_config 的大多数选项是「第一个匹配生效」,具体
Host写在前面才能覆盖通配值。 - 通配段只写
IdentityAgent。 提供哪几把密钥、按什么顺序提供,由 agent.toml 决定。 IdentityFile指向公钥(.pub)。 ssh 用它在 agent 里查找对应私钥,本地不需要私钥文件。IdentityFile和IdentitiesOnly写在具体Host里。IdentityFile是累积型选项。写进Host *后,需要专用密钥的主机会先拿到通用密钥。写在具体Host里,IdentitiesOnly yes只作用于该主机,其余主机照常走 agent。
配置 1Password 密钥白名单#
在 ~/.config/1Password/ssh/agent.toml 里列出要提供的密钥,item 填 1Password 条目标题:
- 不配这个文件时,agent 只提供默认保管库(Personal / Private / Employee)里的 SSH 密钥。密钥放在自定义保管库时,必须配置这个文件。
- agent 按书写顺序把密钥提供给服务器。密钥多时,用顺序避免触发服务器常见的六次密钥尝试上限。
- 条目标题按精确匹配。在 1Password 里改了条目名,要同步修改这里,见故障排查。
用 1Password 签名 commit#
-
在
~/.gitconfig里加上,signingkey填完整公钥: -
创建
~/.config/git/allowed_signers,一行一个签名者:没有这个文件,本地
git log --show-signature会因找不到可信签名者而报错。 -
在 GitHub 上再添加一次公钥,类型选 Signing Key。认证密钥和签名密钥要分别添加。
统一密钥命名#
公钥末尾的 comment 不参与认证,只用于识别。以下三处用同一个值,用条目标题而非邮箱:
不要清空 comment。authorized_keys 有多个条目时,没有 comment 只能逐条用 ssh-keygen -lf 比对指纹。
浏览器填充公钥时不带 comment。目标平台把公钥原样写进 authorized_keys 时,改用 ssh-copy-id,它会带上本地 .pub 的 comment。
清除服务器上的 Git 身份#
不在服务器上提交代码时,清掉 Git 身份配置:
没有 user.email 时,git commit 会报 *** Please tell me who you are.,可防止误在服务器上提交。insteadOf 等不含个人信息的选项可以保留,方便 clone 和 pull。
需要临时提交一次时,在命令里传入身份:
保留备用登录方式#
私钥唯一副本在 1Password 里时,若再关闭密码登录,就只剩一条登录路径。账号锁定、服务故障,或设备丢失且没保存 Emergency Kit 时,将无法登录。
用云控制台的 VNC 或串口登录作为备用。它不经过 SSH,不增加攻击面。确认一次可用即可。
在 Windows 服务端安装公钥#
Windows 的管理员账户不读 ~/.ssh/authorized_keys。sshd_config 末尾有这一段:
账户在 Administrators 组里时,公钥必须写到 C:\ProgramData\ssh\administrators_authorized_keys。写进用户目录无效,也不会报错。
-
在 macOS 客户端上运行以下命令,
<用户>和<主机>换成服务端的用户名和地址。首次需要输入密码:命令的三部分缺一不可:
[IO.File]::WriteAllText:不写入 BOM;结尾的[char]10使换行为 LF。有 BOM 或 CRLF 时,sshd 认为公钥格式非法。icacls /inheritance:r:收紧权限。权限过宽时,sshd 静默忽略整个文件。Restart-Service sshd:重启 sshd。
-
在服务端验证:
在 Windows 服务端把默认 shell 设为 PowerShell 7#
SSH 登录 Windows 默认进入 cmd.exe。改为 PowerShell 7 需要写三个注册表值:
分两步写入。DefaultShell 写错会使 ssh 主机 '命令' 失效,之后只能在本机手动改注册表。
-
可选:没装 PowerShell 7 时先安装:
-
写入前两个值:
-
从客户端验证命令模式可用:
-
写入第三个值:
不需要重启 sshd,新会话立即生效。
只有 Windows PowerShell 5.1 时,把路径换成 C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe。5.1 和 7 的 $PROFILE 是两个不同文件(WindowsPowerShell\ 与 PowerShell\),配置不会自动共用。
使用#
日常管理密钥和连接的命令。
查看公钥#
macOS / Linux:
Windows(PowerShell):
测试 SSH 连接#
测试与 GitHub 的连接:
把密钥添加到 ssh-agent#
macOS / Linux:
Windows(PowerShell):
列出 ssh-agent 中的密钥#
列出已添加的密钥:
从 ssh-agent 移除密钥#
移除指定密钥,macOS / Linux:
Windows(PowerShell):
移除所有密钥:
agent 转发#
开启 agent 转发前注意:
- 远端 root 能读取
/tmp下的 agent socket,借用密钥连接任何信任你的机器。只对归属清楚的机器开启。 - 转发是会话级的。常驻会话(tmux、终端复用器的 pane)继承创建时那次连接的 socket 路径,原连接断开后失效,用 symlink 固定路径也无效。
- 远端不要设
commit.gpgSign = true,否则在没有 agent 的会话里git commit会失败。 - 自动化场景用专用的 deploy key,不要转发个人密钥。
验证 1Password 配置#
逐项检查 agent、认证和签名,主机、文件、OWNER/REPO 换成实际值:
删除本地私钥之前,先运行 ssh-keygen -Y sign。ssh-add -l 只证明 agent 知道这把密钥,签名成功才证明它持有可用的私钥。
故障排查#
以下问题按现象列出。
连接成功但用了错误的身份#
默认密钥在同一台服务器上也对应一个有效账号时,服务器会接受它,连接和命令都正常,只是身份错误。
对比 ssh -v 输出中 Server accepts key 那行的指纹与 ssh-add -l 的输出。确认后,在该主机的 Host 块里指定 IdentityFile 和 IdentitiesOnly yes,见使用 1Password SSH agent。
Load key 报 invalid format#
原因:1Password 条目改了名,agent.toml 里的 item 没有同步,agent 不再提供密钥(The agent has no identities)。ssh 于是把公钥当私钥读取。此时 SSH、Git 和签名同时失效。
- 把
~/.config/1Password/ssh/agent.toml里的item改为当前条目标题。 - 运行
ssh-add -l,确认 agent 列出密钥。
GitHub 上 commit 显示 Unverified#
原因:公钥只作为认证密钥添加,没有作为签名密钥添加。
- 在 GitHub 上把公钥再添加一次,类型选 Signing Key。
- 用验证 1Password 配置里的
gh api命令查看verification.reason:unsigned:commit 没有签名。unknown_key:平台不认识这把密钥(没添加,或添加成了 Authentication 类型)。bad_email:签名密钥关联的邮箱与 commit author 不一致。
Windows 服务端添加公钥后仍要求密码#
原因通常是以下之一,日志里没有明确提示:
- 账户在 Administrators 组里,公钥写进了用户目录的
authorized_keys。 administrators_authorized_keys的权限没有收紧,sshd 忽略了整个文件。- 文件带 BOM 或 CRLF 换行,sshd 认为公钥格式非法。
按在 Windows 服务端安装公钥重新写入,并运行其中的验证命令。
改用 PowerShell 后 SSH 会话报错#
默认 shell 是 cmd.exe 时 profile 不加载。改用 PowerShell 后,profile 里已有的问题会第一次出现。
Windows 11 24H2 及以后最常见的是「不受信任的装入点」:SSH 会话读不了部分符号链接和 junction,依赖它们的工具(fnm、WinGet 的 shim、pnpm、vite-plus)会报错。修复方法:用 mklink /J 重建被拦的 junction;把 %LOCALAPPDATA%\Microsoft\WinGet\Packages\<包 ID> 加到用户 PATH 前面,绕开 WinGet 的 shim;安装和升级改到本地或远程桌面做。