前言

日常开发中,我们每个人手里都有十几个甚至几十个 API Key:OpenAI、Anthropic、AWS、GitHub Token、Stripe……

它们通常散落在这些地方:

  • 项目里的 .env 文件
  • ~/.bashrc~/.zshrc 里的环境变量
  • 浏览器书签或备忘录
  • 各种配置文件

用的时候到处翻,找到了还要手动复制。更糟糕的是,.env 文件一不小心就提交到 Git 了,Key 泄露到 GitHub 上……

所以我写了 mk (My Keys) —— 一个极简的终端工具,把所有 API Key 存到系统 Keychain 里,两个字母就能管理。

效果演示

$ mk set openai sk-proj-abc123...
  ✓  Set openai

$ mk set nvidia nvapi-xyz789...
  ✓  Set nvidia

$ mk ls
  ● nvidia
  ● openai

$ mk get openai
sk-proj-abc123...

$ mk cp openai
  ✓  Copied openai to clipboard

$ mk rm openai
  ✓  Removed openai

为什么不用 .env?

我对比了一下常见的方案:

方案 安全性 便捷性 跨项目
.env 文件 ❌ 明文存磁盘 ⚠️ 需要 cd 到项目目录 ❌ 每个项目都要配
1Password ✅ 加密存储 ⚠️ 需要打开 App ✅ 全局可用
pass (GPG) ✅ 加密存储 ❌ 需要 GPG 配置 ✅ 全局可用
mk ✅ 系统级加密 ✅ 两个字母 ✅ 全局可用

mk 的优势在于:零配置,零依赖,跟系统登录密码同级安全。

实际使用场景

1. 嵌入命令

curl -H "Authorization: Bearer $(mk get openai)" https://api.openai.com/v1/models

2. 设置环境变量

export ANTHROPIC_API_KEY=$(mk get anthropic)

3. 复制到剪贴板(终端不留痕迹)

mk cp openai

这个特别实用。直接 mk get 会在终端里打印 Key,而 mk cp 只复制到剪贴板,终端历史里不会留下任何痕迹。

安装

macOS

brew tap axliupore/tap
brew install axliupore/tap/mk

Linux

GitHub Releases 下载安装包:

# Debian / Ubuntu
sudo dpkg -i mk_*_linux_amd64.deb

# Fedora / RHEL
sudo rpm -i mk_*_linux_amd64.rpm

# Alpine
sudo apk add --allow-untrusted mk_*_linux_amd64.apk

Windows

scoop bucket add axliupore https://github.com/axliupore/scoop-bucket
scoop install mk

从源码编译

go install github.com/axliupore/mk@latest

技术实现

整体架构

mk/
├── main.go                 # 入口
├── cmd/                    # Cobra 命令
│   ├── root.go
│   ├── set.go
│   ├── get.go
│   ├── cp.go
│   ├── ls.go
│   └── rm.go
├── internal/               # 内部包
│   ├── keyring.go          # go-keyring 封装
│   ├── style.go            # lipgloss 终端美化
│   ├── list_darwin.go      # macOS ls 实现
│   ├── list_linux.go       # Linux ls 实现
│   └── list_windows.go     # Windows ls 实现
├── go.mod
└── .goreleaser.yaml        # 跨平台构建配置

技术栈

  • Go 1.26 — 单二进制,零依赖
  • Cobra — CLI 框架
  • go-keyring — 跨平台 Keychain 访问
  • lipgloss — 终端输出美化(charmbracelet 出品)
  • GoReleaser — 跨平台自动构建发布

核心难点:实现 mk ls

go-keyring 库只提供了 SetGetDelete 三个 API,没有 List。所以我需要自己解析各平台的原生命令输出来实现列表功能。

macOS:解析 security dump-keychain

这是最复杂的一个。security dump-keychain 的输出格式非常不一致:

属性标签有三种写法:

"svce"<blob>="mk"           # 带引号
svce<blob>="mk"              # 不带引号
0x00000007 <blob>="mk"       # 十六进制代码

更坑的是,当属性值包含非 ASCII 字符(比如中文别名 )时,值会被十六进制编码:

0x00000008 <blob>=0xE58898E58898...

而不是正常的 UTF-8:

0x00000008 <blob>="刘"

我写了 6 种模式匹配器来覆盖所有组合,加上 encoding/hex 解码十六进制的 blob 值。

Windows:cmdkey /list 的多语言问题

在中文 Windows 上,cmdkey /list 的输出是这样的:

目标: LegacyGeneric:target=mk:openai

而不是英文的:

Target: LegacyGeneric:target=mk:openai

一开始我加了中英文两种匹配,但后来想到日文、韩文怎么办?最终方案是匹配 LegacyGeneric:target=mk: 这个内部标识符——它在任何语言系统下都是英文的。

Linux:secret-tool search

这个反而是最简单的。secret-tool search --all service mk 输出很干净。唯一要注意的是,没有匹配项时返回退出码 1,需要单独处理。

管道兼容性

mk get 的输出是纯文本,不带任何 ANSI 颜色代码。这是刻意的设计,确保 $(mk get alias) 在脚本中直接可用,不需要额外处理。

mk lsmk set 等命令的输出则用 lipgloss 做了美化,有颜色和图标。

跨平台构建

用 GoReleaser 统一构建 macOS、Linux、Windows 三个平台的二进制。一开始踩了个坑:以为 Linux 上 go-keyring 依赖 dbus 需要 CGO_ENABLED=1,结果交叉编译时各种报错。后来发现 godbus/dbus 是纯 Go 实现,CGO_ENABLED=0 就够了。

安全性

  • Key 存储在操作系统原生的加密凭据库中(macOS Keychain / Windows Credential Manager / Linux Secret Service)
  • mk 不会往磁盘写任何文件
  • 不联网,不上传,完全离线
  • mk cp 直接复制到剪贴板,终端里不打印
  • MIT 开源,代码可审计

总结

如果你也经常为管理 API Key 发愁,可以试试 mk。两个字母,从此安心。

  • GitHub: https://github.com/axliupore/mk
  • 开源协议: MIT

觉得有用的话,欢迎 Star ⭐

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