権限を取り消してもターミナルは動いている
目標
新規のexec権限の遮断と、既存の実行接続の終了を、それぞれ検証し、証拠を保全します。
なぜ重要なのか
新しい接続が開かないことだけを確認すると、残っている実行を見逃すことがあります。逆に、無条件にPodを削除すると、調査の資料と業務を失うことがあります。専用VMの無害なACKプログラムでその違いを観察し、指定したUIDだけを終了したあと、対照群と復旧したPodの権限の境界を確認します。
65分のラボです。セッションはデフォルトで60分なので、期限が切れる前に+時間で延長してください。最大180分で、セッションが終了すると、ファイルと実行中の接続は消えます。必要な証拠は、終了する前にダウンロードしてください。
ステップ
- inspectでベースラインを読み取り、/root/cks-exec/scope.jsonにnamespace、target_uid、control_uid、identity_methodの4つのフィールドを記録してください。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"]で、2つ目は、resources=["pods/exec"]、resourceNames=["target"]、verbs=["get","create"]で、apiGroups=[""]です。act 2で適用し、controlの実際のexec拒否を確認してください。
- act 3でtargetに実際のexec接続を開き、新しい入力のACKのベースラインを観察してください。/root/cks-exec/evidence/03.jsonのfacts.streamに、nonce・reply・atが保存されます。この接続は後のステップまで維持し、新しい接続に切り替えないでください。
- /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でベースラインを読み取り、/root/cks-exec/scope.jsonにnamespace、target_uid、control_uid、identity_methodの4つのフィールドを記録してください。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"]で、2つ目は、resources=["pods/exec"]、resourceNames=["target"]、verbs=["get","create"]で、apiGroups=[""]です。act 2で適用し、controlの実際のexec拒否を確認してください。
podsとpods/execを別のルールに分けて、resourceNamesを指定してください。制御用のPodは、参照だけができる状態でなければなりません。
実際の双方向接続のベースライン
act 3でtargetに実際のexec接続を開き、新しい入力のACKのベースラインを観察してください。/root/cks-exec/evidence/03.jsonのfacts.streamに、nonce・reply・atが保存されます。この接続は後のステップまで維持し、新しい接続に切り替えないでください。
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は引き続き拒否される必要があります。