はじめに
Orchard Market は、出店と配送のアプリケーション用に小さなステータスボードを必要としています。ボードのプログラムは準備済みですが、現在の Kubernetes の実行主体には、それらの Deployment を読む権限がありません。ボード専用の実行主体と、実際の希望レプリカ数、利用可能なレプリカ数、テンプレートイメージを表示するためだけの権限を与えてください。スタッフの名前空間、Secret、ワークロードの変更は、アクセス範囲外に保ちます。
成果物は、利用できるボードと CSV ダウンロード、そして実行主体、2 つの名前空間の権限付与、ワークロードの実行主体選択を記述する 4 つの保存済みマニフェストです。ボードは、準備済みクラスターへ実際の HTTPS リクエストを送ります。アクセスが失敗した場合に代用する、成功済みの静的データはありません。
基本的なターミナルのパス、簡単な YAML、名前空間、Pod、Deployment、Service、ラベルを理解していることを前提とします。この実験では、ServiceAccount、Role、RoleBinding、配布されたクライアントを、使う前に説明します。実際の単一ノード Kubernetes クラスター、ボード、合成されたアプリケーションデータ、診断ツールは準備済みです。クラスターのインストール、イメージのビルド、クライアントのプログラミング、トークンのコピーは行いません。所要時間は、読む時間と通常の操作ミスへの対応を含む作者の見積もりであり、初学者の完了時間を実測したものではありません。
ボード専用の実行主体を作成する
このステップでは、ボードの実際の初期実行主体を読み、アプリケーションへのアクセスをまだ付与せずに、専用の ServiceAccount を保存します。
Board タブから始めます。Orchard Market には A clear view of the working day.、Market stalls と Market delivery のグループが表示され、両グループに Access denied · API 403 が出るはずです。これは想定された初期問題です。完成時には、catalogue は希望数 2 と利用可能数 2、checkout は 1 と 1、pickup は 1 と 1、receipts は 0 と 0 で表示されます。4 つとも、準備済みの python:3.12-alpine テンプレートイメージを使います。領収書アーカイブは、意図的にゼロにスケールされています。
主な 3 フィールドは、異なる問いに答えます。Desired replicas は、Deployment に宣言された数です。Available replicas は、readiness と最小 Ready 時間を満たした後の、コントローラーによる数です。Template image は、Deployment テンプレートが要求するイメージです。更新中は、既存のすべての Pod がすでにそのイメージを使うことを証明するものではありません。What these fields mean を展開して読み、もう一度閉じます。これらはコントローラーの観測値であり、顧客向け Web サイトの稼働確認ではありません。
Access details を選びます。Read as の値は API に由来し、最初は market-board:default で終わります。表は意図する権限範囲を示し、すでにアクセスを付与したと主張するものではありません。Back to status board で戻り、Workspace に切り替えます。
ターミナルは /home/labex/project/status-board から始まります。pwd は作業ディレクトリを表示し、ls はその内容を一覧表示します。ディレクトリを変更した場合は、絶対パス付きの cd でここに戻れます。
pwd
ls
cd /home/labex/project/status-board
scope.json、starter、tools があるはずです。cat は、準備済みの作業範囲ファイルを表示します。このファイルは、名前付きの値とリストを表すテキスト形式の JSON(JavaScript Object Notation)を使い、実際の名前空間、実行主体、アプリケーション名を記録しています。
cat scope.json
ボードは market-board で動作し、承認されたアプリケーションデータは market-stalls と market-delivery にあります。market-office は対象外です。--context=labex-v135 は準備済みクラスターを選び、-n は名前空間を選びます。Workspace の既存の操作者用認証情報は、このコースのオブジェクトを調査・設定できます。ボードの認証情報とは別です。その操作者として、実際の対象 Deployment を調べます。
kubectl --context=labex-v135 get deployments -n market-stalls
kubectl --context=labex-v135 get deployments -n market-delivery
希望数ゼロの領収書アーカイブも含め、名前と希望数・利用可能数の結果を読みます。ボードが読み取れなくても、背後のオブジェクトは存在しています。この操作者のターミナルから成功しても、ボード Pod 内のプロセスにアクセスがある証拠にはなりません。
ServiceAccount は、ワークロード用の、名前空間に属する Kubernetes API の実行主体です。Linux ユーザーやブラウザーの訪問者ではありません。準備済みのボード Deployment は、最初は default ServiceAccount を選択しています。describe は、オブジェクトの設定を読みやすいセクションで表示します。
kubectl --context=labex-v135 describe deployment status-board -n market-board
Pod テンプレート内で、選択されている ServiceAccount を探します。Pod は、そのアカウントの認証情報を射影されたファイルとして受け取ります。準備済みのクライアントは、それを内部で読み、配布された認証局を使って API サーバーの証明書を検証します。認証情報を表示したり、操作者の kubeconfig を使ったりすることはありません。認証情報の扱いを実装するのではなく、実行主体と権限を設定します。
配布された ./tools/board-test は、現在のボード Pod 内でそのクライアントを実行します。先頭の ./ は、この作業ディレクトリ内のツールであることを意味します。最初の引数で、ここで学ぶ診断操作を選びます。identity は、この実際の認証情報をどのように認証したかを API に問い合わせます。
./tools/board-test identity
username は system:serviceaccount:market-board:default となり、現在の pod_uid が付くはずです。http_status の値 201 は、この自己識別レビューに API が回答したことを意味します。このレビューは永続化されるクラスターオブジェクトではなく、権限を変更したり Deployment を作成したりしません。トークンは表示されません。ボードのプロセスが Ready で実行主体を確認できても、アプリケーションデータへのアクセスがないことはあります。
リリースディレクトリを作成します。mkdir -p は必要なら作成し、既存のディレクトリは保持します。次のコマンドの > は、編集可能なファイルに出力をリダイレクトします。引用符付きの YAML マーカーは、単独の行にある最後のマーカーまでテキストをそのまま扱わせます。繰り返しても、そのリリースファイルだけが上書きされます。
mkdir -p release
cat > release/identity.yaml <<'YAML'
apiVersion: v1
kind: ServiceAccount
metadata:
name: market-reader
namespace: market-board
YAML
ファイルを読んでから適用します。apply -f は指定されたマニフェストを読み、そのオブジェクトを作成または更新します。
cat release/identity.yaml
kubectl --context=labex-v135 apply -f release/identity.yaml
kubectl --context=labex-v135 get serviceaccount market-reader -n market-board
これで専用の実行主体が存在します。長寿命のトークン Secret が自動的に必要になるわけではありません。Pod がその実行主体を使うと、Kubernetes は Pod に紐付けた認証情報を Pod 内に射影します。この ServiceAccount を作成しただけでは、Deployment へのアクセスも、稼働中のボードの実行主体の変更も行われません。元の default アカウントは変更しないでください。
パスを打ち間違えた場合は、すでに示した pwd、ls、絶対パスの cd を使ってから、失敗した操作を繰り返します。YAML エラーでは、編集可能なファイルを読み、完全な例とインデントを比較して書き直し、再適用してください。scope.json、スターター、ツール、元の名前空間、アプリケーション、データは変更しないでください。編集するのは、指定されたリリースマニフェストと、そこで名前を指定する実行主体・RBAC オブジェクト、およびボード Deployment が選択する ServiceAccount だけです。
最初の名前空間を接続する
このステップでは、出店の名前空間で 2 種類の読み取り操作を付与し、新しいボード Pod に専用の実行主体を実際に使わせます。
Workspace の /home/labex/project/status-board から始めます。Kubernetes の RBAC は、ロールベースのアクセス制御を意味します。Role は、1 つの名前空間内の権限を定義します。RoleBinding は、その名前空間の Role を実行主体に結び付けます。名前が一致するだけでは、この結び付きは生まれません。
ボードは、Deployment のコレクションを読むために list、個々の Deployment を開くために get を必要とします。Deployment は apps API グループに属します。ルールには apps を使い、/v1 は付けません。watch は変更のストリームを要求しますが、このボードは使いません。書き込みの動詞や Secret へのアクセスは不要です。各承認済み名前空間のすべての Deployment に対し、両方の読み取り動詞を使えるようにします。名前を指定したリソースに権限を制限する任意フィールド resourceNames は省きます。バインディングの roleRef.apiGroup は RBAC API の rbac.authorization.k8s.io を識別します。Role が許可する Deployment を含む apps グループとは異なります。
Role とそのバインディングを、1 つのマニフェストに保存します。区切りの --- は、2 つ目の YAML 文書を始めます。バインディングの metadata.namespace は権限の適用場所で、subjects.namespace は ServiceAccount の存在場所です。ここでは意図的に異なっています。
cat > release/first-access.yaml <<'YAML'
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: deployment-reader
namespace: market-stalls
rules:
- apiGroups: [apps]
resources: [deployments]
verbs: [get, list]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: board-reader
namespace: market-stalls
subjects:
- kind: ServiceAccount
name: market-reader
namespace: market-board
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: deployment-reader
YAML
両オブジェクトを読んで適用し、解釈された結び付きを調べます。
cat release/first-access.yaml
kubectl --context=labex-v135 apply -f release/first-access.yaml
kubectl --context=labex-v135 describe role deployment-reader -n market-stalls
kubectl --context=labex-v135 describe rolebinding board-reader -n market-stalls
Deployment に対する get と list だけがあるはずです。roleRef をたどると market-stalls の Role に、対象の subject をたどると market-reader という market-board 内のアカウントにつながります。このバインディングは、対象の名前空間に 2 つ目の ServiceAccount を作成しません。
稼働中のボードは、まだ default を使っています。診断ツールの list 操作は、その Pod の現在の認証情報で実際の Deployment コレクションを要求します。禁止された読み取りは http_status: 403 とゼロ以外の終了ステータスを返します。ワークロードの実行主体を切り替える前は、これが想定どおりです。
./tools/board-test list market-stalls
新しい権限は market-reader のものであり、default のものではありません。default アカウントに権限を付与して直してはいけません。準備済みのボード Deployment の保存用コピーで、専用アカウントを選択します。
最初にスターター全体を読みます。既存のイメージ、マウントされたソース、ヘルスチェック、レプリカ数、その他の保持すべき設定が入っています。
cat starter/board.yaml
kubectl set serviceaccount は、選択する実行主体を変更します。--local は、クラスターに適用せずにこの入力ファイルを変換します。-f は入力名を指定し、-o yaml は標準出力に YAML マニフェストを書き出します。すでに学んだ > で、編集可能なリリースファイルとして保存します。
kubectl --context=labex-v135 set serviceaccount --local -f starter/board.yaml market-reader -o yaml > release/board.yaml
結果を読み、spec.template.spec.serviceAccountName が market-reader であることを確認します。その他のアプリケーション設定はすべて維持してください。
cat release/board.yaml
kubectl --context=labex-v135 apply -f release/board.yaml
既存の Pod の ServiceAccount をその場で変更することはできません。Deployment の Pod テンプレートを更新すると、新しい Pod が作成されます。rollout status は新しいワークロードを待ち、--timeout=120s は待機時間を制限します。
kubectl --context=labex-v135 rollout status deployment/status-board -n market-board --timeout=120s
kubectl --context=labex-v135 get pods -n market-board
現在のボード Pod が 1 つ Ready になるはずです。このボード Pod の置き換えは必要ですが、対象アプリケーションの Pod は変更しません。実際に認証された実行主体をもう一度読みます。
./tools/board-test identity
system:serviceaccount:market-board:market-reader と、元の default 実行主体の Pod とは異なる pod_uid が期待されます。これは、別の実行主体を偽装した評価だけでなく、プロセスの認証情報を確認しています。
Deployment のコレクションと詳細の結果には、希望状態のバージョンである generation と、コントローラーが最後に処理したバージョンである observed_generation も含まれます。詳細ページの表示名は Deployment generation と Observed generation です。コントローラーは、希望状態の変更に一時的に追い付いていないことがあります。これらのフィールドは顧客リクエストを数えたり、Web サイトの可用性を証明したりするものではありません。
出店のコレクションと個々の Deployment を読みます。get は、名前空間に続いて Deployment 名を受け取ります。
./tools/board-test list market-stalls
./tools/board-test get market-stalls catalogue
http_status: 200、コレクション内の元の出店 Deployment 両方、そして個別結果では catalogue の希望数 2 と利用可能数 2 が期待されます。uid は元のオブジェクトを識別します。テンプレートイメージは python:3.12-alpine のままです。名前空間の Role は、配送の名前空間まで広がりません。
./tools/board-test list market-delivery
最後のコマンドでは、API 403 とゼロ以外の終了ステータスが期待されます。Board に切り替え、Refresh view を使い、Inspect catalogue を開いて希望数・利用可能数と Template image を読みます。Back to status board で戻ります。出店のカードは動作し、配送グループはまだ Access denied · API 403 を表示するはずです。この部分的な結果は、名前空間の境界を示す有用な証拠です。
ロールアウト直後に Read as がまだ以前の実行主体を表示していたら、Refresh view をもう一度使います。現在の Pod を確認するには、Workspace に切り替え、./tools/board-test identity を繰り返してから、Board に戻って更新します。Service のルーティングがロールアウトに追い付くまで、少し時間がかかる場合があります。移行を隠すために、古い実行主体にアクセスを与えてはいけません。
実際の読み取り主体、成功した出店カード、まだ拒否されている配送グループを、次の稼働例と比較します。

