docs: 添加内网通信安全加固开发计划

This commit is contained in:
qing committed 2026-08-03 13:13:52 +08:00
1 parent 9f440ee884
commit 9dbe395484
1 file changed
+152
+152
View File
@@ -0,0 +1,152 @@
# micro_servers 内网通信安全加固 · 开发计划
> 项目:qing/micro_servers(DIY 轻量微服务框架)
> 场景:单机部署(所有服务同一台,仅 waf:443 对外)
> 目标:在"单机 + 绑 127.0.0.1"基础上,补齐服务间认证与加密
> 状态:计划 v1.0
---
## 0. 决策摘要(来自需求讨论)
| 问题 | 结论 |
|------|------|
| 内网是否需要独立鉴权 | 网络隔离为主(绑127.0.0.1),高危面另加服务间认证 |
| 能否用用户密钥做认证 | 对外链路可用;服务间互调改用独立 service key |
| 能否用 RSA+AES 通信加密 | 能,但单机场景 RS‌A 公钥分发太麻烦,不划算 |
| 最终方案 | **core 生成进程组密钥 → 环境变量注入 → AES-GCM 服务间加密** |
| 分发方式 | 由 core 作为密钥生成/分发中心,免手动拷贝 |
---
## 1. 总体目标
为 micro_servers 的内网服务间通信建立**三层防线**:
1. **隔离层**(地基):所有内部服务绑定 `127.0.0.1`,云安全组仅放行 443
2. **认证层**:服务间调用携带共享密钥(进程组密钥)校验身份
3. **加密层**:敏感通信用 AES-256-GCM 加解密 + 完整性 + 防重放
---
## 2. 架构变更(目标态)
```
外网攻击者 ──只能到达──► 只开放 waf:443
│
┌────────────────────────┴───────────┐
│ core (:5200, 本机) │
│ [密钥生成器] 生成进程组密钥 │
│ 通过环境变量 MICROSERV_KEY 注入 │
└─────┬──────────────────────────────┘
│ 拉起 + 注入密钥
┌────────┬────────┬───┴───┬────────┬────────┬─────────┐
▼ ▼ ▼ ▼ ▼ ▼
waf gateway static dnfs db ai_review ...
:443 :8443 :9200 :8006 :8005 :8007
全部绑定 127.0.0.1(仅本机可达)
服务间调用:AES-GCM 加密 + 进程组密钥认证
```
---
## 3. 工作分解(3 阶段)
### 阶段一:隔离加固(P0,先行)
对齐"绑 127.0.0.1 + 只放行 443"的基线。
- [ ] 1.1 检查并修改所有服务监听地址为 `127.0.0.1`(禁止 `0.0.0.0`)
- waf 例外:443 对外;但可考虑 waf 内部转发目标为 127.0.0.1:8443
- [ ] 1.2 云安全组 / ufw:仅放行 TCP 443,其余端口公网关闭
- 规则示例:`ufw default deny incoming` + `ufw allow 443/tcp`
- [ ] 1.3 验证:从外网 curl 各内部端口(8443/9200/8005…)应全部超时/拒绝
- [ ] 1.4 验证:本机 `curl http://127.0.0.1:8443` 正常(确认仅本机可达)
**完成标准**:对外仅 443 一个口,内部端口公网不可达。
---
### 阶段二:core 密钥生成 + 环境变量注入(P1 核心)
实现"core 作为进程组密钥中心"。
- [ ] 2.1 core 启动时生成随机密钥
- 实现:`openssl rand -hex 32`(或 C++ 读取 /dev/urandom 256 位)
- 输出:32 字节(256 位)十六进制串作为进程组密钥
- [ ] 2.2 core 拉起子进程时注入环境变量
- 用 `execve` 的 envp 直接传 `MICROSERV_KEY=<key>`(勿用全局 export,减少暴露)
- 涉及子进程:ai_review/db/dnfs/smtp/static/waf/gateway/captcha/aibox
- [ ] 2.3 子进程侧读取密钥
- 各服务启动时读 `os.environ["MICROSERV_KEY"]`
- **fail-fast**:读不到立即报错退出,禁止静默降级为明文
- [ ] 2.4 core 接口安全复核
- core(:5200) 必须:只绑 127.0.0.1 + 管理接口带鉴权
- 说明:core 现为"主钥匙",是最高价值目标,重点保护
**完成标准**:所有由 core 拉起的服务均带 `MICROSERV_KEY`,缺失时报错退出。
---
### 阶段三:服务间 AES-GCM 加密通信(P1)
用预共享的进程组密钥加密服务间流量。
- [ ] 3.1 编写统一加解密库 `microcrypt`
- 目标语言:Python(pymsg/Flask 服务)+ C++(gateway)各一份,接口对齐
- 算法:AES-256-GCM
- 加密:随机 12 字节 nonce + 明文 → (nonce, ciphertext, tag)
- 解密:nonce + tag 校验,失败即拒绝
- 防重放:帧内携带时间戳/序号,接收方校验新鲜度
- [ ] 3.2 接入 pymsg 帧(db/captcha/smtp/confs 等基于 pymsg 的服务)
- 在长度前缀帧的 payload 外包一层 GCM 加密
- [ ] 3.3 接入 HTTP 服务(static/dnfs/ai_review/gateway 的互相调用)
- 敏感请求体加密,或至少加认证 header + 加密关键字段
- [ ] 3.4 密钥轮换
- core 重启即换新密钥(进程生命周期天然轮换)
- 配置项:可设定期轮换(可选,P2)
- [ ] 3.5 回归测试
- 正常链路:注册/登录/笔记 CRUD/日志上报 全流程可跑通
- 故障测试:错误密钥/乱序/篡改 → 服务应拒绝而非崩溃
**完成标准**:服务间敏感通信已 GCM 加密,篡改/伪造被拒。
---
## 4. 风险与对策
| 风险 | 对策 |
|------|------|
| 环境变量对同机进程可见(/proc/<pid>/environ) | 接受局限:威胁模型以"防外网"为主;不把 key 当终极秘密;仅绑本机+少暴露 |
| core 被攻破 → 主钥匙泄露 | 将 core 作为最高价值目标:绑本机、接口精简、强鉴权、最小权限 |
| 调试时手动跑单服务导致 key 缺失/不一致 | fail-fast 报错 + 统一由 core 拉起,文档明确"禁止手动裸跑" |
| AES-GCM 误用(nonce 重用等) | 库内统一封装,nonce 每次随机生成;禁止外部传入 |
| 明文降级残留 | fail-fast + 代码审查禁止"No key → 明文"分支 |
---
## 5. 里程碑
| 里程碑 | 内容 | 预估 |
|--------|------|------|
| M1 | 阶段一:隔离加固完成,对外仅 443 | 0.5 天 |
| M2 | 阶段二:core 密钥注入 + 子进程读取 | 1 天 |
| M3 | 阶段三:AES-GCM 库 + 接入全部服务 | 2-3 天 |
| M4 | 回归测试 + 安全验证(篡改/伪造/重放) | 1 天 |
---
## 6. 验证清单(上线前)
- [ ] 外网端口扫描:仅 443 开放
- [ ] 内部端口仅 127.0.0.1 可达
- [ ] 所有 core 拉起服务均带 MICROSERV_KEY
- [ ] 缺失密钥 → 服务 fail-fast 报错(无明文降级)
- [ ] 错误/篡改密文 → 服务拒绝请求
- [ ] 完整业务链路回归通过
- [ ] MICROSERV_KEY 未提交进 git(.env/.gitignore)
---
## 7. 备注 / 后续可选项(P2)
- 密钥定期轮换定时器
- mTLS 升级路径(若未来改多机部署)
- 审计日志:记录服务间认证失败/解密失败事件