jitpass/jit

GitHub: jitpass/jit

一款 macOS 命令行工具,用于发现并加密本地散落的明文密钥,在不破坏现有工具链的前提下将其转换为 Touch ID 保护下的即时凭据。

Stars: 2 | Forks: 0

# jitpass:`jit` CLI **为你的开发机器提供即时凭据。** ## 简介 **问题所在。** 一台正在使用的开发机器会积累大量明文 secrets:`.env` 文件,shell 配置中的 `export STRIPE_KEY=...` 语句,`~/.aws/credentials`, kubeconfig client keys,Terraform Cloud token,`.npmrc` auth token,MCP 服务器配置。每一个 secret 都可以被以你的用户身份运行的任何程序读取, 会被扫入备份和文件索引中,并在你真正需要它的那一刻过去很久后, 依然留在磁盘上。 **jit 做了什么。** `jit` 会找到这些 secrets(通过 `jit audit`,严格 只读),将它们移动到本地加密的 vault 中,并重写每个文件, 这样在没有 secret 存留在磁盘上的情况下,一切依然能正常工作: ``` jit audit # what's exposed on this machine? (strictly read-only) jit migrate local # fix this project; tools keep working jit run -- npm run dev # or inject secrets straight into a process, no file at all ``` **它是如何解决的。** Secrets 会在使用时(进程启动、凭据握手、 通过显示读取文件)显现,而在其余时间里不会以明文存在于任何地方。 Vault 将每个 secret 存储为单独加密的文件,受 Touch ID/密码验证限制, 并通过后台 agent 解锁,因此你每个会话只需认证一次, 而不是每条命令一次。每个被重写的文件在被修改前都会进行备份 (加密后存入 vault),并且 `jit migrate undo` 可以将其 逐字节地恢复。 **状态:早期开发,仅限 macOS。** 如果你从源码构建,下面的一切都可以正常工作; 代码签名/公证和 Homebrew tap 是目前阻碍其发布打包版本的原因。 ### 涵盖范围 每个凭据都会通过该工具自身的原生机制返回给其消费者, 因此一切都能继续正常工作: | Secret 存放位置 | 示例 | `jit migrate` 后如何保持工作 | | --- | --- | --- | | `.env` 文件 | 项目 `.env` 中的 `DATABASE_URL=...` | 实时挂载的文件:默认为诱饵值,在短暂的显示窗口期内提供真实值 | | Shell 配置导出 | `~/.zshrc` 中的 `export STRIPE_KEY=...` | 配置中的一行 `eval "$(jit export ...)"` | | MCP 服务器配置 | 项目 `mcp.json`,Claude Desktop 配置 | 服务器命令包装在 `jit run` 中 | | AWS 凭据 | `~/.aws/credentials` | `~/.aws/config` 中的 `credential_process`:CLI 和 SDK 按需获取,完全不需要文件 | | kubeconfig | `~/.kube/config` 中的 client keys/tokens | 一个 kubectl `exec` credential 插件 | | Terraform Cloud token | `~/.terraform.d/credentials.tfrc.json` | 一个 `credentials_helper`;`terraform login`/`logout` 保持正常工作 | | `.npmrc` auth token | 项目或全局的 `.npmrc` | 从模板实时挂载;非 secret 设置保持不变 | GCP application-default credentials 尚未涵盖。 ### 每个提示都会告诉你它为什么出现 一个你无法解释的 Touch ID 提示就是你出于习惯会批准的提示 —— 这就 失去了询问的意义。因此,当 jit 询问时,它会指明它是在询问*什么*, 以及是什么触发了它: 那是你的编辑器启动的一个 MCP 服务器,想要你 `mcp-jamf` 配置文件中的 secrets。根据事实进行批准或取消,而不是盲目猜测。 相同的来源记录在之后也会保留,因为“为什么会发生这种情况?”通常 是在提示消失*之后*才被问到的。`jit agent status` 显示谁解锁了当前 会话以及什么导致了它的解锁/锁定;`jit agent history` 列出了 agent 见过的 每一次解锁和锁定;并且两者都被写入 agent 的日志中,该日志 在重启后依然保留。 ``` Session (most recent first): • locked 48m ago (11:48:04) — 15m0s idle timeout • unlocked 1h ago (11:33:04) — launched by claude ~/go/bin/jit run --profile mcp-jamf -- uv --directory ~/Documents/… ``` 调用者是谁的信息来自于内核(其在 socket 上的 pid,然后是 其命令行和父进程链),从来不是来自调用者对自身的任何声明 —— 因此它无法被一个填写了某个字段的进程伪造。它仅用于 *解释*和*审计*,从不用于决定:请参阅下方的安全说明。 ## 安装 jit 仅限 macOS,并且需要 Touch ID 或设备密码。有两种安装方式 —— 目前还没有 Homebrew tap(计划在首次签名版本发布时提供)。 ### 选项 A:预构建二进制文件(Apple Silicon,不需要 Go) ``` curl -sLO https://github.com/jitpass/jit/releases/latest/download/jitpass_darwin_arm64.tar.gz tar -xzf jitpass_darwin_arm64.tar.gz jit sudo mv jit /usr/local/bin/ ``` 预构建的二进制文件仅限 Apple Silicon —— 我们没有 Intel 硬件来 进行测试,而且我们不会发布我们无法测试的东西。在 Intel Mac 上,请使用 选项 B(它从源码构建,因此可以在任何 Mac 上运行)。 要验证下载,[发布页面](https://github.com/jitpass/jit/releases/latest)上的 `checksums.txt` 包含 SHA-256 校验和:`shasum -a 256 --check checksums.txt --ignore-missing`。 请使用 `curl`,而不是浏览器:浏览器下载会获得 macOS 的隔离 属性,并且 Gatekeeper 会阻止没有经过 Developer-ID 签名 的隔离二进制文件(目前的发布版本还没有签名 —— 与 Homebrew tap 的签名工作相同)。 如果你已经通过这种方式下载了,请使用 `xattr -d com.apple.quarantine jit` 取消隔离。 ### 选项 B:使用 Go 从源码构建 **1. 安装 Go**(1.26+),如果你还没有安装的话: ``` brew install go ``` **2. 安装 jit:** ``` go install github.com/jitpass/jit/cmd/jit@latest ``` 本地编译的二进制文件也不会被隔离,所以在这里不需要 点击通过 Gatekeeper 提示。 ### Shell 自动补全(适用于两种选项) `jit ` 会补全子命令、flags 及其描述: ``` echo 'source <(jit completion zsh)' >> ~/.zshrc && exec zsh ``` **如果打印出 `command not found: jit` 或 `command not found: compdef`**(在全新的 Homebrew 安装的 Go 和普通的 zsh 设置中使用选项 B 时很常见): `go install` 将二进制文件放在 `~/go/bin/jit`,默认情况下它不在你的 PATH 上, 并且普通的 zsh 从不初始化其补全系统。你的 `~/.zshrc` 需要按此顺序添加以下几行: ``` # 使 jit 可被找到(go install 会将其放在 ~/go/bin) export PATH="$HOME/go/bin:$PATH" # 初始化 zsh 的补全系统(如果 oh-my-zsh 已经完成了此操作,则跳过) autoload -Uz compinit && compinit # 现在可以正常工作了:jit 已在 PATH 上且 compdef 存在 source <(jit completion zsh) ``` 然后再次运行 `exec zsh`。bash 和 fish 的说明位于 **[docs/USAGE.md](./docs/USAGE.md#shell-completion)**。 **想要贡献代码而不仅仅是使用它?** 请从克隆代码开始构建;结果 是一样的: ``` git clone https://github.com/jitpass/jit.git cd jit go install ./cmd/jit ``` ### 升级 新版本会在 [Releases 页面](https://github.com/jitpass/jit/releases)公布。升级是两个 步骤,而不是一个。第 1 步是重新安装二进制文件 —— 对于预构建的安装, 重新运行相同的选项 A 的三条命令(`releases/latest/download/...` 总是提供最新版本);从源码安装: ``` go install github.com/jitpass/jit/cmd/jit@v0.4.0 # 1. reinstall the binary (pin the new tag) jit agent install # 2. restart the background agent on it ``` 在刚发布一个版本后,最好固定 tag 而不是 `@latest`:Go module proxy 会缓存 `@latest`,因此它可能会在一段时间内悄悄地提供给你之前的版本。 对于这两种安装方法,第 2 步都是一样的。 人们通常会跳过第二个步骤。如果你安装了后台 agent, launchd 会在你重新安装的整个过程中保持旧进程(以及旧的 二进制文件)继续运行;每个与其通信的命令依然会获得上个版本的行为, 这让你感觉“我升级了,但没有任何改变”。`jit status` 和 `jit agent status` 会警告“不同的构建版本”,直到你重新启动它。如果你 从未运行过 `jit agent install`,那么仅第 1 步就是完整的升级。 ## 快速开始 ``` jit audit # 1. see the problem (read-only, run it anywhere) jit vault init # 2. create the vault (master key in your login keychain) jit agent install # 3. background helper: unlock once, everything shares it jit migrate local --dry-run # 4. preview the fix for the project you're in jit migrate local # 5. apply it: plan, [y/N], one Touch ID prompt jit status # 6. vault / agent / mounts / backup health, one screen ``` 每个修改命令都会首先打印其计划并进行询问;每个被重写的文件在 被修改前都会进行备份(加密后存入 vault),并且 `jit migrate undo` 可以将其中任何一个逐字节恢复。对于实时挂载的 文件,显示步骤会自动连接到你的 `.envrc` 或 npm `dev`/`start` 脚本中,因此通常情况下不需要手动操作。 ## 练习场 不想第一天就把一个 secrets 工具指向你真实的机器?可以理解。 **[jitpass-playground](https://github.com/jitpass/jitpass-playground)** 是一个 真实的模拟应用,预置了合成的 secrets 并提供长达 10 分钟的引导之旅: audit、migrate、观察诱饵值变为真实值、撤销所有操作。 ## 了解更多 日常操作指南(设置、migrate、在修复后的生活)位于 **[docs/USAGE.md](./docs/USAGE.md)**。除此之外: - **[docs/COMMANDS.md](./docs/COMMANDS.md)**:完整的命令参考,每一个命令和 flag - **[TECH_STACK.md](./TECH_STACK.md)**:实现选择及原因 - **[docs/example-audit-report.md](./docs/example-audit-report.md)**:`jit audit` 输出的样子(合成模型) - **[security/](./security/)**:我们审查 jit 自身代码的漏洞并公布结果(范围、发现、修复以及客观的局限性) - **[CONTRIBUTING.md](./CONTRIBUTING.md)**:构建/测试设置和约定;通过 DCO 签署(`git commit -s`),无 CLA ### 安全模型是什么(以及不是什么) 我们宁愿你了解这些边界,也不愿你以后才发现它们: - **`jit audit` 在任何 flag 下都是只读的,毫无例外。** 它也绝不 打印 secret 的值,仅显示打码预览。 - Vault 的本地身份验证门目前**由 jit 自身的代码通过真正的 OS Touch ID/密码提示来执行,而不是由 OS 强制执行的 Keychain ACL/Secure Enclave 绑定来执行**(因为这受限于签名身份)。它 可以防止抓取文件的恶意软件、备份/索引泄露以及随意的 数据窃取。它不能阻止已经以你的用户身份执行代码的攻击者, 我们也不会欺骗你。 - 注入到进程中的 secret 在该进程内部是明文的;jit 缩小了暴露窗口,但它无法对你的依赖项进行 sandbox 处理。 - **调用者身份识别是为了解释,从来不是为了做决定。** 提示中出现 的名字(“launched by claude”)以及在 `jit agent status` 中的信息来自于 内核,并且不能被填写了某个字段的调用者伪造 —— 但是一个进程可以 在连接后 `exec` 其他东西,而且 pid 会被重用,所以永远不会仅仅 因为调用者看起来是谁而*授予*任何权限。对 agent socket 的唯一访问 检查是对端是否以相同的 OS 用户身份运行。对于被指出读取了 实时挂载文件的进程也是如此:这是审计信号,而不是一道门。 - 将 secret 放回磁盘的命令(`jit unmount`、 `jit migrate undo`、`jit vault export`)按照设计总是会再次提示。 - [security/](./security/) 中发布的每份审查 都以其涵盖的构建版本的已知且已接受的局限性作为结尾。 ## 许可证 Apache License 2.0。请参阅 [LICENSE](./LICENSE)。
标签:EVTX分析, SOC Prime, StruQ, 凭据保护, 开发工具, 日志审计, 本地加密