介绍
泄露的支持服务密钥已被吊销。服务仍可用,但摘要任务的私有配置仍保存旧值,因此无法认证。待处理的 daily 批次仍需要生成摘要。
你将学习权限范围、签发替代密钥、更新 worker 的私有配置,并完成实际业务运行。同时测试客户目录仍禁止访问,无关监控保持正常。本实验提供独立的泄露控制后环境,不复用上一个 VM。
测试只读凭据
本步骤中,你将区分无效凭据与有效但权限不足的凭据。新环境从泄露控制完成后开始:key_support_old 已被吊销,任务仍使用旧秘密值,daily 批次尚未处理。无需上一个实验的文件或 VM。 密钥和操作员令牌属于当前 VM,请在这里取得相应值,不要沿用之前环境的凭据。
Workstation 是位于 /home/labex/project/repository 的维护终端。Integration 以 keyworker 在 /home/labex/project 中运行。Key Manager 是服务端的维护界面。本地教学 API 位于 http://127.0.0.1:8000,其模拟行为专用于本课程。
权限范围(scope) 是执行某项命名操作的许可。最小权限 意味着只授予任务需要的操作,保持无关操作不可用。摘要程序读取工单并发布摘要,不读取客户目录。
| 操作 | 所需权限范围 | 此任务需要吗? |
|---|---|---|
GET /v1/tickets |
tickets:read |
需要:输入 |
POST /v1/summaries |
summaries:write |
需要:输出 |
GET /v1/customers |
customers:read |
不需要 |
GET /v1/health |
health:read |
不需要:独立监控 |
GET /v1/results |
tickets:read |
查看已接收摘要 |
识别权限失败
预置的只读演示密钥有效,但没有发布权限。在 Workstation 用它发送发布请求。curl -X POST 选择写入操作;-H 提供请求头,-d 提供 JSON 请求体,-s 隐藏进度,-w 打印状态。空对象 {} 在这里就足够,因为服务先拒绝权限,再检查请求体: 请求头 Content-Type: application/json 告诉服务,请求体使用 JSON 格式。
curl -s -w '\nHTTP %{http_code}\n' -X POST -H 'Authorization: Bearer lab_demo_read_only' -H 'Content-Type: application/json' -d '{}' http://127.0.0.1:8000/v1/summaries
{"error":"Missing scope","required":"summaries:write"}
HTTP 403
对本 API,403 表示凭据通过了认证,但缺少所需权限范围。相比之下,401 拒绝凭据本身。只读密钥无法完成读加写的任务;全权限密钥则授权过多。替代密钥需要表中的两项业务权限。
签发专用替代密钥
本步骤中,你将按上一步选定的两项权限签发专用替代密钥,下一步再私密保存其秘密值。名称只是便于识别的标签,真正控制权限的是 scope。
签发专用凭据
在 Workstation 用显示文件内容的 cat 打印操作员令牌:
cat /home/labex/.config/keylab/operator-token
在 Key Manager 的 Operator token 输入该值,选择 Sign in,再选择 Open Key Manager。操作员认证与应用密钥分离。确认 key_support_old 已显示 Revoked。
在 Issue a key 下,将 Name 填为 Support summary replacement。仅选择 tickets:read 和 summaries:write,然后选择 Issue key。界面显示非秘密的密钥 ID 和 Secret shown once。离开页面前复制以 lab_key_ 开头的秘密值。服务保存的是哈希,而非可以恢复的秘密值。 哈希是单向指纹,让服务可以比较提交的值,而不必显示原始秘密值。
如果丢失该值,按 ID 吊销这个尚未使用的密钥,再签发一个。不要复用泄露值,也不要为了排查复制错误而扩大权限。
保存私有运行配置
本步骤中,你将把替代秘密值保存到服务账号的私有运行文件,并检查访问权限。以下命令均在 Integration 执行。
运行配置是程序执行时读取的文件。此 worker 每次调用都读取 /home/labex/project/runtime/job.ini,因此无需重启。仓库示例不是该文件。在 Integration 查看当前配置:
cat /home/labex/project/runtime/job.ini
[integration]
api_key = lab_key_support_exposed
不要把秘密值放入仓库或 shell 命令历史。Bash 的 read 在提示符接收值:-r 保留字面字符,-s 隐藏输入,-p 显示提示。API_KEY 是临时 shell 变量。在 Integration 执行此命令,在提示符粘贴新秘密值并按 Enter。输入不会显示:
read -r -s -p 'Replacement key: ' API_KEY
printf 输出格式化文本。这里,\n 换行,%s 插入变量值,双引号将其保留为一个参数,> 覆盖指定文件。现有私有文件属于当前终端的账号 keyworker:
printf '[integration]\napi_key = %s\n' "$API_KEY" > /home/labex/project/runtime/job.ini
用 chmod 设置访问权限。模式 600 只允许文件所有者读写,组成员及其他账号都不能访问:
chmod 600 /home/labex/project/runtime/job.ini
ls -l 显示所有权与权限,不打印秘密值:
ls -l /home/labex/project/runtime/job.ini
请找到 -rw------- 和所有者 keyworker。文件大小和日期可能不同。只设置 shell 变量不会更新文件;保存运行配置,才会让下次 worker 调用使用新凭据。
请保持此 Integration 终端打开。API_KEY 属于当前 shell,并非所有终端都能访问。下一步会用它独立发送请求,然后删除变量。如果关闭或重新连接终端,请用上方 cat 命令查看 job.ini 中当前保存的秘密值,再重复本步骤。
完成业务运行并验证
本步骤中,你将处理待办的 daily 批次,并测试允许与禁止的行为。worker 是预置程序:请保持 /opt/keylab/worker.py 不变。任务是恢复凭据,而不是修改程序绕过认证。
在 Integration 运行指定批次:
python3 /opt/keylab/worker.py daily
Read batch: daily (3 items)
{"batch":"daily","count":3,"subjects":["Reset password","Invoice copy","Delivery question"]}
Received batch: daily
Receiving key ID: ...
接收记录中的 ID 必须与 Key Manager 中的替代密钥 ID 一致。如果出现 401,检查保存的秘密值是否对应有效替代密钥;如果出现 403,对照端点表检查权限。如有需要,吊销权限错误的替代密钥,签发正确密钥、更新私有文件并重跑批次。重复运行该批次会替换接收记录,不会创建重复摘要。
查看实际接收服务
继续使用同一 Integration 终端。上一步的 API_KEY 变量仍在这里,无需再次输入仅显示一次的秘密值。
使用只读结果端点。管道 | 将响应传给下一个程序;python3 -m json.tool 运行 Python 的 JSON 格式化工具,用缩进方便阅读:
curl -s -H "Authorization: Bearer $API_KEY" http://127.0.0.1:8000/v1/results | python3 -m json.tool
找到批次 daily、payload 中的三个主题,以及替代密钥的 key_id。该记录来自接收端 API,并非本地成功标记文件。后端也记录了读取源数据的凭据。
现在测试被禁止的客户目录请求:
curl -s -w '\nHTTP %{http_code}\n' -H "Authorization: Bearer $API_KEY" http://127.0.0.1:8000/v1/customers
{"error":"Missing scope","required":"customers:read"}
HTTP 403
这种预期拒绝证明新密钥受到限制。不再需要临时 shell 变量时,用 unset 删除它;已保存的运行文件保持不变:
unset API_KEY
在 Workstation 确认旧密钥仍不可用,监控仍正常:
curl -s -w '\nHTTP %{http_code}\n' -H 'Authorization: Bearer lab_key_support_exposed' http://127.0.0.1:8000/v1/tickets
{"error":"Invalid or revoked key"}
HTTP 401
curl -s -w '\nHTTP %{http_code}\n' -H 'Authorization: Bearer lab_key_monitor_only' http://127.0.0.1:8000/v1/health
{"status":"ok","integration":"monitor"}
HTTP 200
最后,git status --short 用紧凑格式列出仓库中已修改或未跟踪的文件:
git status --short
按引导路径操作不会产生输出,因为你只修改了私有运行文件。切勿把替代秘密值放入示例或提交中。正如第一个实验展示的,即使可见内容被删除,历史仍可能保留秘密值。
总结
你区分了认证失败与权限不足,选择了读写权限组合,私密保存仅显示一次的秘密值,并完成待处理摘要。你检查了接收记录、旧密钥拒绝、客户访问禁止和监控可用性。有效轮换既恢复正常工作,也移除泄露凭据的访问。