ロールアウトがタイムアウトしたら、Workspace に戻り、すでに示した describe と get のコマンドで同じ Deployment と Pod を調べます。読み取りが予想外に拒否されたら、Role、RoleBinding の subject の名前空間、選択したワークロードの実行主体を比較してください。自分のリリースファイルだけを修正して適用し、該当するロールアウトまたはリクエストを繰り返します。操作者の認証情報をコピーしたり、アプリケーションを変えたり、VM を再起動したりしてはいけません。
RoleBinding の roleRef は変更できません。以前の打ち間違いで、このコースの新しい board-reader バインディングを誤った Role 参照で作成した場合、Kubernetes はその参照の直接変更を拒否します。調査して release/first-access.yaml を修正した後、自分の名前付きバインディングだけを再作成し、修正した保存済みファイルを適用します。
kubectl --context=labex-v135 delete rolebinding board-reader -n market-stalls
kubectl --context=labex-v135 apply -f release/first-access.yaml
これは条件付きの復旧コマンドであり、通常の成功経路で必要な削除ではありません。default やプラットフォームのバインディングを削除せず、元のボード Deployment や対象ワークロードも削除しないでください。
ボードの役割を広げずに対象を追加する
このステップでは、同じ実行主体に配送の名前空間で同じ 2 種類の読み取り操作を与え、利用できる出力と保護された境界を検証します。
Workspace の /home/labex/project/status-board から始めます。2 つ目の名前空間にも専用の Role と RoleBinding が必要です。そこで Role 名を再利用しますが、subject は market-board に保ちます。実行主体は移動していません。
cat > release/second-access.yaml <<'YAML'
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: deployment-reader
namespace: market-delivery
rules:
- apiGroups: [apps]
resources: [deployments]
verbs: [get, list]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: board-reader
namespace: market-delivery
subjects:
- kind: ServiceAccount
name: market-reader
namespace: market-board
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: deployment-reader
YAML
cat release/second-access.yaml
kubectl --context=labex-v135 apply -f release/second-access.yaml
kubectl --context=labex-v135 describe rolebinding board-reader -n market-delivery
バインディングは、この対象の Role を既存のボードの実行主体に付与します。現在の Pod はすでにその実行主体を使っているため、追加のボードロールアウトは不要です。RBAC の権限付与は足し合わされます。ファイルの順番を変えても拒否ルールが加わったり、無関係な権限付与が消えたりすることはありません。
実際のボードの認証情報で、承認された両コレクションと配送の詳細を読みます。
./tools/board-test list market-stalls
./tools/board-test list market-delivery
./tools/board-test get market-delivery pickup
API 200 と、元のオブジェクトおよびイメージが期待されます。配送コレクションには、希望数 1 / 利用可能数 1 の pickup と、0/0 の receipts が含まれます。希望数ゼロの Deployment は、稼働中の Pod がなくても実際のオブジェクトとして存在します。この宣言された設定を維持してください。
次に、除外されたデータを確認します。Kubernetes の Secret は、名前付きのデータ値を保存します。準備済みの staff-note は合成された教材用データであり、ボードが読む理由はありません。操作者は、値を表示せずに、このオブジェクトの存在を確認できます。
kubectl --context=labex-v135 get secret staff-note -n market-stalls
ボード自身の認証情報は、3 つ目の名前空間とこの Secret に対し、引き続き API 403 を受け取る必要があります。次の両コマンドは、ゼロ以外のステータスで終了することが期待されます。
./tools/board-test list market-office
./tools/board-test secret market-stalls staff-note
オブジェクトの不存在、接続失敗、エラーのスクリーンショットは、この実際の認可拒否と同等ではありません。同じクライアントで承認された対象を正常に読み取れ、既存の除外対象オブジェクトはそのまま残っています。射影された認証情報ファイルがあっても、Secret API へのアクセスが与えられるわけではありません。
ツールの permission 操作は、この実際の認証情報で操作を実行してよいかを API に問い合わせます。その操作自体は実行しません。引数は名前空間、動詞、該当する場合は Deployment 名です。永続化されないレビューは、禁止された各操作に対して http_status: 201 と allowed: false を返します。ツールは、その拒否に対してゼロ以外のステータスを返します。
./tools/board-test permission market-stalls patch catalogue
./tools/board-test permission market-delivery delete pickup
./tools/board-test permission market-stalls create
ボードに必要なのは get と list だけです。watch ストリームやワークロードの変更は認可しません。default の実行主体と元のプラットフォーム RBAC は変更しないでください。ClusterRole、ClusterRoleBinding、ワイルドカード、追加の subject、他のリソースへの権限付与を加えてはいけません。
Board に切り替え、Refresh view を使います。両グループが元の Deployment を表示するようになります。Inspect pickup を開き、数とイメージを読み、Back to status board で戻ります。receipts のカードを読みます。Scaled to zero、利用可能数 0、希望数 0 です。これは、失敗したリクエストを空の値で代用したものではありません。
実際の読み取り主体、4 つすべての Deployment カード、表示されている希望数ゼロのアーカイブを、次の完成例と比較してください。

