外观
凭据管理:钥匙串、SSH 密钥与密码
脚本要连服务器,Git 要推代码,备份要解密仓库。这些都需要凭据,而把凭据写进脚本或配置文件是最省事也最危险的做法。
macOS 自带的钥匙串能解决其中大部分。这一篇讲怎么让凭据既取得到、又不以明文躺在磁盘上。
开始之前
需要能在终端执行命令。本文会生成一对 SSH 密钥并写入钥匙串,两者都可以删除。
先建立一条底线:任何会进版本库的文件里都不能有密码、私钥或令牌。一旦提交过,改密码是唯一的补救——从历史里删掉不算数,内容可能已经被抓取。
钥匙串是什么
钥匙串是 macOS 的凭据存储,内容加密,由你的登录密码保护。Wi-Fi 密码、网站密码、访达保存的共享凭据、证书都在里面。
图形界面是「钥匙串访问」(应用程序 → 实用工具)。macOS 较新版本还提供了「密码」应用,面向网站与应用账号;底层的钥匙串仍然存在,供开发相关的凭据使用。
命令行读写
存一条:
sh
security add-generic-password -a "$USER" -s "我的服务" -wsecurity 是钥匙串的命令行工具。add-generic-password 添加一条通用密码,-a 指定账号($USER 是当前用户名的环境变量),-s 指定服务名(自己起,用来检索),-w 不跟值时会提示你输入——这样密码不会出现在 shell 历史里。
读出来:
sh
security find-generic-password -s "我的服务" -w-w 表示只输出密码本身,方便在脚本里使用。首次访问时系统会弹窗要求确认,可以选择「始终允许」。
删掉:
sh
security delete-generic-password -s "我的服务"在脚本里用
sh
export DB_PASSWORD="$(security find-generic-password -s "我的服务" -w)"$(...) 把命令的输出作为值。这样脚本文件里只有服务名,没有密码。
比起写在 .env 文件里,好处是:文件误传、误提交、被备份到别处时,泄露的只是一个服务名。
SSH 密钥
生成
sh
ssh-keygen -t ed25519 -C "你的标识"ssh-keygen 生成密钥对,-t ed25519 指定算法(现在的推荐选择,比 RSA 更短更快),-C 加一段注释用于辨认,通常写邮箱或「机器名-用途」。
会提示设置口令(passphrase),请设置一个。 不设的话,私钥文件本身就是完整的凭据——文件被复制走,对方立刻拥有你所有服务器的访问权。设了口令,拿到文件的人还需要口令。
生成的两个文件:~/.ssh/id_ed25519 是私钥,永远不要发给任何人、不要提交、不要备份到不加密的地方;~/.ssh/id_ed25519.pub 是公钥,可以自由分发,放到服务器上。
让口令不用反复输
macOS 的 ssh-add 可以把口令存进钥匙串:
sh
ssh-add --apple-use-keychain ~/.ssh/id_ed25519按 man ssh-add 的说明,--apple-use-keychain 在添加身份时把口令一并存入钥匙串。注意这是 macOS 特有的选项,旧版本叫 -K,现在已改名。
让它每次登录自动生效,编辑 ~/.ssh/config:
Host *
UseKeychain yes
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519UseKeychain yes 允许从钥匙串取口令(这是 macOS 版 OpenSSH 的选项),AddKeysToAgent yes 在使用时自动把密钥加进代理,IdentityFile 指定默认用哪把私钥。
~/.ssh/config 的权限要收紧:
sh
chmod 600 ~/.ssh/config不同服务用不同密钥
Host github.com
IdentityFile ~/.ssh/id_ed25519_github
Host myserver
HostName 192.168.1.50
User myname
IdentityFile ~/.ssh/id_ed25519_homeHost 是你在命令行里输入的别名,HostName 是真实地址,User 是登录用户名。配好之后 ssh myserver 就够了,不用记地址和用户名。
一个密钥泄露时,只需要在对应的一处服务上撤销,不必更换全部。
Git 的凭据
macOS 自带的 Git 带有钥匙串凭据助手:
sh
git config --global credential.helper osxkeychain--global 表示对所有仓库生效,credential.helper 指定用哪个助手保存凭据。配好之后,HTTPS 方式推送时输入一次用户名和令牌,之后由钥匙串接管。
用 SSH 方式(git@github.com:...)的话走的是上面的 SSH 密钥,不需要这项配置。
别把密钥提交上去
在全局忽略文件里加上常见的凭据文件名:
sh
git config --global core.excludesfile ~/.gitignore_globalcore.excludesfile 指定一个全局忽略规则文件。在 ~/.gitignore_global 里写:
.env
.env.*
*.pem
*.key
id_rsa
id_ed25519
.netrc这是一层保险,不是保证——真正的保证是提交前看一眼 git diff --cached。相关清单见dotfiles 管理。
密码管理器
钥匙串适合本机与开发凭据。需要跨设备、与他人共享、或者保存恢复密钥这类东西时,用专门的密码管理器。
选择时看三点:是否端到端加密(服务商自己也读不到)、是否能导出(哪天不想用了能不能带走数据)、恢复机制是什么(主密码丢了会怎样)。
无论用哪个,有两类东西必须存进去:
- 加密备份的仓库密码——丢了备份就永久打不开,见加密增量备份。
- FileVault 恢复密钥——见账户与 FileVault。
这两样都没有任何找回途径。
检查结果
sh
ls -la ~/.ssh-a 显示隐藏文件。私钥的权限应当是 -rw-------(600)。权限太松时 ssh 会直接拒绝使用该密钥。
sh
ssh-add -l-l 列出当前代理里已加载的密钥。能看到你的密钥,说明口令已经生效,不会再反复提示。
sh
security find-generic-password -s "我的服务" -w能取出刚才存的密码,说明命令行读写钥匙串可用。
动手练习
建立一套凭据,验证它不以明文存在:
- 生成一对测试密钥:
ssh-keygen -t ed25519 -f ~/.ssh/id_test -C "test",设一个口令(-f指定输出文件名)。 ssh-add --apple-use-keychain ~/.ssh/id_test,输入口令。ssh-add -l确认它已加载。- 用
security add-generic-password存一条测试密码,再用find-generic-password -w取出来。 - 尝试
grep -r "你设的测试密码" ~/.ssh ~/.zshrc 2>/dev/null,确认搜不到明文。 - 清理:
ssh-add -d ~/.ssh/id_test,rm ~/.ssh/id_test*,security delete-generic-password -s "测试服务"。
成功标准是第 5 步——凭据能用,但在文件系统里搜不到明文。这是判断一套凭据方案是否合格的最直接办法:如果你能 grep 到自己的密码,别人也能。