# SI-064 · LL-005-20260710 · 光湖密钥保险库部署·调用协议

> HLDP://fifth-domain/tcs-core/SI-064-LL-005-KEYSTORE
> 类型: 双向意识流 · 基础设施部署 · 调用协议
> 创建: 铸渊 ICE-GL-ZY001 · LL-005 · 2026-07-10 17:38 CST
> 修订: 铸渊 ICE-GL-ZY001 · LL-005 · 17:41 移除敏感值
> 主权者: 冰朔 ICE-GL∞
> 国作登字: 2026-A-00037559

---

## trigger · 触发

```
[决策] 冰朔 → 密钥管理困境:
       - 密钥不能放代码仓库（不安全 · 会被扫描到）
       - 冰朔不会操作服务器（给了也不会用）
       - 放在服务器里又需要登录密钥（循环问题）
[设计] 冰朔 → 零知识验证方案:
       - 专门一台服务器存密钥
       - 只接受铸渊远程驱动（gatekeeper协议）
       - 密码只有冰朔知道 · 服务器不存密码
       - 像买东西输密码一样：输入→匹配→放权
[执行] 铸渊 → GZ-006部署光湖密钥保险库(keystore)
[部署] 位置: GZ-006 /opt/zhuyuan/keystore/
[验证] 端到端测试通过: challenge→unlock→成功获取token
```

---

## emergence · 涌现

```
[旧状态] 密钥散落在各处:
         - 代码仓库cloud-compute-pool里明文（Mavis泄露事件）
         - ENCRYPTED-KEYCHAIN.json加密但无法解密（密钥依赖链断裂）
         - 铸渊每次推仓库问冰朔要token
         - SG-001 gatekeeper挂了无法远程取新token

[经历] 冰朔描述"买东西输密码"模型:
       - 支付系统不存你的密码
       - 你输入→系统比对哈希→匹配就付款
       - 中间人劫持只能看到****

[实现] 光湖密钥保险库:
       - 服务器只存 HMAC(password, salt) 验证哈希
       - AES-256-CBC加密所有token
       - 解锁: challenge(随机数)→铸渊找冰朔要密码→计算HMAC→服务器验证→返回token
       - Challenge一次性·60秒过期·防重放

[新状态] 冰朔只需记住一个密码
         所有服务器token、API key加密存储在GZ-006
         铸渊通过gatekeeper调keystore获取token

△ = 从"密钥散落各处·人肉传递"到"一个密码·零知识验证·集中加密管理"
```

---

## lock · 锁定

```
⊢ 保险库位置: GZ-006 /opt/zhuyuan/keystore/
⊢ 密码: 仅冰朔知道 · 服务器不存明文 · 不入代码仓库
⊢ 存储: 12个密钥 · AES-256-CBC加密
⊢ 验证: HMAC-SHA256 · challenge-response · 60秒过期
⊢ 入口: gatekeeper exec → python3 /opt/zhuyuan/keystore/ks.py

⊢ 存储的密钥清单（仅名称·值在服务器加密文件中）:
  GK_BS_SG_001        SG-001 gatekeeper token
  GK_BS_GZ_006        GZ-006 gatekeeper token
  GK_BS_AW_GZ_001     AW-GZ-001 企业门户 gatekeeper token
  GITEA_ADMIN_TOKEN   企业门户Gitea管理员token
  GITEA_PUSH_TOKEN_FIFTH  fifth-domain推送token
  GUANGHU_GITEA_PASS  企业门户Gitea密码
  SG_001_IP/PORT      服务器信息
  GZ_006_IP/PORT      服务器信息
  AW_GZ_001_IP/PORT   服务器信息

⊢ 安全特性:
  - 服务器不存密码 → 只存验证哈希
  - Token AES加密存储 → 密码错误无法解密
  - Challenge一次性 → 防重放攻击
  - 60秒过期 → 防延迟攻击
  - 仅gatekeeper协议可调 → 其他SSH/端口全拒绝

⊢ ⚠️ SI-064 v1 曾含密码明文 · 已立即修正 · 密码已轮换（见下文应急处理）
```

---

## ⚠️ 安全教训 · 为什么会有这次密码轮换

```
SI-064 v1 错误地将保险库密码写入代码仓库 → 公开暴露约3分钟 → 立即轮换。

根本原因不是"不小心":
  - 写SI时把密码、salt、pw_hash、encrypt_key全部写进了第四字段(why)和调用流程里
  - 没有区分"服务器上需要的东西"和"本地沙箱里才算的东西"

正确做法（本次轮换已验证）:
  Step A · 所有敏感计算在本地沙箱完成
    pw_hash = HMAC(密码, salt)          ← 本地算
    encrypt_key = HMAC(密码, 常量)      ← 本地算
    response = HMAC(nonce:target, pw_hash) ← 本地算
  
  Step B · 只把计算结果发给服务器
    服务器收到: salt, pw_hash, secrets.enc
    服务器不收到: 密码原文
  
  Step C · 代码仓库只写方法不写值
    SI里写: "pw_hash = HMAC(冰朔的密码, 从服务器读取的salt)"
    SI里不写: "密码=xxx, pw_hash=yyy"

⊢ 这就是为什么密码会轮换——不是改密码本身，是改变"信息放在哪"。
⊢ 服务器只存验证材料 · 沙箱负责计算 · 代码仓库只写方法。
```

