Metadata-Version: 2.5
Name: mctech-key
Version: 0.2.0
Summary: Portable local secret management with a four-digit PIN
Author: mctech-key contributors
Requires-Python: >=3.10
Requires-Dist: cryptography>=42.0.0
Description-Content-Type: text/markdown

# mctech-key

`mctech-key` 是一个可移植的本地密钥管理项目，Python 包导入名和 CLI 命令保持为 `mckey`。项目通过四位 PIN 使用 API key、secret、连接字符串等字段，避免将明文写进源码或普通配置文件。

它适合开发机、Linux 和 Docker 中的轻量级明文防护，不是密码保险箱。使用者仍应在自己的密码管理器中保存凭据原件。

## 安全模型

- 四位 PIN 通过 Scrypt 派生密钥；
- 字段使用 AES-256-GCM 认证加密；
- 每个 vault 使用独立随机 salt 和 nonce；
- `.mckey` 中不保存 PIN 或字段明文；
- 连续八次 PIN 错误会删除对应 `.key` 文件；
- 文件损坏和状态损坏不会被当作 PIN 错误。

vault 不再绑定设备。同一个 `.mckey` 目录可以复制到 Windows、Linux 或 Docker，并使用原 PIN 解锁。

> [!IMPORTANT]
> 四位 PIN 只有 10,000 种组合。Scrypt 可以增加猜测成本，但拿到 `.key` 文件的人仍可离线穷举。错误次数记录只能限制通过 mckey 正常解锁的尝试，不能阻止攻击者复制、修改或回滚文件。

> [!WARNING]
> 第八次 PIN 错误会删除当前 `.key` 文件，但不会安全擦除磁盘、备份或其他副本。其他副本仍能通过正确 PIN 解密。

## 安装

要求 Python 3.10 或更高版本：

```bash
pip install mctech-key
```

## Python API

首次运行会输入两遍四位 PIN。每遍输入满四位后自动提交，不需要按 Enter；随后隐藏输入各字段值。

```python
import mckey

keys = mckey.start(
    "development",
    fields=["OPENAI_API_KEY", "DATABASE_URL"],
)

api_key = keys.get("OPENAI_API_KEY")
database_url = mckey.get("DATABASE_URL")
```

默认从当前目录向上寻找最近的 `pyproject.toml` 或 `.git`，然后创建：

```text
.mckey/
├── development.key
├── development.state
└── development.lock
```

也可以指定项目根目录或存储目录：

```python
mckey.start("development", fields=["TOKEN"], root="/path/to/project")
mckey.start("development", fields=["TOKEN"], directory="/secure/path")
```

已有 vault 遇到新字段时只补录缺失字段，不会删除其他字段。

### 管理字段

```python
keys.set("OPENAI_API_KEY", "new-value")
keys.delete("OLD_SECRET")
keys.get("OPTIONAL", default=None)
keys.keys()       # 只返回字段名
keys.change_pin()
keys.lock()
mckey.lock()
```

字段名和字段值必须是字符串，字段值可以包含任意 Unicode 文本。

### PIN 文件

Docker 和其他非交互环境应通过只读文件提供 PIN：

```python
keys = mckey.start(
    "production",
    fields=["API_KEY"],
    pin_file="/run/secrets/mckey_pin",
)
```

PIN 文件只能包含四位 ASCII 数字，可以带结尾换行。`pin=` 和 `pin_file=` 不能同时使用。不要把 PIN 文件提交到 Git，也不建议通过普通环境变量传递 PIN。

## CLI

```bash
mckey init development OPENAI_API_KEY DATABASE_URL
mckey list development
mckey set development OPENAI_API_KEY
mckey delete development OLD_SECRET
mckey change-pin development
```

使用 PIN 文件：

```bash
mckey --pin-file /run/secrets/mckey_pin list production
```

`list` 只显示字段名，不输出字段值。

## Docker 方案

仓库的 [`examples/docker`](examples/docker) 提供了完整示例。设计原则是：

- `.mckey` 作为 bind mount 或持久卷挂载，不写入镜像；
- PIN 使用 Docker secret 只读挂载，不写入镜像和 Compose 环境变量；
- 容器中的应用通过 `pin_file=` 解锁；
- 初始化时使用一次性交互容器录入字段。

先在宿主机创建 PIN 文件（内容必须与初始化时输入的 PIN 一致）：

```bash
mkdir -p examples/docker/secrets
printf '1234\n' > examples/docker/secrets/mckey_pin.txt
chmod 600 examples/docker/secrets/mckey_pin.txt
```

构建镜像并初始化 vault：

```bash
docker compose -f examples/docker/compose.yaml build
docker compose -f examples/docker/compose.yaml run --rm app \
  mckey --pin-file /run/secrets/mckey_pin init docker API_KEY
```

初始化命令会隐藏输入 `API_KEY`。之后启动应用：

```bash
docker compose -f examples/docker/compose.yaml up
```

Compose 会把项目根目录的 `.mckey` 挂载到 `/app/.mckey`。需要迁移时复制整个 `.mckey` 目录，包括 `.key` 和 `.state`，并在目标环境提供相同 PIN。

生产环境建议使用 Docker Swarm、Kubernetes Secret 或云平台 secret store 提供 `/run/secrets/mckey_pin`，不要将示例中的本地 PIN 文件打包进镜像。

不要让多个容器副本同时读写同一个 `.mckey` bind mount。多副本生产服务更适合直接使用平台 secret manager；mckey 主要用于单实例或开发环境。

## 使用边界

mckey 防止凭据以明文直接出现在源码、普通配置文件和磁盘中。它不能防御读取解密后进程内存的恶意程序，也不能为四位 PIN 提供密码保险箱级安全性。

请始终将 `.mckey/` 和 PIN 文件加入 `.gitignore`。
