Skip to content
Published on

Kubernetes RBAC 徹底ガイド: Role・ClusterRole・OPA Gatekeeperで実現する最小権限アクセス制御

Authors
  • Name
    Twitter
Kubernetes RBAC OPA Gatekeeper

はじめに

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を設計する際は、以下の原則に従う。

  1. パイプライン別に専用のServiceAccountを作成: 1つのServiceAccountを複数のパイプラインで共有しない
  2. 必要なネームスペースにのみRoleBindingを作成: ClusterRoleBindingの代わりにネームスペース別のRoleBindingを使用
  3. トークン有効期間を最小化: パイプラインの実行時間に合わせてトークンの有効期間を設定
  4. 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/bind verb: Role/ClusterRoleを変更またはバインドできるメタ権限

OPA Gatekeeperアーキテクチャ

OPA GatekeeperはKubernetesアドミッションWebhookとして動作し、APIサーバーがリソースを作成/変更/削除する前にポリシー検証を実行する。

構成要素

  1. Gatekeeper Controller Manager: アドミッションWebhookリクエストを処理し、Regoポリシーを評価するコアコンポーネント
  2. Audit Controller: 既にデプロイされたリソースがポリシーに準拠しているかを定期的に検査
  3. ConstraintTemplate CRD: Regoポリシーロジックとパラメータスキーマを定義するテンプレート
  4. 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のポリシー評価フローは以下の通りである。

  1. ユーザーまたはコントローラーがAPIサーバーにリソース作成/変更リクエストを送信
  2. APIサーバーが認証(AuthN)と認可(AuthZ/RBAC)を実行
  3. アドミッション段階でGatekeeper Webhookにリクエストを転送
  4. Gatekeeperが該当リソースにマッチするConstraintを見つけてRegoポリシーを評価
  5. 違反事項がある場合、リクエストを拒否(Deny)し違反メッセージを返却
  6. 違反がない場合、リクエストを承認(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のアクセス制御とポリシーエンジンの総合比較を行う。

項目RBACOPA GatekeeperPod 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組み込みGraduatedKubernetes組み込み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のfailurePolicyFailから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-admin ClusterRoleがバインドされた主体をすべて把握しているか
  • ワイルドカード(*)権限を使用するRole/ClusterRoleが存在するか
  • ServiceAccountにautomountServiceAccountToken: falseがデフォルト設定されているか
  • ネームスペース別に適切なRole/RoleBindingが構成されているか
  • pods/execsecretsrolebindingsなど機密性の高い権限が最小限に付与されているか
  • 使用していない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は技術的なツールであるが、これを効果的に運用するには組織のアクセス制御ガバナンスとの連携が不可欠であることを忘れてはならない。