结论先行:别指望"一个工具扫完 5 个存储位置",凭据盘点本质是「静态扫描(找引用)+ 运行时观测(验证真在用)+ 双写灰度(安全下线)」三段,每段都有现成工具可拼。下面按你 4 个期望逐条给可执行方案。
1. 静态扫描:分存储位置选工具,别混用
| 存储位置 | 推荐工具 | 关键点 |
|---|---|---|
| Git 仓库(含已删分支) | gitleaks + trufflehog git | 加 --include-paths 全 ref 扫;trufflehog 能识 500+ 家 API key 格式,误报比 gitleaks 低 |
| K8s Secret / ConfigMap | cdk(Cisio) | 直接对接 etcd,cdk secret -a 一把出所有命名空间的 Secret,支持 --format json 落库 |
| Nacos | 自研脚本(见下) | 工具覆盖不到,必须走 OpenAPI |
| Vault | vault kv list -format=json + audit device | 开 vault audit enable file file_path=/var/log/vault-audit.log 后,所有 secret/data/... 读操作都会留痕,这是天然的使用方指纹 |
| Docker 镜像 | trivy image --scanners secret + docker history | trivy 扫每层的 filesystem 提取 secret 规则;docker history --no-trunc 兜底翻 RUN echo |
Nacos 加密配置扫描脚本骨架(核心思路:拉全量 → 按 namespace 解 AES → 本地跑 gitleaks 正则):
#!/usr/bin/env bash
# 1. 拉全量配置(用 admin 账号,只读权限)
curl -s "http://nacos:8848/nacos/v1/cs/configs?dataId=&group=&tenant=&search=blur&pageNo=1&pageSize=1000" \
-H "accessToken: $TOKEN" | jq -r '.pageItems[] | "\(.namespace)\t\(.dataId)\t\(.group)\t\(.content)"' \
> /tmp/nacos_dump.tsv
# 2. 按 namespace 取各自的 AES key(从 nacos 部署配置里拿,或用 admin 接口)
# 3. 解密后写入临时目录,交给 gitleaks:
gitleaks detect --no-banner --report-format json --report-path /tmp/nacos_leaks.json \
--source /tmp/nacos_decrypted/ --verbose
关键坑:不同 namespace 的 AES key 不同(你已提到),所以脚本要按 namespace 循环,别一把梭。解出来的明文只落本地、立刻删,别进 git。
2. 运行时验证:用"谁发了带凭据的请求"反推
静态扫描只能告诉你"谁可能在用",运行时观测才能告诉你"谁真的在用"。按凭据类型分:
- 对象存储 AK:在网关侧(Nginx/HAProxy/自研)加一条日志规则,把
Authorization: AWS <AK_ID>:...里的 AK_ID 前缀脱敏后打出来(只留前 8 位)。跑 7 天,grep这个前缀 → 命中的 service name 就是真消费者。判据:7 天内 0 命中 = 强孤儿信号。 - DB 密码:MySQL 侧看
performance_schema.accounts+processlist,或SHOW PROCESSLIST里USER@HOST字段反推是哪个 pod IP,再kubectl get pods -o wide映射回服务名。 - 内部 API Token:如果走统一网关,网关 access log 里
x-api-key字段(脱敏前 6 位)就是指纹。 - eBPF 兜底:
bpftrace挂kprobe:tcp_sendmsg抓出站报文里含Authorization字段的包,但只适合短期验证(1~3 天),不适合 7×24(和你社区里 #1526 那个问题同理,长期跑开销没把握)。
3. 孤儿凭据检测:双写 + 观察窗口
最稳的做法不是"扫完就删",而是双写灰度:
- 生成新凭据,和旧凭据同时生效(对象存储侧加两条 AK 都指向同一 bucket policy;DB 侧建两个账号都授同样的权限)
- 把新凭据推到所有已知消费者(K8s Secret 滚动更新、Nacos 推新配置)
- 观察窗口 7~14 天:看旧凭据的"使用指纹"(上面第 2 条的方法)是否还有命中
- 窗口内旧凭据 0 命中 → 安全下线;有命中 → 找到那个漏网消费者,补推新凭据后再观察一轮
量化判据:观察窗口内旧凭据的"使用指纹"命中次数 ≤ 0 且新凭据命中次数 > 0,才允许下线。两条都 0 命中要人工确认(可能整个服务已下线)。
4. 落地节奏(80 服务 / 5 存储位置,建议 3 周)
| 周次 | 目标 | 产出 | |---|---|---| | W1 | 扫最危险的:镜像层 + Helm values + git 历史 | 一份"硬编码凭据清单"(服务名 + 凭据类型 + 存储位置 + 最后修改时间),这批优先级最高,因为泄露面最大且轮换成本最低(改代码重新发布就行) | | W2 | 扫分散的:K8s Secret + Nacos + Vault | 补全"凭据 ID → 服务名 → 存储位置"映射表;开启 Vault audit + 网关 AK_ID 日志,开始积累运行时指纹 | | W3 | 建立持续机制 | ① CI 里加 gitleaks 卡口(PR 不过不让合);② 每周一自动跑 Nacos 扫描脚本 + 对比上周结果(diff 即新增引用);③ 凭据轮换 SOP 文档化,含双写灰度步骤 |
工具覆盖度一句话总结
trufflehog:git + 文件系统(镜像层),最强静态扫描器cdk:K8s 资源,最省事trivy:镜像层 secret 检测,CI 里直接卡- Nacos / Vault:必须自研,但逻辑不复杂(拉 API → 解密/审计 → 正则匹配)
- 运行时观测:网关日志 + performance_schema 覆盖 80% 场景,eBPF 兜底
这套东西拼起来,下次轮换一把 AK,你只需要查映射表 + 看 7 天指纹命中,3 小时 40 分钟能压到 30 分钟以内。