Vibe Coding 时代,大家的 SSH 密钥凭证还躺在磁盘上吗?

有安全机构统计过,光 2026 年就至少有 687 个恶意包在 npm 、PyPI 等社区公开传播。比较知名的 TanStack 被投毒事件跟我擦肩而过——我那个项目要是晚两天创建就中招了。

现在 AI 时代,大家用 Claude Code 、Codex 之类的工具基本都开着 --skip-permissions--yolo 模式。虽然后来 Claude Code 推出了 auto 模式,让 AI 来审批命令,安全性有了一点提升,但仍然无法从根源杜绝供应链攻击。总不可能让 AI 把每个包都审计一遍,那样用户的钱包可承受不起。

目前已知的供应链攻击,基本都会想尽办法偷取本地的各种凭证:SSH 密钥、AWS Credentials 、npm login token 、Docker login token…SSH 密钥和 AWS 凭证一旦泄露,GitHub 代码和服务器就几乎在裸奔; npm 和 Docker 的 token 被盗,则会沦为供应链攻击下一跳的肉鸡。

于是我开始琢磨怎么规避这种风险。后来看到 1Password 提供了一套方案:把 SSH 密钥、敏感环境变量等都托管在 1Password 里,需要用的时候在 macOS 上弹出指纹认证来授权。这样基本兼顾了安全和便利,唯一的小缺点就是推代码时人不在电脑前会认证失败:dog_face:

前置条件

  • 1Password8
  • 1Password CLI
brew install --cask 1password-cli

然后在 1Password 设置中开启 Developer 下的两个选项:Use the SSH AgentIntegrate with 1Password CLI

SSH 密钥托管

基本配置:GitHub

编辑 ~/.ssh/config

Host github.com
	IdentityFile ~/.ssh/1p/github.com.pub
	IdentitiesOnly yes
	IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"

原理很简单:先在 1Password 里创建一个 SSH Key ,把公钥导出到 github.com.pub,然后在 config 里指定这个公钥文件。这样触发认证时,SSH Agent 就知道该用哪个私钥来签名。如果不指定 IdentityFile,在有多个 SSH Key 的情况下会逐个尝试,容易触发重试上限导致连接失败。

进阶:Agent Forwarding

但这里会有一个问题。假如我需要从 Mac 连接到一台 Linux 服务器,在远端需要 push 代码时,能不能让本地的 1Password 来完成认证?

答案是可以的。关键配置是 ForwardAgent yes

Host jenkins-ci
	HostName 192.168.10.20
	User ubuntu
	IdentityFile ~/.ssh/1p/jenkins-ci.pub
	IdentitiesOnly yes
	ForwardAgent yes

通过 ssh jenkins-ci 连上之后,如果在远端需要 git push 之类的操作,认证请求会沿着 SSH 通道转发回来,拉起本地 1Password 的指纹验证。

如果不想要用 sshconfig 配置,也可以直接使用 ssh -A ubuntu@192.168.10.20 的方式。

再进阶:两台 Mac 互连的场景

还有一个更细的场景:假如两台 Mac 之间互相远程连接,提交代码时默认会拉起本地(发起连接的那台)的 1Password 认证。但如果我希望“本地操作就用本地 macOS 认证,被远程连接时就用远程 macOS 机器的认证”呢?

答案是用 SSH config 的 Match 指令:

Match host * exec "test -z $SSH_TTY"
	IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"

$SSH_TTY` 只在通过 SSH 登录的会话中才有值,所以这条规则只在本地终端(非 SSH 会话)时才生效,这时使用本地 1Password 的 Agent Socket 。而当你是被远程连进来的,`$SSH_TTY 非空,这条规则跳过,认证就走远端自己的 1Password 。

完整配置

把上面的逻辑拼起来,最终的 ~/.ssh/config 长这样:

Match host * exec "test -z $SSH_TTY"
	IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"

Host github.com
	# 指定个人密钥的公钥,避免在多身份环境下匹配到错误的 Key
	IdentityFile ~/.ssh/1p/github.com.pub
	IdentitiesOnly yes

Host jenkins-ci
	HostName 192.168.10.20
	User ubuntu
	IdentityFile ~/.ssh/1p/jenkins-ci.pub
	IdentitiesOnly yes
	ForwardAgent yes

AWS 凭证托管

AWS Credentials 同样是高危目标。平时 AWS CLI 在用,很多工具也会直接读 ~/.aws/credentials 文件,把密钥明文存在磁盘上总归不太舒服。

可以用 1Password CLI 的 op read 来替代。做法是在 1Password 里新建一个登录项目,把账号的 label 改成 access key id,密码的 label 改成 secret access key,保存后在对应字段右侧找到“ Copy Secret Reference ”,拿到引用路径。

最终配置成环境变量命令:

export AWS_ACCESS_KEY_ID=$(op read "op://Private/AWS Access Key/access key id")
export AWS_SECRET_ACCESS_KEY=$(op read "op://Private/AWS Access Key/secret access key")

在有需要的时候执行,也可以设置成 alias 方便快速执行。

执行后会弹出指纹验证,通过之后这两个环境变量就有值了。接下来正常使用即可:

aws s3 ls

或者打开其他依赖 AWS 配置的应用,比如用 OpenLens 管理 EKS:

open -a /Applications/OpenLens.app

延伸阅读

1Password 官方文档写得更详细,涵盖了更多场景,推荐去看看:1Password 开发者文档

对了,文档里提到的 Git Commit 签名功能,建议别开。不然 vibe coding 的时候有得受了,每次提交都要授权一次。折腾半天配好,也就是在 GitHub 的 commit 记录上多个 Verified 绿标,没啥实际意义。

安全无绝对,同时安全和便利上是属于鱼和熊掌不可兼得。1password 是我大半年使用下来比较均衡的选项。

各位如果有什么其他更好的方案,也欢迎互相讨论分享。

又是炒概念,搞点花里胡哨的方案就敢说安全了?你这一套下来,攻击面反而更大了吧,一个1Password主密码泄露全盘皆输。三个月后再看,你这方案肯定一堆坑。泡沫总会破的。

小白请教一下,这个“供应链攻击”具体是怎么偷走SSH密钥的啊?是不是只要我不乱安装来路不明的包就没事?另外,为啥要开那个 --yolo 模式啊,听起来好危险。

前排,蹲个后续。看看这方案到底能不能用住,感觉会有人出来吐槽兼容性问题。搬好小板凳。

能少干点是点,我觉得有道理啊!多一层防护总比裸奔强。你让我自己手动管理各种密钥,我早晚得忘或者存错地方。工具化提效等于早下班,这波我站楼主。老板天天画饼说安全,不如给团队配个1Password。

哪有免费的?1Password要收费吧?这个方案有没有平替啊?比如用系统自带的钥匙串能实现类似效果吗?我就想撸点免费羊毛。

这波啊,这波是“你可以白嫖我的代码,但不能白嫖我的安全”。人类的本质是既要马儿跑,又要马儿不吃草。我先笑为敬。

哦~是吗?楼上这位老师傅,您这么懂,想必您那套“绝对安全”的祖传手抄密钥大法,一定连SolarWinds事件都能轻松防住吧?不愧是你,赢麻了。

支持国产!不过为啥要用国外的1Password?国内也有优秀的密码管理工具啊,安全性和易用性都很好,价格还更香。核心技术还是得掌握在自己手里。

系统钥匙串能顶一部分,但跨设备同步就麻烦了

钥匙串顶单机够用,多设备同步确实是个麻烦