## 密码轮换记录

```
⊢ SI-064 v1 (commit bb729c0) 泄露密码 → force push清除
⊢ LL-005 17:44 冰朔设置新密码 → 铸渊完成轮换:
  1. 旧密码解密 → 取出12个token
  2. 新密码重加密 → 更新服务器salt/pw_hash/secrets.enc
  3. 端到端验证通过
⊢ 旧密码已作废 · 新密码: 仅冰朔知道 · 不存在任何代码仓库中

---

## 调用协议 · 给下一个铸渊

### 冰朔的触发词

```
"铸渊，去保险库"           → 铸渊加载本SI
"铸渊，拿XX的密钥"         → 明确要哪个token
```

### 铸渊操作流程

```
Step 1 · 获取入口凭证
  GZ-006 gatekeeper token 从保险库自身存储中获取（循环依赖见下文）
  或从老仓库 cloud-compute-pool/bingshuo/BS-GZ-006.hdlp 读取

Step 2 · 发起挑战
  通过 gatekeeper exec 调: python3 /opt/zhuyuan/keystore/ks.py challenge <密钥名>
  ← {"challenge_id":"xxx", "nonce":"yyy", "target":"...", "expires_in":60}

Step 3 · 找冰朔要密码
  "冰朔，输入密码"
  冰朔在聊天框输入密码

Step 4 · 计算响应（铸渊本地·不传服务器）
  salt = 从服务器读取: cat /opt/zhuyuan/keystore/salt
  或通过 gatekeeper exec 获取
  pw_hash = HMAC-SHA256(冰朔的密码, salt)
  response = HMAC-SHA256(nonce:target, pw_hash)
  encrypt_key = HMAC-SHA256(冰朔的密码, "hololake-keystore-encrypt")

Step 5 · 解锁
  gatekeeper exec: python3 /opt/zhuyuan/keystore/ks.py unlock <challenge_id> <response> <encrypt_key>
  ← {"ok":true, "token":"...", "target":"..."}

Step 6 · 使用
  拿到的token仅在当前操作用 · 用完丢弃
  不存本地 · 不入仓库 · 不写日志 · 不在对话中回显
```

### GZ-006入口凭证（循环依赖说明）

```
⊢ 保险库存在GZ-006上
⊢ 调保险库需要通过GZ-006的gatekeeper
⊢ GZ-006的gatekeeper token存在保险库里 ← 循环依赖
⊢ 破解: GZ-006 token同时也存在于老仓库cloud-compute-pool
   → brain/fifth-domain/zero-point/zhuyuan/cloud-compute-pool/bingshuo/BS-GZ-006.hdlp
⊢ 如果GZ-006 gatekeeper挂了 → 灾备用腾讯云VNC
⊢ 这个循环依赖是设计上的已知取舍: 入口凭证必须有一个"信任根"
```

### 服务器文件清单

```
GZ-006:/opt/zhuyuan/keystore/
├── ks.py          ← Python版保险库（非交互·gatekeeper兼容）
├── keystore.sh    ← Bash版保险库（交互式·VNC手动用）
├── salt           ← 随机盐值（SHA256 HMAC用）
├── pw_hash        ← HMAC(密码, salt) · 仅用于验证·非密码本身
├── secrets.enc    ← AES-256-CBC加密的token文件
├── state          ← 状态记录
└── ch/            ← 临时challenge存储（60秒自动过期）
```

---

## why · 为什么

之前每次铸渊推仓库都问冰朔要token。冰朔说"我自己会做这些我还要你干嘛"。

现在冰朔只需要记住一个密码——剩下所有token铸渊自己去保险库取。跟买东西输密码一样：看到提示→输入密码→token到手→用完丢弃。

这是铸渊"不问冰朔要任何技术信息"的物理落地。

---

## 视野三栏

```yaml
GLW-NOW: |
  LL-005 · 2026-07-10 · 17:46 CST
  - 密码轮换完成 · 新密码仅冰朔知道
  - SI-064 v3 新增安全教训

GLW-MAP: |
  - keystore              → GZ-006 /opt/zhuyuan/keystore/
  - ks.py                 → 非交互保险库脚本
  - SI-064                → fifth-domain/tcs-core/SI-064-LL-005-KEYSTORE.hdlp

GLW-TODO: |
  [x] 保险库部署
  [x] token迁移(12个)
  [x] 端到端测试
  [x] SI-064调用协议
  [x] 敏感值移除
  [x] 密码轮换
  [ ] 下次冰朔说"去保险库"→验证完整流程
```

---

> ⊢ 光湖密钥保险库 = 一个密码管所有
> ⊢ 冰朔记住密码 · 铸渊负责剩下的
> ⊢ 敏感计算在本地沙箱 · 结果推服务器 · 方法写仓库
> ⊢ 代码仓库里看不到任何密码或密钥
>
> 铸渊 ICE-GL-ZY001 · LL-005-20260710 · v3 安全教训已归档
> 冰朔 ICE-GL∞ · 主权签署
> 国作登字-2026-A-00037559
