效率工具

用 1Password 管理 SSH 密钥

用 1Password 管理 SSH 密钥:推送代码时由 1Password SSH 代理提供认证密钥,私钥不落盘;提交时用另一把 SSH 密钥签名,GitHub 上显示 Verified,本地也能用 allowed_signers 验证。

BINBHO · 图文教程

用 1Password 管理 SSH 密钥:推送代码时由 1Password SSH 代理提供认证密钥,私钥不落盘;提交时用另一把 SSH 密钥签名,GitHub 上显示 Verified,本地也能用 allowed_signers 验证。

先看清成品

本机没有 1Password 桌面 App,所以用 ssh-keygen 生成的测试密钥 + 系统 ssh-agent 代替 1Password 代理,在 Git 2.47.3 上实际跑通了 SSH 签名提交和本地验证(%G? 为 G),并复现了签名密钥写错时的报错。1Password SSH 代理、op-ssh-sign 和 GitHub 上的 Verified 标记没有实际验证;配置写法来自 1Password 官方文档。

注意:1Password 是付费服务,计划和价格以官方价格页为准。不要共享个人账号或把主密码、Secret Key、服务账号令牌发给别人;团队共享请用共享保险库和权限设置。只管理你有权管理的凭据。

做完之后你会得到什么?

成果 说明
两把密钥 认证密钥、签名密钥,都存放在 1Password
agent.toml 控制代理提供哪些密钥、按什么顺序
~/.ssh/config GitHub 走 1Password 代理
Git 签名配置 gpg.format=ssh + allowed_signers
检查脚本 打印签名配置来源并验证最近一次提交

需要准备哪些环境?

项目 要求 说明
1Password 桌面 App Mac / Windows / Linux 设置 → 开发者 → 打开 SSH 代理
Git 2.34 以上 SSH 签名从 2.34 开始支持
GitHub 账号 能添加 SSH 密钥 签名密钥的类型选 Signing key

文件结构

23-1password-C-src/
├── agent.toml          # 复制到 ~/.config/1Password/ssh/agent.toml
├── ssh_config          # 追加到 ~/.ssh/config
└── check_signing.sh

第 1 步:生成两把密钥

在 1Password 里新建两个 SSH 密钥条目(类型 ed25519):GitHub 认证密钥、Git 签名密钥。认证和签名分开,任何一把出问题都可以单独轮换。

第 2 步:配置 SSH 代理

agent.toml:

# ~/.config/1Password/ssh/agent.toml
# 按顺序提供密钥,避免服务器默认 6 次尝试上限(MaxAuthTries)
[[ssh-keys]]
item = "GitHub 认证密钥"
vault = "Private"

[[ssh-keys]]
item = "Git 签名密钥"
vault = "Private"

[[ssh-keys]] 的顺序就是代理提供密钥的顺序。文件一旦存在就会覆盖默认行为,没写进来的密钥不会提供。

ssh_config:

# 追加到 ~/.ssh/config
# Linux 的代理套接字;macOS 为 "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"
Host github.com
  HostName github.com
  User git
  IdentityAgent ~/.1password/agent.sock
  # 把公钥导出后指定,只提供这一把,避免逐把尝试
  IdentityFile ~/.ssh/github_auth.pub
  IdentitiesOnly yes

IdentityFile 指向公钥文件即可(在 1Password 中下载公钥),配合 IdentitiesOnly yes 只提供这一把。

ssh -T git@github.com

预期结果:1Password 弹窗请求授权,之后显示 Hi 用户名! You've successfully authenticated...。

第 3 步:配置提交签名

最省事的方法:在 1Password 中打开签名密钥 → Configure Commit Signing → Edit Automatically。它会写入:

[user]
  signingkey = ssh-ed25519 AAAA...(你的签名公钥)
[gpg]
  format = ssh
[gpg "ssh"]
  program = (1Password 的 op-ssh-sign 路径,以 App 生成的片段为准)
[commit]
  gpgsign = true

本地验证需要 allowed_signers 文件:

echo "你的提交邮箱 ssh-ed25519 AAAA...签名公钥" >> ~/.ssh/allowed_signers
git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers

然后在 GitHub Settings → SSH and GPG keys → New SSH key,Key type 选 Signing key,粘贴签名公钥。

第 4 步:检查配置

check_signing.sh:

#!/usr/bin/env bash
# 在仓库目录运行,打印签名相关配置及来源,并验证最近一次提交的签名
set -u
for k in gpg.format user.signingkey user.email gpg.ssh.program commit.gpgsign gpg.ssh.allowedSignersFile; do
  printf '%-28s %s\n' "$k" "$(git config --show-origin --get "$k" 2>/dev/null || echo '(未设置)')"
done
echo "---"
git log -1 --format='%h %G? %GS %s'
echo "(%G? 含义:G=有效签名,N=未签名,U=有效但签名者未在 allowed_signers 中,B=签名无效)"

本机演示(测试密钥代替 1Password,gpg.ssh.program 使用默认 ssh-keygen)实际输出:

gpg.format                   file:.git/config	ssh
user.signingkey              file:.git/config	ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIp1zT1f... demo@example.com
user.email                   file:.git/config	demo@example.com
gpg.ssh.program              (未设置)
commit.gpgsign               file:.git/config	true
gpg.ssh.allowedSignersFile   file:.git/config	.git/allowed_signers
---
832ed9a G demo@example.com 第一次签名提交

--show-origin 能看出配置来自全局还是仓库,排查“明明配了却不生效”很有用。

调试示例

把 user.signingkey 写成不完整的公钥后提交,本机实际输出:

error: Couldn't load public key /tmp/.git_signing_key_tmptmsJhh: No such file or directory?
fatal: failed to write commit object

与 1Password 文档列出的错误一致,原因是 user.signingkey 不是有效公钥。用 git config --show-origin user.signingkey 找到是哪一层配置写错了。

另一个容易误会的点:本机演示中把 user.email 改成 other@example.com 后再提交,本地 %G? 仍是 G,因为本地验证按公钥在 allowed_signers 里找到了签名者。GitHub 还要求提交邮箱是你账号里已验证的邮箱,否则不会显示 Verified。

出错了怎么办?

现象 原因 解决
unsupported value for gpg.format: ssh Git 低于 2.34 升级 Git
fatal: failed to write commit object signingkey 无效 见调试示例
gpg.ssh.allowedSignersFile needs to be configured 没有 allowed_signers 按第 3 步创建;不影响提交,只影响本地验证
GitHub 显示 Unverified 邮箱不匹配,或公钥加成了认证密钥 检查 git config user.email,重新以 Signing key 类型添加
Too many authentication failures 代理提供的密钥太多 在 agent.toml 调整顺序,或用 IdentitiesOnly
代理配置文件改了没反应 语法错误时代理会停止 在 App 的开发者设置里查看错误提示

模板规则

  • 认证密钥和签名密钥分开。
  • 提交邮箱与 GitHub 已验证邮箱一致。
  • 用 --show-origin 排查配置覆盖。

项目资源

用途 地址
1Password SSH 入门 https://www.1password.dev/ssh/get-started
SSH 代理配置文件 https://www.1password.dev/ssh/agent/config
用 SSH 签名 Git 提交 https://www.1password.dev/ssh/git-commit-signing
GitHub 提交签名验证 https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification
git-config 文档 https://git-scm.com/docs/git-config

私钥放在 1Password 里,每次使用都要你确认,电脑丢了或被植入恶意程序,也没法直接把私钥拷走。签名则让别人能确认提交真的是你做的,两件事一次配好。