PR

Kubernetes応用編 第02回

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管理まで」という権限の分離を実装します。

BeforeAfter
kubeconfigの持ち主は何でもできる。怖いチーム・役割に応じた権限設計ができ、最小権限の原則を実装できる

2.2 RBACの全体像

2.2.1 VMの世界との対比 — vCenterの権限モデル

VMware vCenterでは、権限管理を以下の3要素で行います。

要素vCenterKubernetes 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(自動作成)、developeroperatorの3つのServiceAccountが存在しています。この時点では、developeroperatorもまだ何の権限も持っていません。次のステップで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 createkubectl 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.apiGrouprbac.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と同じですが、metadatanamespaceを指定しません(クラスタ全体に適用されるため)。

参考として、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/loggetを含めた理由を、チームの運用フローと紐づけて設計書に記載する、というプロセスを踏みます。

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の提案をそのまま採用するのではなく、チームの現実と照らし合わせて調整することが大切です。

kubernetes