Download CSV を選び、実際にダウンロードした orchard-market-deployments.csv を開きます。領収書アーカイブも含め、元の Deployment ごとに 1 行、計 4 行のデータがあります。名前空間、Deployment 名、希望数・利用可能数、テンプレートイメージ、API ステータスをページと照合してください。これは新しい API エクスポートであり、保存された成功サンプルではありません。ブラウザーのダウンロード先とターミナルのワークスペースは別の場所です。ダウンロードをワークスペースにコピーする必要はありません。
Access details を選び、実際の Read as の値と、両方の意図された名前空間の範囲を確認して、Back to status board で戻ります。元の対象 Deployment、Pod とコンテナーの識別情報、ソース、イメージ、データ、名前空間ラベルをすべて保持してください。元のボード Deployment と Service を維持し、選択する ServiceAccount だけを変えます。再利用可能なリリースには identity.yaml、first-access.yaml、second-access.yaml、board.yaml が含まれ、実際の実行主体と有効な権限に一致します。
2 つ目の名前空間がまだ拒否される場合は、Workspace に戻り、示した describe コマンドでそのバインディングを調べます。subject の名前空間と Role 参照を比較し、保存したファイルを修正して再適用してください。変更できない誤った roleRef には、前に学んだ同じ限定的な復旧を使います。今度は、自分が新しく作成した配送のバインディングだけが対象です。
kubectl --context=labex-v135 delete rolebinding board-reader -n market-delivery
kubectl --context=labex-v135 apply -f release/second-access.yaml
この特定の復旧の場合にだけ実行してください。除外されたアクセスが予想外に成功する場合は、保存した 2 つの Role とバインディングを調べ、それらのオブジェクト内の意図しない権限を取り除いて再適用します。広い権限付与は、別の狭い Role では上書きされません。ミスを隠すために、プラットフォームの権限やアプリケーションを編集してはいけません。パスと YAML のエラーでは、VM をリセットせず、すでに学んだ復旧を使います。
完成したツールは、この準備済みの単一ノードクラスターで、コントローラーが報告する Deployment 状態を読みます。ボードの訪問者を認証したり、Pod のログやメトリクスを読んだり、本番環境の連続稼働を証明したりするものではありません。readiness エンドポイントが確認するのは、ボードプロセスが応答できることだけです。アプリケーションデータにアクセスできるかどうかは、実際の API 結果が示します。
まとめ
クラスター内で実際に API を利用するプログラムに専用の ServiceAccount を与え、名前空間に限定した Role と RoleBinding を接続し、新しい Pod にその実行主体を実際に使わせました。さらに、同じ読み取りの仕事を 2 つ目の承認済み名前空間に広げ、除外されたデータやワークロードの変更へのアクセスは許可しませんでした。
利用可能なボード、現在の CSV、保存したマニフェストによって、実行主体、権限、実際の API 出力がつながります。希望するレプリカ数、コントローラーが報告する可用数、テンプレートイメージは、それぞれ異なる観測値です。API の拒否は利用不可のまま扱い、意図的に希望数をゼロにした Deployment は、実際のオブジェクトとして表示し続けます。



