- Published on
Kubernetes RBAC 徹底ガイド: Role・ClusterRole・OPA Gatekeeperで実現する最小権限アクセス制御
- Authors
- Name
- はじめに
- RBACの基本概念
- ServiceAccountとトークン管理
- RBAC設計パターン
- OPA Gatekeeperアーキテクチャ
- ConstraintTemplateとRegoポリシーの作成
- 実践ポリシー事例
- RBAC監査(Audit)とモニタリング
- 比較表: RBAC vs OPA Gatekeeper vs PSA vs Kyverno
- 障害事例と復旧手順
- 運用チェックリスト
- まとめ

はじめに
Kubernetesクラスターを本番環境で運用する際、最初に体系を整備すべき領域がアクセス制御(Access Control)である。クラスター管理者、開発者、CI/CDパイプライン、モニタリングエージェントなど、様々な主体がAPIサーバーにリクエストを送信し、これらのリクエストを誰(Subject)がどのリソース(Resource)にどの操作(Verb)を実行できるかで細かく制御する必要がある。Kubernetesが提供するデフォルトの認可メカニズムであるRBAC(ロールベースアクセス制御)だけでもかなりのレベルのアクセス制御が可能だが、「特定のイメージレジストリのみ許可」、「すべてのPodにリソース制限を必須設定」、「特定のラベルがないネームスペースの作成を禁止」といったポリシー(Policy)ベースの制御はRBACの範囲外である。
このギャップを埋めるのがOPA Gatekeeperである。Open Policy Agent(OPA)ベースのKubernetesアドミッションコントローラーで、Rego言語で記述したポリシーをConstraintTemplateとConstraint CRDを通じてクラスターに適用する。RBACが「誰にどの権限を付与するか」を扱うのに対し、OPA Gatekeeperは「許可されたリクエストがポリシーに準拠しているか」を検証する補完レイヤーである。
本記事では、RBACのコア構成要素からServiceAccountトークン管理、ネームスペース別の権限分離設計パターン、OPA Gatekeeperアーキテクチャ とRegoポリシー作成、実践的なポリシー事例、監査(Audit)戦略、主要ポリシーエンジンの比較、そして障害事例と復旧手順まで総合的に解説する。
RBACの基本概念
Kubernetes RBACは4つのAPIオブジェクトで構成される。この4つの関係を正確に理解することがアクセス制御設計の出発点である。
RoleとClusterRole
Roleは特定のネームスペース内でリソースに対する権限ルール(rules)を定義する。ClusterRoleはネームスペースに限定されず、クラスター全体のリソース(nodes、persistentvolumesなど)に対する権限や、複数のネームスペースにまたがって再利用する権限セットを定義する際に使用する。
# ネームスペーススコープのRole: devネームスペースでのPod読み取り権限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev
name: pod-reader
rules:
- apiGroups: ['']
resources: ['pods']
verbs: ['get', 'watch', 'list']
- apiGroups: ['']
resources: ['pods/log']
verbs: ['get']
# クラスタースコープのClusterRole: 全ネームスペースでのDeployment管理
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: deployment-manager
rules:
- apiGroups: ['apps']
resources: ['deployments']
verbs: ['get', 'list', 'watch', 'create', 'update', 'patch']
- apiGroups: ['apps']
resources: ['deployments/scale']
verbs: ['update', 'patch']
核心原則はワイルドカード(*)の使用を可能な限り避けることである。resources: ["*"]やverbs: ["*"]を使用すると、現在だけでなく将来追加されるリソースに対しても無制限のアクセスを許可することになり、セキュリティリスクが急激に増大する。
RoleBindingとClusterRoleBinding
定義されたRole/ClusterRoleを実際の主体(Subject)に紐付けるのがRoleBindingとClusterRoleBindingである。
# RoleBinding: devネームスペースでfrontend-teamグループにpod-reader Roleを付与
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: frontend-pod-reader
namespace: dev
subjects:
- kind: Group
name: frontend-team
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
重要な警告: system:mastersグループにユーザーを追加してはならない。このグループのメンバーはすべてのRBACチェックをバイパスし、RoleBindingやClusterRoleBindingを削除しても権限を取り消すことができない。
Subjectの種類
RBACで権限を付与されるSubjectには3つの種類がある。
- User: 外部認証システム(OIDC、証明書など)が提供するユーザーアイデンティティ
- Group: ユーザーの論理的なグループ。認証システムからグループ情報を伝達
- ServiceAccount: Kubernetesが直接管理するPod内ワークロード用のアカウント
ServiceAccountとトークン管理
Kubernetes 1.24以降、ServiceAccountに自動的に永続トークンが生成されなくなった。TokenRequest APIを通じて時間制限のあるトークンを発行するのがデフォルトの動作であり、これはセキュリティの面で重要な改善である。
# ServiceAccountの作成
kubectl create serviceaccount ci-deployer -n staging
# 時間制限付きトークンの発行(1時間有効)
kubectl create token ci-deployer -n staging --duration=3600s
# ServiceAccountの権限確認
kubectl auth can-i create deployments --as=system:serviceaccount:staging:ci-deployer -n staging
# 特定のServiceAccountにバインドされたRoleの確認
kubectl get rolebindings -n staging -o json | \
jq '.items[] | select(.subjects[]? | .name=="ci-deployer" and .kind=="ServiceAccount")'
CI/CDパイプライン用のServiceAccountを設計する際は、以下の原則に従う。
- パイプライン別に専用のServiceAccountを作成: 1つのServiceAccountを複数のパイプラインで共有しない
- 必要なネームスペースにのみRoleBindingを作成: ClusterRoleBindingの代わりにネームスペース別のRoleBindingを使用
- トークン有効期間を最小化: パイプラインの実行時間に合わせてトークンの有効期間を設定
- automountServiceAccountTokenの無効化: Podで不必要にServiceAccountトークンがマウントされないように設定
# automountServiceAccountTokenの無効化例
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-service
namespace: production
automountServiceAccountToken: false
RBAC設計パターン
ネームスペース別の分離
マルチテナント環境では、ネームスペースをチームまたは環境単位で分離し、各ネームスペースに独立したRBACポリシーを適用する。
# チーム別ネームスペース + RBAC一括構成例
---
apiVersion: v1
kind: Namespace
metadata:
name: team-alpha
labels:
team: alpha
environment: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: team-alpha
name: team-alpha-developer
rules:
- apiGroups: ['', 'apps', 'batch']
resources: ['pods', 'deployments', 'services', 'configmaps', 'jobs']
verbs: ['get', 'list', 'watch', 'create', 'update', 'patch', 'delete']
- apiGroups: ['']
resources: ['secrets']
verbs: ['get', 'list'] # Secret書き込み権限を制限
- apiGroups: ['']
resources: ['pods/exec']
verbs: ['create'] # デバッグ用にexecを許可
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: team-alpha-developer-binding
namespace: team-alpha
subjects:
- kind: Group
name: team-alpha-devs
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: team-alpha-developer
apiGroup: rbac.authorization.k8s.io
権限エスカレーションの防止
RBAC設計で最も注意すべきことは**権限エスカレーション(Privilege Escalation)**の経路を遮断することである。以下の権限は特に注意が必要である。
pods/exec: Pod内で任意のコマンドを実行できるため、PodのServiceAccountトークンの窃取が可能secretsの読み取り: 他のServiceAccountのトークンやデータベースの認証情報が漏洩するリスクrolebindings/clusterrolebindingsに対するcreate: 自分自身に上位の権限を付与可能escalate/bindverb: Role/ClusterRoleを変更またはバインドできるメタ権限
OPA Gatekeeperアーキテクチャ
OPA GatekeeperはKubernetesアドミッションWebhookとして動作し、APIサーバーがリソースを作成/変更/削除する前にポリシー検証を実行する。
構成要素
- Gatekeeper Controller Manager: アドミッションWebhookリクエストを処理し、Regoポリシーを評価するコアコンポーネント
- Audit Controller: 既にデプロイされたリソースがポリシーに準拠しているかを定期的に検査
- ConstraintTemplate CRD: Regoポリシーロジックとパラメータスキーマを定義するテンプレート
- Constraint CRD: ConstraintTemplateをインスタンス化して、具体的なポリシー適用対象とパラメータを指定
インストール
# Gatekeeperのインストール(Helm)
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm repo update
helm install gatekeeper gatekeeper/gatekeeper \
--namespace gatekeeper-system \
--create-namespace \
--set audit.interval=60 \
--set constraintViolationsLimit=50 \
--set audit.fromCache=true
# インストールの確認
kubectl get pods -n gatekeeper-system
kubectl get crd | grep gatekeeper
動作フロー
Gatekeeperのポリシー評価フローは以下の通りである。
- ユーザーまたはコントローラーがAPIサーバーにリソース作成/変更リクエストを送信
- APIサーバーが認証(AuthN)と認可(AuthZ/RBAC)を実行
- アドミッション段階でGatekeeper Webhookにリクエストを転送
- Gatekeeperが該当リソースにマッチするConstraintを見つけてRegoポリシーを評価
- 違反事項がある場合、リクエストを拒否(Deny)し違反メッセージを返却
- 違反がない場合、リクエストを承認(Allow)してetcdに保存
ConstraintTemplateとRegoポリシーの作成
基本構造
ConstraintTemplateは2つの部分で構成される。CRDスペック(パラメータスキーマ)とRegoコード(ポリシーロジック)である。
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema:
type: object
properties:
labels:
type: array
items:
type: string
description: '必須ラベルのリスト'
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
violation[{"msg": msg, "details": {"missing_labels": missing}}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_]}
missing := required - provided
count(missing) > 0
msg := sprintf("リソースに必須ラベルが不足しています: %v", [missing])
}
Constraintの適用
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: require-team-label
spec:
enforcementAction: deny
match:
kinds:
- apiGroups: ['']
kinds: ['Namespace']
excludedNamespaces:
- kube-system
- gatekeeper-system
parameters:
labels:
- 'team'
- 'cost-center'
実践ポリシー事例
事例1: イメージレジストリの制限
本番クラスターで許可されたコンテナレジストリからのみイメージを取得するよう強制する。
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sallowedrepos
spec:
crd:
spec:
names:
kind: K8sAllowedRepos
validation:
openAPIV3Schema:
type: object
properties:
repos:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sallowedrepos
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not image_from_allowed(container.image)
msg := sprintf("コンテナ '%v' のイメージ '%v' は許可されていないレジストリです。許可レジストリ: %v",
[container.name, container.image, input.parameters.repos])
}
violation[{"msg": msg}] {
container := input.review.object.spec.initContainers[_]
not image_from_allowed(container.image)
msg := sprintf("initContainer '%v' のイメージ '%v' は許可されていないレジストリです。",
[container.name, container.image])
}
image_from_allowed(image) {
repo := input.parameters.repos[_]
startswith(image, repo)
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
name: prod-allowed-repos
spec:
enforcementAction: deny
match:
kinds:
- apiGroups: ['']
kinds: ['Pod']
namespaces:
- production
- staging
parameters:
repos:
- 'gcr.io/my-company/'
- 'us-docker.pkg.dev/my-company/'
- 'registry.internal.company.com/'
事例2: リソースリクエスト/リミットの必須設定
すべてのコンテナにCPUとメモリのrequests/limitsの設定を強制する。
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequireresourcelimits
spec:
crd:
spec:
names:
kind: K8sRequireResourceLimits
validation:
openAPIV3Schema:
type: object
properties:
requiredResources:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequireresourcelimits
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
resource := input.parameters.requiredResources[_]
not container.resources.limits[resource]
msg := sprintf("コンテナ '%v' に resources.limits.%v が設定されていません。", [container.name, resource])
}
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
resource := input.parameters.requiredResources[_]
not container.resources.requests[resource]
msg := sprintf("コンテナ '%v' に resources.requests.%v が設定されていません。", [container.name, resource])
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequireResourceLimits
metadata:
name: require-cpu-memory-limits
spec:
enforcementAction: deny
match:
kinds:
- apiGroups: ['']
kinds: ['Pod']
excludedNamespaces:
- kube-system
- gatekeeper-system
parameters:
requiredResources:
- 'cpu'
- 'memory'
事例3: 特権コンテナのブロック
特権モード(privileged)で実行されるコンテナをブロックする。
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sdisallowprivileged
spec:
crd:
spec:
names:
kind: K8sDisallowPrivileged
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sdisallowprivileged
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
container.securityContext.privileged == true
msg := sprintf("特権コンテナは許可されていません: '%v'", [container.name])
}
violation[{"msg": msg}] {
container := input.review.object.spec.initContainers[_]
container.securityContext.privileged == true
msg := sprintf("特権initContainerは許可されていません: '%v'", [container.name])
}
RBAC監査(Audit)とモニタリング
kubectlベースの監査
# 現在のユーザーの権限確認
kubectl auth can-i --list
# 特定のServiceAccountのネームスペース権限確認
kubectl auth can-i --list --as=system:serviceaccount:production:app-deployer -n production
# 特定の操作の可否確認
kubectl auth can-i delete pods --as=system:serviceaccount:staging:ci-runner -n staging
# クラスター全体でsecrets読み取り可能な主体の探索(kubectl-who-canプラグイン)
kubectl who-can get secrets --all-namespaces
# 過剰な権限を持つClusterRoleBindingの探索
kubectl get clusterrolebindings -o json | \
jq '.items[] | select(.roleRef.name=="cluster-admin") | .metadata.name, .subjects'
GatekeeperのAudit機能
GatekeeperのAudit機能は、既にデプロイされたリソースについてもポリシー違反の有無を検査する。enforcementAction: dryrunに設定すると、ブロックせずに違反事項のみを記録できる。
# ポリシー違反状況の照会
kubectl get k8sallowedrepos prod-allowed-repos -o yaml | \
grep -A 100 "status:" | head -50
# 全Constraint違反のサマリー
kubectl get constraints -o json | \
jq '.items[] | {name: .metadata.name, kind: .kind, violations: (.status.totalViolations // 0)}'
モニタリング統合
GatekeeperはデフォルトでPrometheusメトリクスを公開する。
gatekeeper_violations: 現在の監査で検出された違反数gatekeeper_request_duration_seconds: アドミッションリクエストの処理時間gatekeeper_request_count: 総アドミッションリクエスト数(許可/拒否別)gatekeeper_constraint_template_status: ConstraintTemplateのステータス
比較表: RBAC vs OPA Gatekeeper vs PSA vs Kyverno
Kubernetesのアクセス制御とポリシーエンジンの総合比較を行う。
| 項目 | RBAC | OPA Gatekeeper | Pod Security Admission (PSA) | Kyverno |
|---|---|---|---|---|
| 動作レイヤー | 認可(Authorization) | アドミッション(Admission) | アドミッション(Admission) | アドミッション(Admission) |
| ポリシー言語 | YAML宣言型 | Rego | 組み込みプロファイル(Privileged/Baseline/Restricted) | YAML宣言型 |
| 学習コスト | 低い | 高い(Rego学習が必要) | 非常に低い | 低い |
| 柔軟性 | 低い(権限付与/拒否のみ) | 非常に高い | 低い(3つのプロファイルのみ) | 高い |
| Mutationサポート | 該当なし | サポート(Assign/Modify) | 非サポート | サポート(mutate) |
| リソース生成 | 該当なし | 非サポート | 非サポート | サポート(generate) |
| 監査(Audit) | 監査ログの分析が必要 | 組み込みAudit機能 | audit/warnモード | PolicyReport CRD |
| CNCFステージ | Kubernetes組み込み | Graduated | Kubernetes組み込み | Incubating |
| リソース消費 | なし(APIサーバー組み込み) | 高い(複数Pod) | 非常に低い | 中程度 |
| 推奨用途 | 基本的なアクセス制御 | 複雑なポリシーロジック | Podセキュリティ基準の強制 | Kubernetesネイティブポリシー |
推奨組み合わせ: RBAC(基本認可)+ PSA(Podセキュリティ基準)+ GatekeeperまたはKyverno(カスタムポリシー)を併用することが本番環境のベストプラクティスである。シンプルなポリシーにはKyverno、複雑なクロスリソース検証にはOPA Gatekeeperが適している。
障害事例と復旧手順
事例1: Gatekeeper Webhook障害による全デプロイメントブロック
症状: すべてのPod作成が拒否され、エラーメッセージに webhook "validation.gatekeeper.sh" denied the request または接続タイムアウトが表示される。
原因: Gatekeeper Controller Podが異常終了したか、リソース不足で応答できない状態である。
復旧手順:
# 1. Gatekeeper Podの状態確認
kubectl get pods -n gatekeeper-system
# 2. 緊急時: Webhookの一時無効化(failurePolicyをIgnoreに変更)
kubectl get validatingwebhookconfigurations gatekeeper-validating-webhook-configuration -o yaml > webhook-backup.yaml
kubectl patch validatingwebhookconfigurations gatekeeper-validating-webhook-configuration \
--type='json' -p='[{"op": "replace", "path": "/webhooks/0/failurePolicy", "value": "Ignore"}]'
# 3. Gatekeeper Podの再起動
kubectl rollout restart deployment gatekeeper-controller-manager -n gatekeeper-system
# 4. 正常化確認後にfailurePolicyを復元
kubectl apply -f webhook-backup.yaml
予防措置: GatekeeperのfailurePolicyをFailからIgnoreに変更すると可用性は向上するが、ポリシーのバイパスが可能になるため、本番環境ではFailを維持しつつGatekeeper Podのリソースとreplicasを十分に確保する。
事例2: 過剰なClusterRoleBindingによる権限漏洩
症状: すべてのServiceAccountがクラスターリソースを読み取れる異常な状態が発見される。
診断と復旧:
# cluster-adminにバインドされた主体の探索
kubectl get clusterrolebindings -o json | \
jq '.items[] | select(.roleRef.name=="cluster-admin") | {name: .metadata.name, subjects: .subjects}'
# 不要なClusterRoleBindingの削除
kubectl delete clusterrolebinding suspicious-admin-binding
# 全ClusterRoleBindingの監査
kubectl get clusterrolebindings -o json | \
jq '.items[] | {name: .metadata.name, role: .roleRef.name, subjects: [.subjects[]? | .kind + ":" + .name]}'
事例3: ConstraintTemplate構文エラーによるポリシー未動作
症状: Constraintを作成したがポリシーが適用されない。kubectl get constrainttemplatesでSTATUSが異常である。
診断:
# ConstraintTemplateの状態確認
kubectl get constrainttemplate k8srequiredlabels -o json | jq '.status'
# Rego構文エラーの確認
kubectl describe constrainttemplate k8srequiredlabels | grep -A 10 "Status:"
# Gatekeeperログでエラーを確認
kubectl logs -n gatekeeper-system -l control-plane=controller-manager --tail=100
運用チェックリスト
本番Kubernetesクラスターのアクセス制御を点検するためのチェックリストである。
RBACチェックリスト
-
system:mastersグループに不要なユーザーが登録されていないか -
cluster-adminClusterRoleがバインドされた主体をすべて把握しているか - ワイルドカード(
*)権限を使用するRole/ClusterRoleが存在するか - ServiceAccountに
automountServiceAccountToken: falseがデフォルト設定されているか - ネームスペース別に適切なRole/RoleBindingが構成されているか
-
pods/exec、secrets、rolebindingsなど機密性の高い権限が最小限に付与されているか - 使用していないServiceAccountとRoleBindingが整理されているか
- RBAC設定がGitで管理されているか(GitOps)
OPA Gatekeeperチェックリスト
- Gatekeeper Controllerが高可用性(replicas 2以上)でデプロイされているか
-
failurePolicyが本番要件に合わせて設定されているか - kube-system、gatekeeper-systemなどのシステムネームスペースが適切に除外されているか
- 新しいポリシーを
dryrunモードで先にテストするプロセスがあるか - Audit結果を定期的にレビューしているか
- ConstraintTemplateのRegoコードがユニットテストを通過しているか
- GatekeeperメトリクスがPrometheus/Grafanaに統合されているか
- Webhook障害時の緊急復旧手順(Runbook)が文書化されているか
定期監査項目
- 四半期ごとのRBAC権限レビュー: 過剰な権限を持つ主体の特定
- 月次GatekeeperのAuditレポート: ポリシー違反リソースの現状
- ServiceAccountトークンの使用パターン分析: 未使用トークンの整理
- 新規CRD/API導入時のRBACおよびGatekeeperポリシーの更新
まとめ
Kubernetesのアクセス制御はRBACだけでは完結しない。RBACは「誰にどの権限を付与するか」に対する答えを提供するが、「許可された操作がポリシーに準拠しているか」を検証するにはOPA Gatekeeperのようなアドミッションコントローラーが不可欠である。両方のメカニズムを併用し、Pod Security Admissionで基本的なセキュリティ基準を強制し、定期的な監査を実施することが、本番環境での最小権限の原則を実現する方法である。
特にポリシーをコードとして管理(Policy as Code)し、変更前に必ずdryrunモードで影響を評価し、障害時の緊急復旧手順を事前に準備する運用習慣がセキュリティインシデントを予防する核心である。RBACとOPA Gatekeeperは技術的なツールであるが、これを効果的に運用するには組織のアクセス制御ガバナンスとの連携が不可欠であることを忘れてはならない。