权限已撤销,终端却仍在运行
目标
分别验证新 exec 权限的阻断与已有执行连接的终止,并保全证据。
为什么重要
只确认新连接打不开,可能会漏掉仍在运行的执行。反过来,如果不加区分地直接删除 Pod,又可能丢失调查数据和业务。在专用 VM 上用无害的 ACK 程序观察这种差别,只终止指定的 UID,然后确认对照组和已恢复 Pod 的权限边界。
这是 65 分钟的实验。会话默认为 60 分钟,请在到期前通过+时间延长。最长 180 分钟,会话结束后,文件和正在运行的连接都会消失。需要的证据请在结束前下载。
步骤
- 用 inspect 读取基线,并把 namespace、target_uid、control_uid、identity_method 这四个字段记录到 /root/cks-exec/scope.json。namespace 为 cks-terminal,其余是当前实验中的实际值。用 act 1 保存调查范围。
- 在 /root/cks-exec/allow-role.json 中编写 apiVersion=rbac.authorization.k8s.io/v1、kind=Role、metadata.name=terminal、metadata.namespace=cks-terminal。第一条规则为 apiGroups=[""]、resources=["pods"]、resourceNames=["target","control"]、verbs=["get"],第二条为 resources=["pods/exec"]、resourceNames=["target"]、verbs=["get","create"],apiGroups=[""]。用 act 2 应用,并确认 control 的真实 exec 被拒绝。
- 用 act 3 对 target 打开真实的 exec 连接,观察新输入的 ACK 基线。nonce、reply 和 at 会保存在 /root/cks-exec/evidence/03.json 的 facts.stream 中。这个连接要保持到后面的步骤,不要换成新连接。
- 在 /root/cks-exec/revoke-role.json 中编写同一个 Role,只删除 pods/exec 规则,保留 target 和 control 的 GET 规则。用 act 4 撤销权限,并确认 evidence/04.json 的 new_exec 恰好是 pods/exec 权限被拒绝。
- 用 act 5 向已有连接发送新输入。evidence/05.json 中的响应必须是与第 3 步不同的 nonce,时间必须晚于第 4 步的保存时间。请与同一 target UID 的 GET 成功进行对比,说明这并不是整个 API 的故障。
- 在 /root/cks-exec/containment.json 中记录 namespace=cks-terminal、target=target、实际的 target_uid、preserve_control_uid、evidence_sha256、action=delete-owned-pod、force=false。哈希是把 evidence/05.json 按键排序、无空格的 UTF-8 JSON(ensure_ascii=False)序列化之后得到的 SHA-256。用 act 6 保全终止前的计划和证据。
- 用 act 7 只正常终止在计划中验证过的原始 target UID。在 evidence/07.json 中确认 old_pod_absent=true、stream_rc 为真实的整数退出码、control_ready=true 且原始 control_uid 保持不变、force=false。不要删除其他 Pod 或 namespace。
- 在 /root/cks-exec/report.json 中记录 new_exec=denied、existing_exec=responded-after-revocation、实际的 old_target_uid 和 control_uid、containment=owned-pod-terminated、authentication_tested=impersonation-not-token-revocation、evidence_sha256。哈希是第 7 步证据用同样方式得到的 SHA-256。用 act 8 恢复拥有新 UID 的 target,并确认 Ready、GET 成功以及 exec 仍被拒绝。
参考
所有操作只应用于 VM 内部的 cks-terminal。helper 的用法是
python3 /opt/fixtures/cks_exec_lab.py inspect、从 act 1 到 act 8、从 grade 1 到 grade 8。
act 执行真实的操作和观测,grade 只读取文件。已经完成的 act 会保留答案,不会再次执行。部分输入也不会被自动覆盖,请自行修改。
如果某个步骤在执行途中被中断、结果不确定,请保留数据并在新会话中重现。
本实验的身份是管理员证书的 SA impersonation,并不是真实的 SA 令牌撤销实验。 不要使用特权、主机网络和额外的 capability。不要在生产服务中原样执行这套终止流程,而要先审查所属控制器、节点状态、证据保全和业务影响。
调查对象与对照组的身份
用 inspect 读取基线,并把 namespace、target_uid、control_uid、identity_method 这四个字段记录到 /root/cks-exec/scope.json。namespace 为 cks-terminal,其余是当前实验中的实际值。用 act 1 保存调查范围。
名称可以重复使用,但 UID 是这次资源的身份。这不是寻找令牌值的任务。
只对目标 Pod 授予终端权限
在 /root/cks-exec/allow-role.json 中编写 apiVersion=rbac.authorization.k8s.io/v1、kind=Role、metadata.name=terminal、metadata.namespace=cks-terminal。第一条规则为 apiGroups=[""]、resources=["pods"]、resourceNames=["target","control"]、verbs=["get"],第二条为 resources=["pods/exec"]、resourceNames=["target"]、verbs=["get","create"],apiGroups=[""]。用 act 2 应用,并确认 control 的真实 exec 被拒绝。
把 pods 和 pods/exec 拆成不同的规则,并指定 resourceNames。control Pod 必须只能查询。
真实双向连接的基线
用 act 3 对 target 打开真实的 exec 连接,观察新输入的 ACK 基线。nonce、reply 和 at 会保存在 /root/cks-exec/evidence/03.json 的 facts.stream 中。这个连接要保持到后面的步骤,不要换成新连接。
nonce 和 ACK 对得上,才是真正对新输入的响应。不要只看屏幕上残留的旧输出。
撤销新 exec 请求的权限
在 /root/cks-exec/revoke-role.json 中编写同一个 Role,只删除 pods/exec 规则,保留 target 和 control 的 GET 规则。用 act 4 撤销权限,并确认 evidence/04.json 的 new_exec 恰好是 pods/exec 权限被拒绝。
如果把整个 Role 清空,Pod 的 GET 也会被阻止,就很难区分失败的原因。只删除执行 subresource。
仍然存在的连接与新的输入
用 act 5 向已有连接发送新输入。evidence/05.json 中的响应必须是与第 3 步不同的 nonce,时间必须晚于第 4 步的保存时间。请与同一 target UID 的 GET 成功进行对比,说明这并不是整个 API 的故障。
权限询问的结果与已经打开的进程的生命周期是两回事。请查看撤销之后生成的 nonce 和响应时间。
终止前保全证据和影响范围
在 /root/cks-exec/containment.json 中记录 namespace=cks-terminal、target=target、实际的 target_uid、preserve_control_uid、evidence_sha256、action=delete-owned-pod、force=false。哈希是把 evidence/05.json 按键排序、无空格的 UTF-8 JSON(ensure_ascii=False)序列化之后得到的 SHA-256。用 act 6 保全终止前的计划和证据。
即使内容相同,只要空格或键的顺序不同,原文哈希也会不同。请计算所要求的规范化 JSON 的哈希。
只终止指定的 UID 并确认对照组
用 act 7 只正常终止在计划中验证过的原始 target UID。在 evidence/07.json 中确认 old_pod_absent=true、stream_rc 为真实的整数退出码、control_ready=true 且原始 control_uid 保持不变、force=false。不要删除其他 Pod 或 namespace。
删除 API 成功、对象消失、连接终止,是三种不同的证据。对照组的 UID 和 Ready 状态也必须留下记录。
恢复新 Pod 并编写响应报告
在 /root/cks-exec/report.json 中记录 new_exec=denied、existing_exec=responded-after-revocation、实际的 old_target_uid 和 control_uid、containment=owned-pod-terminated、authentication_tested=impersonation-not-token-revocation、evidence_sha256。哈希是第 7 步证据用同样方式得到的 SHA-256。用 act 8 恢复拥有新 UID 的 target,并确认 Ready、GET 成功以及 exec 仍被拒绝。
新 Pod 的服务恢复并不等于恢复临时管理权限。exec 必须继续被拒绝。