Kubernetes応用編 第02回
「誰が何をできるか」の制御 — RBAC
2.1 はじめに
前回(第1回)では、マルチノードのkindクラスタを構築し、TaskBoard APIをビルド・デプロイし、Namespace / ResourceQuota / LimitRangeで環境を分離しました。現在のTaskBoardは以下の状態です。
第1回終了時の構成:
[app Namespace]
├── Nginx (Deployment, 2レプリカ) + Service (ClusterIP)
└── TaskBoard API (Deployment, 2レプリカ, インメモリ版) + Service (NodePort:30080)
[db Namespace]
└── (空 — 第3回でMySQL StatefulSetを追加)
[monitoring Namespace]
└── (空 — 第4回でログ収集DaemonSetを追加)
基盤:
├── kindクラスタ (CP 1 + Worker 3)
├── Metrics Server 稼働中
├── 各NamespaceにResourceQuota適用済み
└── 各NamespaceにLimitRange適用済み
Namespaceでリソースの「場所」は分離できました。しかし、「誰が」その場所で「何をできるか」は何も制限されていません。いま、kubeconfigを持っている人なら誰でも、どのNamespaceのどのリソースでも自由に操作できます。
VMwareの世界で言えば、vCenterに管理者権限でログインしたユーザー全員が、すべてのフォルダ・リソースプール・VMに対してフルアクセスできる状態です。開発者がうっかり本番のVMを停止してしまう。検証用のリソースプールに本番VMを移動してしまう。こうした事故は、権限分離がないところで起きます。
今回はRBAC(Role-Based Access Control)を使い、「開発者はPodの参照とログ取得だけ」「運用者はDeploymentの更新とPod管理まで」という権限の分離を実装します。
| Before | After |
|---|---|
| kubeconfigの持ち主は何でもできる。怖い | チーム・役割に応じた権限設計ができ、最小権限の原則を実装できる |
2.2 RBACの全体像
2.2.1 VMの世界との対比 — vCenterの権限モデル
VMware vCenterでは、権限管理を以下の3要素で行います。
| 要素 | vCenter | Kubernetes RBAC |
|---|---|---|
| 誰が | ユーザー / グループ(Active Directoryと連携) | ServiceAccount(またはユーザー / グループ) |
| 何をできるか | ロール(読み取り専用、VM管理者、等) | Role / ClusterRole |
| どこで | インベントリオブジェクト(フォルダ、リソースプール) | Namespace(Roleの場合)/ クラスタ全体(ClusterRoleの場合) |
| 紐づけ | 権限の割り当て(ユーザー × ロール × オブジェクト) | RoleBinding / ClusterRoleBinding |
Active DirectoryのOU(組織単位)とグループポリシーに慣れている方なら、「OUがNamespace」「グループがServiceAccount」「グループポリシーのアクセス許可がRole」と読み替えると馴染みやすいでしょう。構造は違いますが、「誰に」「何を」「どの範囲で」許可するかという設計思想は共通です。
2.2.2 RBACの4つの登場人物 — ServiceAccount / Role / ClusterRole / Binding
KubernetesのRBACには4つのリソースが登場します。
| リソース | 役割 | スコープ |
|---|---|---|
| ServiceAccount | 「誰が」— クラスタ内のアイデンティティ | Namespace |
| Role | 「何をできるか」— 許可する操作の定義 | Namespace |
| ClusterRole | 「何をできるか」— Roleのクラスタ全体版 | クラスタ全体 |
| RoleBinding | 「紐づけ」— ServiceAccountにRoleを付与する | Namespace |
| ClusterRoleBinding | 「紐づけ」— ServiceAccountにClusterRoleを付与する | クラスタ全体 |
これらの関係を図にすると、次のようになります。
ServiceAccount ──── RoleBinding ──── Role
(誰が) (紐づけ) (何をできるか)
↕ スコープ: Namespace内
ServiceAccount ── ClusterRoleBinding ── ClusterRole
(誰が) (紐づけ) (何をできるか)
↕ スコープ: クラスタ全体
2.2.3 「誰が」「何を」「どこで」— RBACの3要素
RBACの設計は、常にこの3つの問いから始まります。
| 問い | RBACでの表現 | TaskBoardでの例 |
|---|---|---|
| 誰が | ServiceAccount(subjects) | developer、operator |
| 何を | apiGroups / resources / verbs(rules) | Podの参照、Deploymentの更新 |
| どこで | Namespace(Roleの配置先) | app Namespace、db Namespace |
今回のハンズオンでは、TaskBoardのapp Namespaceとdb Namespaceそれぞれに「developer」(参照のみ)と「operator」(参照 + 更新)の2つの役割を作り、権限の違いを体験します。
2.3 ServiceAccountを作成する
2.3.1 ServiceAccountとは何か
ServiceAccountは、Kubernetes内でアイデンティティを表すリソースです。人間のユーザーアカウントとは異なり、Namespace内に存在し、PodやツールがクラスタのAPIにアクセスする際の「身分証明書」として機能します。
各Namespaceにはdefaultという名前のServiceAccountが自動的に作成されています。特に指定しない限り、そのNamespace内のPodはdefault ServiceAccountで動作します。しかし、defaultには通常、最小限の権限しかありません。用途に応じた専用のServiceAccountを作成し、必要な権限だけを付与するのが最小権限の原則です。
今回は「人間がkubectlで操作する際の権限検証」にServiceAccountを使います。kubectl --as=system:serviceaccount:<namespace>:<name>の構文で、特定のServiceAccountとして操作を実行できるためです。本番環境では、外部のIDプロバイダー(OIDC等)で人間のユーザーを管理し、ServiceAccountはPodやCI/CDパイプライン用に使うのが一般的です。
2.3.2 TaskBoard用のServiceAccountを作成する
まず、第1回で構築した環境が正常に稼働していることを確認します。
[Execution User: developer]
kubectl get pods -n app
NAME READY STATUS RESTARTS AGE
nginx-7d8b4f6c9-k2m5x 1/1 Running 0 1d
nginx-7d8b4f6c9-p8n3q 1/1 Running 0 1d
taskboard-api-5f9d7b8c4-h6j2r 1/1 Running 0 1d
taskboard-api-5f9d7b8c4-w4t9s 1/1 Running 0 1d
Nginx 2台とTaskBoard API 2台がすべてRunningであることを確認できたら、ServiceAccountの作成に進みます。
app Namespaceに「developer」と「operator」の2つのServiceAccountを作成します。
[Execution User: developer]
cat <<'EOF' > ~/k8s-applied/sa-developer-app.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: developer
namespace: app
labels:
app: taskboard
role: developer
EOF
[Execution User: developer]
cat <<'EOF' > ~/k8s-applied/sa-operator-app.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: operator
namespace: app
labels:
app: taskboard
role: operator
EOF
続けて、db Namespaceにも同じ構成で作成します。
[Execution User: developer]
cat <<'EOF' > ~/k8s-applied/sa-developer-db.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: developer
namespace: db
labels:
app: taskboard
role: developer
EOF
[Execution User: developer]
cat <<'EOF' > ~/k8s-applied/sa-operator-db.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: operator
namespace: db
labels:
app: taskboard
role: operator
EOF
4つのServiceAccountをまとめて作成します。
[Execution User: developer]
kubectl apply -f ~/k8s-applied/sa-developer-app.yaml
kubectl apply -f ~/k8s-applied/sa-operator-app.yaml
kubectl apply -f ~/k8s-applied/sa-developer-db.yaml
kubectl apply -f ~/k8s-applied/sa-operator-db.yaml
serviceaccount/developer created
serviceaccount/operator created
serviceaccount/developer created
serviceaccount/operator created
作成されたServiceAccountを確認します。
[Execution User: developer]
kubectl get serviceaccounts -n app
kubectl get serviceaccounts -n db
NAME SECRETS AGE
default 0 1d
developer 0 10s
operator 0 10s
NAME SECRETS AGE
default 0 1d
developer 0 10s
operator 0 10s
各Namespaceにdefault(自動作成)、developer、operatorの3つのServiceAccountが存在しています。この時点では、developerもoperatorもまだ何の権限も持っていません。次のステップでRoleを定義し、権限を付与します。
2.4 Roleで「何ができるか」を定義する
2.4.1 Roleの構造 — apiGroups / resources / verbs
Roleは「どのリソースに対して、どの操作を許可するか」を定義するリソースです。Roleのrulesセクションには、3つの要素を指定します。
| 要素 | 意味 | 例 |
|---|---|---|
| apiGroups | リソースが属するAPIグループ | ""(コアAPI)、"apps"(Deployment等) |
| resources | 対象のリソース種別 | "pods"、"deployments"、"pods/log" |
| verbs | 許可する操作 | "get"、"list"、"watch"、"create"、"update"、"delete" |
apiGroupsは初見だと戸惑うかもしれません。KubernetesのAPIは、リソースの種類によってグループ化されています。Pod、Service、ConfigMapなどの基本リソースはコアAPIグループ(空文字"")に属し、DeploymentやStatefulSetは"apps"グループに属します。どのリソースがどのグループに属するかは、kubectl api-resourcesコマンドで確認できます。
[Execution User: developer]
# よく使うリソースのAPIグループを確認する
kubectl api-resources | grep -E "^pods |^services |^deployments |^configmaps |^secrets "
NAME SHORTNAMES APIVERSION NAMESPACED KIND
configmaps cm v1 true ConfigMap
pods v1 true Pod
secrets v1 true Secret
services svc v1 true Service
deployments deploy apps/v1 true Deployment
APIVERSION列を見てください。v1はコアAPIグループ(Roleでは""と書く)、apps/v1は"apps"グループです。RoleのapiGroupsには、ここに表示されるグループ名を指定します。
verbs(操作)の一覧も押さえておきましょう。
| verb | 意味 | 対応するkubectl操作 |
|---|---|---|
| get | 個別リソースの取得 | kubectl get pod <name> |
| list | リソース一覧の取得 | kubectl get pods |
| watch | リソースの変更監視 | kubectl get pods -w |
| create | リソースの作成 | kubectl create、kubectl apply(新規) |
| update | リソースの更新 | kubectl apply(更新)、kubectl edit |
| patch | リソースの部分更新 | kubectl patch |
| delete | リソースの削除 | kubectl delete |
2.4.2 developer Role — 参照とログ取得のみ
developer Roleでは、Podの状態確認とログの取得だけを許可します。Deploymentの更新やPodの削除はできません。「見る権限はあるが、触る権限はない」というイメージです。
[Execution User: developer]
cat <<'EOF' > ~/k8s-applied/role-developer-app.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
namespace: app
labels:
app: taskboard
role: developer
rules:
# Pod の参照(get / list / watch)を許可
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
# Pod のログ取得を許可
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
# Service の参照を許可(接続先の確認用)
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list"]
# Deployment の参照を許可(状態確認用。更新は不可)
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list"]
EOF
ポイントを整理します。pods/logはサブリソースと呼ばれ、podsとは別に権限を設定する必要があります。kubectl logsコマンドが内部的にアクセスするのはこのサブリソースです。また、Serviceの参照を許可しているのは、開発者がアプリケーションの接続先(ポート番号やClusterIP)を確認する場面を想定しているためです。
db Namespace用も同じ構成で作成します。
[Execution User: developer]
cat <<'EOF' > ~/k8s-applied/role-developer-db.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
namespace: db
labels:
app: taskboard
role: developer
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list"]
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets"]
verbs: ["get", "list"]
EOF
db Namespace用のdeveloper Roleでは、resourcesに"statefulsets"も追加しています。第3回でMySQLをStatefulSetとしてデプロイするため、その参照も許可しておきます。
2.4.3 operator Role — デプロイ更新とPod管理まで
operator Roleは、developer Roleの権限に加え、Deploymentの更新(ローリングアップデート)やPodの削除(トラブル時の再起動)を許可します。ただし、NamespaceやResourceQuotaの変更といったクラスタ管理レベルの操作は含めません。
[Execution User: developer]
cat <<'EOF' > ~/k8s-applied/role-operator-app.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: operator
namespace: app
labels:
app: taskboard
role: operator
rules:
# Pod の参照・ログ取得に加え、削除を許可(障害時の手動再起動用)
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "delete"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
# Service の参照を許可
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list"]
# Deployment の参照に加え、更新を許可(ローリングアップデート用)
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "update", "patch"]
# ConfigMap / Secret の参照を許可(設定値の確認用)
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list"]
EOF
operator Roleのポイントは3つです。Podに"delete"を許可し、障害時にPodを手動で削除してDeploymentに再作成させる運用を可能にしています。Deploymentに"update"と"patch"を許可し、イメージの更新やレプリカ数の変更に対応しています。ConfigMapとSecretは参照のみ("get" / "list")を許可し、設定値の確認はできますが変更はできない設計です。
[Execution User: developer]
cat <<'EOF' > ~/k8s-applied/role-operator-db.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: operator
namespace: db
labels:
app: taskboard
role: operator
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "delete"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list"]
# DB層では StatefulSet も管理対象
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets"]
verbs: ["get", "list", "watch", "update", "patch"]
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list"]
# PVC の参照を許可(DB のデータボリューム確認用)
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list"]
EOF
db Namespace用のoperator Roleは、StatefulSetの管理権限とPVCの参照権限を追加しています。第3回でMySQLをStatefulSetとしてデプロイした際に、データボリュームの状態を確認する場面があるためです。
4つのRoleをまとめて作成します。
[Execution User: developer]
kubectl apply -f ~/k8s-applied/role-developer-app.yaml
kubectl apply -f ~/k8s-applied/role-developer-db.yaml
kubectl apply -f ~/k8s-applied/role-operator-app.yaml
kubectl apply -f ~/k8s-applied/role-operator-db.yaml
role.rbac.authorization.k8s.io/developer created
role.rbac.authorization.k8s.io/developer created
role.rbac.authorization.k8s.io/operator created
role.rbac.authorization.k8s.io/operator created
作成されたRoleを確認します。
[Execution User: developer]
kubectl get roles -n app
kubectl get roles -n db
NAME CREATED AT
developer 2026-01-15T10:00:00Z
operator 2026-01-15T10:00:00Z
NAME CREATED AT
developer 2026-01-15T10:00:00Z
operator 2026-01-15T10:00:00Z
Roleの中身を確認したい場合は、kubectl describeを使います。
[Execution User: developer]
kubectl describe role developer -n app
Name: developer
Labels: app=taskboard
role=developer
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get list watch]
pods/log [] [] [get]
services [] [] [get list]
deployments.apps [] [] [get list]
PolicyRuleに、マニフェストで定義したルールが一覧で表示されます。どのリソースにどの操作が許可されているかが一目でわかります。
2.5 RoleBindingで「誰に」権限を紐づける
2.5.1 RoleBindingの構造
ServiceAccount(誰が)とRole(何をできるか)を作成しましたが、この2つはまだ紐づいていません。RoleBindingで紐づけることで、初めて権限が有効になります。
RoleBindingには2つの要素を指定します。
| 要素 | 意味 | vCenterでの対応 |
|---|---|---|
| subjects | 権限を付与する対象(ServiceAccount) | 権限を割り当てるユーザー / グループ |
| roleRef | 付与するRole | 割り当てるロール(読み取り専用、VM管理者、等) |
2.5.2 各ServiceAccountにRoleを紐づける
app Namespaceの2つのRoleBindingを作成します。
[Execution User: developer]
cat <<'EOF' > ~/k8s-applied/rolebinding-developer-app.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developer-binding
namespace: app
labels:
app: taskboard
role: developer
subjects:
- kind: ServiceAccount
name: developer # 紐づけ対象の ServiceAccount
namespace: app
roleRef:
kind: Role
name: developer # 紐づける Role
apiGroup: rbac.authorization.k8s.io
EOF
subjectsで「誰に」、roleRefで「何を」付与するかを指定しています。roleRef.apiGroupはrbac.authorization.k8s.ioで固定です。
[Execution User: developer]
cat <<'EOF' > ~/k8s-applied/rolebinding-operator-app.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: operator-binding
namespace: app
labels:
app: taskboard
role: operator
subjects:
- kind: ServiceAccount
name: operator
namespace: app
roleRef:
kind: Role
name: operator
apiGroup: rbac.authorization.k8s.io
EOF
続けて、db Namespaceの2つのRoleBindingを作成します。
[Execution User: developer]
cat <<'EOF' > ~/k8s-applied/rolebinding-developer-db.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developer-binding
namespace: db
labels:
app: taskboard
role: developer
subjects:
- kind: ServiceAccount
name: developer
namespace: db
roleRef:
kind: Role
name: developer
apiGroup: rbac.authorization.k8s.io
EOF
[Execution User: developer]
cat <<'EOF' > ~/k8s-applied/rolebinding-operator-db.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: operator-binding
namespace: db
labels:
app: taskboard
role: operator
subjects:
- kind: ServiceAccount
name: operator
namespace: db
roleRef:
kind: Role
name: operator
apiGroup: rbac.authorization.k8s.io
EOF
4つのRoleBindingをまとめて作成します。
[Execution User: developer]
kubectl apply -f ~/k8s-applied/rolebinding-developer-app.yaml
kubectl apply -f ~/k8s-applied/rolebinding-operator-app.yaml
kubectl apply -f ~/k8s-applied/rolebinding-developer-db.yaml
kubectl apply -f ~/k8s-applied/rolebinding-operator-db.yaml
rolebinding.rbac.authorization.k8s.io/developer-binding created
rolebinding.rbac.authorization.k8s.io/operator-binding created
rolebinding.rbac.authorization.k8s.io/developer-binding created
rolebinding.rbac.authorization.k8s.io/operator-binding created
ここまでで、RBAC設定の三層構造(ServiceAccount → Role → RoleBinding)がすべて整いました。ここまでの全体像を整理しておきます。
[app Namespace]
ServiceAccount: developer ── RoleBinding ── Role: developer(参照・ログのみ)
ServiceAccount: operator ── RoleBinding ── Role: operator (更新・削除まで)
[db Namespace]
ServiceAccount: developer ── RoleBinding ── Role: developer(参照・ログのみ)
ServiceAccount: operator ── RoleBinding ── Role: operator (更新・削除まで)
2.6 権限を検証する — 許可と拒否を体験する
2.6.1 kubectl auth can-i で権限を確認する
kubectl auth can-iは、特定の操作が許可されているかどうかを確認するコマンドです。RBACの設定が意図どおりに効いているかを検証するのに使います。
基本構文は以下のとおりです。
# 構文:
# kubectl auth can-i <verb> <resource> -n <namespace> --as=system:serviceaccount:<namespace>:<name>
# 例: app Namespace の developer が pods を get できるか確認
kubectl auth can-i get pods -n app --as=system:serviceaccount:app:developer
--asフラグを使うことで、「もしこのServiceAccountだったら」という視点で権限を確認できます。結果はyes(許可)またはno(拒否)で返ります。
まず、developer ServiceAccountの権限を確認します。
[Execution User: developer]
# developer: Pod の参照 → 許可されているはず
kubectl auth can-i get pods -n app --as=system:serviceaccount:app:developer
# developer: Pod のログ取得 → 許可されているはず
kubectl auth can-i get pods/log -n app --as=system:serviceaccount:app:developer
# developer: Deployment の参照 → 許可されているはず
kubectl auth can-i get deployments -n app --as=system:serviceaccount:app:developer
# developer: Deployment の更新 → 拒否されるはず
kubectl auth can-i update deployments -n app --as=system:serviceaccount:app:developer
# developer: Pod の削除 → 拒否されるはず
kubectl auth can-i delete pods -n app --as=system:serviceaccount:app:developer
yes
yes
yes
no
no
想定どおりです。developerはPodとDeploymentの参照、Podのログ取得はできますが、Deploymentの更新やPodの削除はできません。
次に、operator ServiceAccountの権限を確認します。
[Execution User: developer]
# operator: Deployment の更新 → 許可されているはず
kubectl auth can-i update deployments -n app --as=system:serviceaccount:app:operator
# operator: Pod の削除 → 許可されているはず
kubectl auth can-i delete pods -n app --as=system:serviceaccount:app:operator
# operator: Namespace の削除 → 拒否されるはず(クラスタ管理の操作)
kubectl auth can-i delete namespaces -n app --as=system:serviceaccount:app:operator
yes
yes
no
operatorはDeploymentの更新とPodの削除が許可されていますが、Namespaceの削除のようなクラスタ管理レベルの操作は拒否されます。これが「最小権限の原則」の実装です。各役割に必要な操作だけを許可し、それ以外はすべて拒否します。
🔍 Namespace横断のアクセスも確認してみよう
app Namespaceのdeveloperが、db NamespaceのPodを参照できるか確認してみてください。kubectl auth can-i get pods -n db --as=system:serviceaccount:app:developer
結果はnoです。Roleは定義されたNamespace内でのみ有効です。app Namespaceのdeveloper ServiceAccountにはdb Namespace内での権限がないため、アクセスは拒否されます。
2.6.2 developerでDeploymentを更新しようとして「Forbidden」を体験する
auth can-iでの確認に続いて、実際にdeveloper ServiceAccountとして操作を実行し、拒否される体験をしてみましょう。--asフラグはauth can-iだけでなく、通常のkubectlコマンドでも使えます。
まず、developerとしてPodの一覧を取得します。これは許可されている操作です。
[Execution User: developer]
kubectl get pods -n app --as=system:serviceaccount:app:developer
NAME READY STATUS RESTARTS AGE
nginx-7d8b4f6c9-k2m5x 1/1 Running 0 1d
nginx-7d8b4f6c9-p8n3q 1/1 Running 0 1d
taskboard-api-5f9d7b8c4-h6j2r 1/1 Running 0 1d
taskboard-api-5f9d7b8c4-w4t9s 1/1 Running 0 1d
正常に一覧が取得できました。次に、Podのログを確認します。
[Execution User: developer]
# Pod名は実環境のものに読み替えてください
kubectl logs nginx-7d8b4f6c9-k2m5x -n app --as=system:serviceaccount:app:developer --tail=3
2026/01/15 10:00:00 [notice] 1#1: using the "epoll" event method
2026/01/15 10:00:00 [notice] 1#1: nginx/1.27.0
2026/01/15 10:00:00 [notice] 1#1: start worker processes
ログの取得も問題ありません。では、developerとしてDeploymentのイメージを更新してみます。
[Execution User: developer]
kubectl set image deployment/nginx nginx=nginx:1.27-alpine -n app \
--as=system:serviceaccount:app:developer
Error from server (Forbidden): deployments.apps "nginx" is forbidden: User "system:serviceaccount:app:developer" cannot update resource "deployments" in API group "apps" in the namespace "app"
Forbiddenが返りました。エラーメッセージには、誰が(system:serviceaccount:app:developer)、何を(update resource "deployments")、どこで(in the namespace "app")拒否されたかが明記されています。RBACの拒否メッセージはトラブルシュートの手がかりになるので、読み方に慣れておきましょう。
Podの削除も試してみます。
[Execution User: developer]
kubectl delete pod nginx-7d8b4f6c9-k2m5x -n app \
--as=system:serviceaccount:app:developer
Error from server (Forbidden): pods "nginx-7d8b4f6c9-k2m5x" is forbidden: User "system:serviceaccount:app:developer" cannot delete resource "pods" in API group "" in the namespace "app"
こちらもForbiddenです。developer Roleにはdelete verbが含まれていないため、Podの削除はできません。
2.6.3 operatorで同じ操作が成功することを確認する
同じ操作をoperator ServiceAccountで実行し、権限の違いを確認します。
[Execution User: developer]
kubectl set image deployment/nginx nginx=nginx:1.27-alpine -n app \
--as=system:serviceaccount:app:operator
deployment.apps/nginx image updated
operatorではdeployment.apps/nginx image updatedと表示され、Deploymentの更新に成功しました。developerではForbiddenだった操作が、operatorでは許可されています。これがRBACによるアクセス制御の効果です。
ローリングアップデートが進行中か確認し、その後元のイメージに戻します。
[Execution User: developer]
# ローリングアップデートの状態を確認
kubectl rollout status deployment/nginx -n app
# 元のイメージに戻す
kubectl set image deployment/nginx nginx=nginx:1.27 -n app \
--as=system:serviceaccount:app:operator
deployment "nginx" successfully rolled out
deployment.apps/nginx image updated
Podの削除もoperatorで確認します。DeploymentのPodを削除すると、Deploymentが自動的に新しいPodを作成します。
[Execution User: developer]
# 現在のPod一覧を確認
kubectl get pods -n app --as=system:serviceaccount:app:operator
NAME READY STATUS RESTARTS AGE
nginx-7d8b4f6c9-abc12 1/1 Running 0 30s
nginx-7d8b4f6c9-def34 1/1 Running 0 30s
taskboard-api-5f9d7b8c4-h6j2r 1/1 Running 0 1d
taskboard-api-5f9d7b8c4-w4t9s 1/1 Running 0 1d
[Execution User: developer]
# operatorとしてPodを削除(Pod名は実環境のものに読み替えてください)
kubectl delete pod nginx-7d8b4f6c9-abc12 -n app \
--as=system:serviceaccount:app:operator
pod "nginx-7d8b4f6c9-abc12" deleted
[Execution User: developer]
# Deploymentが新しいPodを自動作成していることを確認
kubectl get pods -n app
NAME READY STATUS RESTARTS AGE
nginx-7d8b4f6c9-def34 1/1 Running 0 60s
nginx-7d8b4f6c9-ghi56 1/1 Running 0 5s
taskboard-api-5f9d7b8c4-h6j2r 1/1 Running 0 1d
taskboard-api-5f9d7b8c4-w4t9s 1/1 Running 0 1d
削除されたPod(abc12)の代わりに、新しいPod(ghi56)が作成されています。Pod数は2台を維持しています。
🔍 –as が使えない場合
--asフラグはimpersonation(成りすまし)機能を使用しています。この機能は、クラスタ管理者(cluster-adminロール)に付与されている権限です。kindクラスタでは、kubectlのデフォルトユーザーがcluster-adminを持っているため問題なく使えます。マネージドKubernetesサービスで同じことを試す場合は、impersonation権限が必要になることに留意してください。
2.7 ClusterRoleとClusterRoleBinding — Namespace横断の権限
2.7.1 ClusterRoleが必要なケース
ここまでで作成したRoleは、すべて特定のNamespace内でのみ有効です。app NamespaceのRoleは、db NamespaceやmonitoringNamespaceには影響しません。多くのケースではこの「Namespace単位の権限分離」で十分です。
しかし、一部のケースではNamespaceを横断する権限が必要になります。
| ケース | なぜNamespace横断が必要か |
|---|---|
| 全Namespaceのリソース監視 | 監視システムがapp / db / monitoringの全PodのメトリクスやログをNodeレベルで収集する |
| Namespace自体の管理 | Namespaceの作成・削除はNamespaceスコープの外にある操作 |
| Nodeの管理 | Nodeはどの Namespaceにも属さないクラスタスコープのリソース |
| PersistentVolumeの管理 | PVはクラスタスコープのリソース(PVCはNamespaceスコープ) |
これらのケースでは、ClusterRoleとClusterRoleBindingを使います。構造はRoleとRoleBindingと同じですが、metadataにnamespaceを指定しません(クラスタ全体に適用されるため)。
参考として、ClusterRoleの構造を示します。今回のTaskBoardではClusterRoleの作成は行いませんが、第4回でDaemonSet(全Nodeでログを収集するPod)を導入する際に必要になる場面があります。
# 参考: ClusterRole の構造(今回は作成しません)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-reader # namespace フィールドがない
rules:
- apiGroups: [""]
resources: ["nodes"] # Node はクラスタスコープ
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: monitoring-node-reader
subjects:
- kind: ServiceAccount
name: log-collector
namespace: monitoring
roleRef:
kind: ClusterRole
name: node-reader
apiGroup: rbac.authorization.k8s.io
2.7.2 「Namespace別Roleが基本、ClusterRoleは例外」の原則
ClusterRoleはクラスタ全体に権限を付与するため、影響範囲が大きくなります。設計の指針は以下のとおりです。
| 原則 | 理由 |
|---|---|
| まずRoleで設計する | 影響範囲がNamespace内に限定されるため、意図しない権限の漏れが起きにくい |
| ClusterRoleは「本当に必要なケースだけ」に使う | Nodeやクラスタスコープのリソース管理、全Namespace横断の監視など、Roleでは実現できないケースに限る |
| ClusterRoleBinding は特に慎重に | クラスタ全体への権限付与は、管理者に限定する。一般のServiceAccountにClusterRoleBindingを安易に付与しない |
VMwareの世界で言えば、「フォルダ単位の権限(= Role)」で管理するのが基本で、「vCenter全体の管理者権限(= ClusterRole)」はインフラチームのリーダーだけに付与する、という運用と同じ考え方です。
2.8 この回のまとめ
2.8.1 TaskBoardの現在地
今回の作業で、TaskBoardは以下の状態になりました。
第2回終了時の構成:
[app Namespace]
├── Nginx (Deployment, 2レプリカ) + Service (ClusterIP)
├── TaskBoard API (Deployment, 2レプリカ, インメモリ版) + Service (NodePort:30080)
├── ServiceAccount: developer + Role + RoleBinding(参照・ログのみ)
└── ServiceAccount: operator + Role + RoleBinding(更新・削除まで)
[db Namespace]
├── (空 — 第3回でMySQL StatefulSetを追加)
├── ServiceAccount: developer + Role + RoleBinding(参照・ログのみ)
└── ServiceAccount: operator + Role + RoleBinding(更新・削除まで)
[monitoring Namespace]
└── (空 — 第4回でログ収集DaemonSetを追加)
基盤:
├── kindクラスタ (CP 1 + Worker 3)
├── Metrics Server 稼働中
├── 各NamespaceにResourceQuota / LimitRange適用済み
└── ★ app / db NamespaceにRBAC適用済み ← 今回追加
2.8.2 RBAC設計の判断基準 — いつ使う / いつ使わない
| 状況 | 推奨 |
|---|---|
| 複数チーム・複数役割がクラスタを共有 | Namespace別のRole + RoleBindingで権限を分離する。必須 |
| 1チーム専用のクラスタ(開発環境等) | Role設計は入れておくのが安全。Pod用ServiceAccountの最小権限化は後工程で効いてくる |
| 全Namespaceの監視・管理が必要 | ClusterRole + ClusterRoleBindingを使う。ただし付与対象を厳選する |
| 個人の検証用クラスタ | RBACの設定は省略可。ただし、本番導入を見据えて練習しておく価値はある |
RBACの設計で最も重要なのは「最小権限の原則」です。必要な権限だけを付与し、不要な権限は与えない。迷ったら「まず狭く設定して、必要に応じて広げる」方が安全です。広い権限から狭めるより、狭い権限から広げる方が事故のリスクは低くなります。
2.8.3 実践編への橋渡し
今回学んだRBACは、実践編 第2回「基本設計」と第4回「環境構築」で再び登場します。応用編では「こう使う」を体験しましたが、実践編では「なぜこの権限設計にするのか」を設計書として言語化します。例えば、developer Roleにpods/logのgetを含めた理由を、チームの運用フローと紐づけて設計書に記載する、というプロセスを踏みます。
2.8.4 次回予告
次回は第3回「ステートフルなアプリの扱い方 — StatefulSet」です。TaskBoardのdb NamespaceにMySQLを追加します。「DeploymentでDBを動かしたらデータが消えた」という体験から始めて、StatefulSetでデータを永続化する方法を学びます。TaskBoard APIもインメモリ版からMySQL接続版に更新し、「アプリ更新 → イメージ再ビルド → デプロイ」のワークフローを初めて体験します。
AIコラム
💡 AIの活用ヒント
RBACのRole設計は「何を許可し、何を拒否するか」の判断が必要です。自分のチームの運用体制に合わせたRole設計をAIに相談すると、設計の叩き台を素早く作れます。
例:「フロントエンドチーム3名、バックエンドチーム2名、SREチーム2名の体制で、Kubernetes上のWebアプリを運用する。各チームに必要なRoleを設計してほしい。最小権限の原則に基づいて」
AIは典型的なRole設計パターンをいくつか提示してくれます。ただし、最終的な判断はチームの実情(オンコール体制、デプロイ頻度、セキュリティポリシー)に基づいて自分で行ってください。AIの提案をそのまま採用するのではなく、チームの現実と照らし合わせて調整することが大切です。
