- Authors
- Name
- なぜRBACだけでは不十分なのか
- RBAC高度な設計原則
- RBAC vs ABAC vs OPA比較
- OPA Gatekeeperアーキテクチャ
- ConstraintTemplate作成の実践
- enforcementAction戦略:AuditからDenyまで
- Gatekeeper vs Kyverno:ポリシーエンジン選択ガイド
- CI/CDパイプラインへのポリシー統合
- トラブルシューティングガイド
- ValidatingAdmissionPolicy連携(Kubernetes 1.30以降)
- 運用チェックリスト
- 実践シナリオ:最初から最後まで
- おわりに
- 参考資料

なぜRBACだけでは不十分なのか
Kubernetes RBAC(Role-Based Access Control)は「誰がどのリソースに対してどの操作を実行できるか」を制御する中核的なメカニズムです。しかし、RBACだけでは以下のような要件を満たすことができません。
- リソース内容に対する制約:RBACは
Podを作成できるかどうかは制御しますが、そのPodがprivileged: trueかどうか、許可されたレジストリのイメージを使用しているかどうかは検証できません。 - 命名規則の強制:特定のlabelやannotationが必ず存在しなければならないという組織ポリシーをRBACで表現することはできません。
- 動的なポリシー変更:RBACの変更にはYAMLの修正と
kubectl applyが必要です。数百のクラスターで一貫したポリシーデプロイを行うのは困難です。
このギャップを埋めるのがAdmission ControllerベースのPolicy-as-Codeアプローチであり、その代表的な実装がOPA Gatekeeperです。この記事ではRBACの高度な設計から始めて、Gatekeeperでポリシーをコード化し運用する全プロセスを解説します。
RBAC高度な設計原則
最小権限の原則の実践適用
RBAC設計の第一原則は必要最小限の権限のみ付与することです。以下のルールに従います。
- ClusterRoleBindingよりRoleBindingを優先使用:Namespaceスコープで十分な場合はClusterRoleBindingを使用しません。
- ワイルドカード禁止:
resources: ["*"]やverbs: ["*"]は使用しません。 - system:mastersグループの使用禁止:このグループのメンバーはすべてのRBACチェックをバイパスします。break-glass手順用としてのみ別途管理します。
# bad-example: 過剰な権限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: too-permissive
rules:
- apiGroups: ['*']
resources: ['*']
verbs: ['*']
---
# good-example: 必要な権限のみ明示
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-deployer
namespace: production
rules:
- apiGroups: ['apps']
resources: ['deployments']
verbs: ['get', 'list', 'watch', 'create', 'update', 'patch']
- apiGroups: ['']
resources: ['services', 'configmaps']
verbs: ['get', 'list', 'watch', 'create', 'update']
- apiGroups: ['']
resources: ['pods']
verbs: ['get', 'list', 'watch']
- apiGroups: ['']
resources: ['pods/log']
verbs: ['get']
権限エスカレーション防止
Kubernetes RBAC APIはデフォルトで権限エスカレーションをブロックします。ユーザーがRoleやRoleBindingを作成・変更するには、そのRoleに含まれるすべての権限を既に保有している必要があります。ただし、以下の2つのverbはこの保護をバイパスできるため、特に注意が必要です。
| 危険なVerb | 説明 | 対応策 |
|---|---|---|
escalate | Roleに自分が持っていない権限を追加できる | プラットフォーム管理者のみに付与、OPAで二重検証 |
bind | 自分が持っていない権限のRoleをバインドできる | ClusterRoleBinding作成権限自体を制限 |
impersonate | 他のユーザー・グループになりすませる | 監査ログの必須モニタリング、特定対象のみ許可 |
# 権限エスカレーション関連verbを監視する監査ポリシー
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: RequestResponse
verbs: ['escalate', 'bind', 'impersonate']
resources:
- group: 'rbac.authorization.k8s.io'
resources: ['clusterroles', 'clusterrolebindings', 'roles', 'rolebindings']
Aggregated ClusterRoleを安全に使う
Aggregated ClusterRoleはラベルセレクターに基づいて複数のClusterRoleのルールを自動的に合算します。便利ですが、**意図しない権限の蓄積(Role Explosion)**が発生する可能性があります。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitoring-aggregate
labels:
rbac.example.com/aggregate-to-monitoring: 'true'
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.example.com/aggregate-to-monitoring: 'true'
rules: [] # rulesは自動的に埋められる
---
# このClusterRoleのルールが上記aggregateに自動マージされる
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitoring-pods
labels:
rbac.example.com/aggregate-to-monitoring: 'true'
rules:
- apiGroups: ['']
resources: ['pods', 'pods/log']
verbs: ['get', 'list', 'watch']
運用Tips:Aggregated ClusterRoleにどのルールが含まれているか定期的に確認しましょう。
# Aggregated ClusterRoleの実際のルール確認
kubectl get clusterrole monitoring-aggregate -o jsonpath='{.rules}' | jq .
# 特定ラベルを持つ全ClusterRoleを照会
kubectl get clusterrole -l rbac.example.com/aggregate-to-monitoring=true
ServiceAccount管理戦略
すべてのNamespaceにはdefault ServiceAccountが自動生成されます。これをそのまま使ってはいけません。
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: production
automountServiceAccountToken: false # 不要ならトークンマウントを無効化
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: production
spec:
template:
spec:
serviceAccountName: my-app-sa
automountServiceAccountToken: false # Podレベルでも明示
containers:
- name: app
image: registry.example.com/my-app:v2.1.0
RBAC vs ABAC vs OPA比較
ポリシーエンジンを選択する前に、各アプローチの違いを明確に理解する必要があります。
| 項目 | RBAC | ABAC | OPA Gatekeeper |
|---|---|---|---|
| ポリシー単位 | ロール(Role)ベース | 属性(Attribute)ベース | ルール(Rego)ベース |
| 設定方式 | Kubernetes APIオブジェクト | 静的ファイル(APIサーバー再起動必要) | CRD(ConstraintTemplate + Constraint) |
| リソース内容検証 | 不可 | 限定的 | 完全対応 |
| 動的更新 | kubectl apply | APIサーバー再起動 | kubectl apply(ゼロダウンタイム) |
| Mutation対応 | 該当なし | 該当なし | 対応(Assign、AssignMetadata) |
| Audit機能 | なし | なし | 既存リソースの監査可能 |
| 学習コスト | 低い | 中程度 | 高い(Rego学習必要) |
| コミュニティ成熟度 | 組み込み機能 | Deprecated(非推奨) | CNCF Graduated(OPA) |
キーポイント:RBACは「アクセス可否」を制御し、OPA Gatekeeperは「リソース内容の適合性」を検証します。両者は代替関係ではなく補完関係です。
OPA Gatekeeperアーキテクチャ
Admission Controllerの動作フロー
Kubernetes APIサーバーはリクエストを処理する際、以下の順序でAdmission Controllerを経由します。
APIリクエスト → Authentication → Authorization(RBAC) → Mutating Admission → Validating Admission → etcd保存
↑ ↑
Gatekeeper Mutation Gatekeeper Validation
GatekeeperはValidatingAdmissionWebhookとMutatingAdmissionWebhookの両方に登録され、APIサーバーがリソースを保存する前にポリシー検証を実行します。
コアコンポーネント
Gatekeeperは大きく3つのコンポーネントで構成されます。
- Controller Manager:ConstraintTemplateとConstraint CRDを管理し、Regoポリシーをコンパイルします。
- Audit Controller:定期的に既存リソースをスキャンしてポリシー違反を検知します(デフォルト60秒間隔)。
- Webhook Server:APIサーバーのAdmissionリクエストを受けてリアルタイムでポリシーを評価します。
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 replicas=3 \
--set audit.replicas=1 \
--set audit.logLevel=INFO \
--set logDenies=true \
--set emitAdmissionEvents=true \
--set emitAuditEvents=true
# インストール確認
kubectl get pods -n gatekeeper-system
kubectl get crd | grep gatekeeper
インストール後に確認すべきCRD一覧:
assign.mutations.gatekeeper.sh
assignmetadata.mutations.gatekeeper.sh
configs.config.gatekeeper.sh
constraintpodstatuses.status.gatekeeper.sh
constrainttemplatepodstatuses.status.gatekeeper.sh
constrainttemplates.templates.gatekeeper.sh
expansiontemplate.expansion.gatekeeper.sh
modifyset.mutations.gatekeeper.sh
mutatorpodstatuses.status.gatekeeper.sh
providers.externaldata.gatekeeper.sh
ConstraintTemplate作成の実践
ConstraintTemplateはポリシーのテンプレート(雛型)を定義し、Constraintはそのテンプレートにパラメータを埋めて実際のポリシーを有効化します。
例1:必須Label強制
すべてのDeploymentにapp.kubernetes.io/nameとapp.kubernetes.io/ownerラベルが必ず存在しなければならないポリシーです。
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema:
type: object
properties:
labels:
type: array
description: '必ず存在しなければならないラベル名のリスト'
items:
type: string
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])
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: deployment-must-have-labels
spec:
enforcementAction: deny
match:
kinds:
- apiGroups: ['apps']
kinds: ['Deployment']
namespaces: ['production', 'staging']
excludedNamespaces: ['kube-system', 'gatekeeper-system']
parameters:
labels:
- 'app.kubernetes.io/name'
- 'app.kubernetes.io/owner'
例2:許可されたコンテナレジストリのみ使用
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sallowedrepos
spec:
crd:
spec:
names:
kind: K8sAllowedRepos
validation:
openAPIV3Schema:
type: object
properties:
repos:
type: array
description: '許可されたコンテナレジストリのプレフィックスリスト'
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sallowedrepos
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not startswith_any(container.image, input.parameters.repos)
msg := sprintf("コンテナ '%v' のイメージ '%v' は許可されたレジストリに含まれていません。許可リスト: %v", [container.name, container.image, input.parameters.repos])
}
violation[{"msg": msg}] {
container := input.review.object.spec.initContainers[_]
not startswith_any(container.image, input.parameters.repos)
msg := sprintf("initContainer '%v' のイメージ '%v' は許可されたレジストリに含まれていません。許可リスト: %v", [container.name, container.image, input.parameters.repos])
}
startswith_any(str, prefixes) {
prefix := prefixes[_]
startswith(str, prefix)
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
name: allowed-repos-production
spec:
enforcementAction: deny
match:
kinds:
- apiGroups: ['']
kinds: ['Pod']
namespaces: ['production']
parameters:
repos:
- 'registry.example.com/'
- 'gcr.io/my-project/'
例3:Privilegedコンテナのブロック
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8spspprivileged
spec:
crd:
spec:
names:
kind: K8sPSPPrivileged
validation:
openAPIV3Schema:
type: object
properties:
exemptImages:
type: array
description: '例外として許可するイメージリスト'
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8spspprivileged
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
container.securityContext.privileged == true
not is_exempt(container.image)
msg := sprintf("Privilegedコンテナは許可されていません: '%v'", [container.name])
}
violation[{"msg": msg}] {
container := input.review.object.spec.initContainers[_]
container.securityContext.privileged == true
not is_exempt(container.image)
msg := sprintf("Privileged initContainerは許可されていません: '%v'", [container.name])
}
is_exempt(image) {
exempt := input.parameters.exemptImages[_]
image == exempt
}
enforcementAction戦略:AuditからDenyまで
Gatekeeperの中核的な運用戦略は段階的ロールアウトです。最初からdenyで始めると、既存ワークロードが大量にブロックされる可能性があります。
段階的適用フロー
第1段階: dryrun → 第2段階: warn → 第3段階: deny
(監査のみ) (警告表示) (実際のブロック)
| enforcementAction | 動作 | 使用タイミング |
|---|---|---|
dryrun | 違反をAudit結果にのみ記録、リクエストは許可 | ポリシー初回デプロイ時、影響度把握段階 |
warn | 違反時に警告メッセージを返すがリクエストは許可 | 開発チームに認知させる段階 |
deny | 違反時にリクエストを拒否 | 十分なテスト後の本番適用 |
Audit結果の確認
# 特定Constraintの違反事項確認
kubectl get k8srequiredlabels deployment-must-have-labels -o yaml
# 違反リソースのみフィルタリング(jq使用)
kubectl get k8srequiredlabels deployment-must-have-labels -o json | \
jq '.status.violations[] | {name: .name, namespace: .namespace, message: .message}'
# Gatekeeper auditログ確認
kubectl logs -n gatekeeper-system -l control-plane=audit-controller --tail=100 | \
grep '"process":"audit"'
dryrunからdenyへの安全な移行方法
#!/bin/bash
# safe-enforcement-switch.sh
# dryrun → deny移行前の違反確認スクリプト
CONSTRAINT_KIND=$1
CONSTRAINT_NAME=$2
echo "=== 現在の違反件数確認 ==="
VIOLATIONS=$(kubectl get ${CONSTRAINT_KIND} ${CONSTRAINT_NAME} -o json | \
jq '.status.totalViolations')
echo "総違反件数: ${VIOLATIONS}"
if [ "${VIOLATIONS}" -gt 0 ]; then
echo ""
echo "=== 違反リソース一覧 ==="
kubectl get ${CONSTRAINT_KIND} ${CONSTRAINT_NAME} -o json | \
jq -r '.status.violations[] | "\(.namespace)/\(.name): \(.message)"'
echo ""
echo "[WARNING] 違反リソースが存在します。denyに切り替えるとそれらのリソースの更新がブロックされます。"
echo "先に違反リソースを修正してください。"
exit 1
fi
echo ""
echo "違反事項なし。denyに切り替えます。"
kubectl patch ${CONSTRAINT_KIND} ${CONSTRAINT_NAME} --type=merge \
-p '{"spec":{"enforcementAction":"deny"}}'
echo "切り替え完了。"
Gatekeeper vs Kyverno:ポリシーエンジン選択ガイド
OPA GatekeeperとKyvernoはKubernetesポリシーエンジンの二大巨頭です。プロジェクトに合った選択が重要です。
| 比較項目 | OPA Gatekeeper | Kyverno |
|---|---|---|
| ポリシー言語 | Rego(専用言語) | YAML(Kubernetes-native) |
| CNCFステージ | Graduated(OPA) | Incubating |
| Validating Webhook | 対応 | 対応 |
| Mutating Webhook | 対応(Assign、AssignMetadata) | 対応(ネイティブ) |
| リソース生成(Generate) | 未対応 | 対応 |
| イメージ署名検証 | 外部データ連携必要 | 組み込み対応(Cosign、Notary) |
| Audit機能 | 組み込み(定期スキャン) | 組み込み(Policy Report CRD) |
| 外部データ連携 | External Data Provider API | API Call対応 |
| マルチクラスター | Config Sync等の外部ツール | 自前対応は限定的 |
| ValidatingAdmissionPolicy連携 | v3.22から統合 | 対応 |
| 学習コスト | 高い(Rego) | 低い(YAML) |
| 表現力 | 非常に高い(複雑なロジック実装可能) | 中程度(CEL式で補完) |
| リソース使用量 | 高い(複数Pod) | 中程度(単一Controller) |
選択基準のまとめ:
- Regoに既に慣れているチーム、複雑なクロスリソースポリシーが必要な場合:Gatekeeper
- Kubernetes YAMLに慣れていて、Mutation/Generationがコアの場合:Kyverno
- 大規模エンタープライズ環境でOPAエコシステム(Styra DAS等)を活用する場合:Gatekeeper
CI/CDパイプラインへのポリシー統合
Gitベースのポリシー管理構造
policies/
├── templates/
│ ├── k8s-required-labels.yaml
│ ├── k8s-allowed-repos.yaml
│ └── k8s-psp-privileged.yaml
├── constraints/
│ ├── production/
│ │ ├── required-labels.yaml
│ │ └── allowed-repos.yaml
│ └── staging/
│ └── required-labels.yaml
├── tests/
│ ├── required-labels_test.rego
│ └── allowed-repos_test.rego
└── Makefile
Rego単体テストの作成
Regoポリシーには必ず単体テストを書く必要があります。OPA CLIのopa testコマンドを使用します。
# tests/required-labels_test.rego
package k8srequiredlabels
test_violation_missing_label {
input := {
"review": {
"object": {
"metadata": {
"labels": {
"app.kubernetes.io/name": "myapp"
}
}
}
},
"parameters": {
"labels": ["app.kubernetes.io/name", "app.kubernetes.io/owner"]
}
}
results := violation with input as input
count(results) > 0
}
test_no_violation_all_labels_present {
input := {
"review": {
"object": {
"metadata": {
"labels": {
"app.kubernetes.io/name": "myapp",
"app.kubernetes.io/owner": "team-platform"
}
}
}
},
"parameters": {
"labels": ["app.kubernetes.io/name", "app.kubernetes.io/owner"]
}
}
results := violation with input as input
count(results) == 0
}
# テスト実行
opa test ./policies/templates/ ./policies/tests/ -v
# CIで使用するMakefileターゲット
# Makefile
.PHONY: test-rego lint-rego apply-dryrun
test-rego:
opa test ./policies/templates/ ./policies/tests/ -v --fail
lint-rego:
opa check ./policies/templates/ --strict
apply-dryrun:
kubectl apply -f ./policies/templates/ --dry-run=server
kubectl apply -f ./policies/constraints/ --dry-run=server
GitHub Actions統合例
# .github/workflows/policy-ci.yaml
name: Policy CI
on:
pull_request:
paths:
- 'policies/**'
jobs:
test-and-validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup OPA
uses: open-policy-agent/setup-opa@v2
with:
version: latest
- name: Rego Lint
run: |
opa check ./policies/templates/ --strict
- name: Rego Unit Tests
run: |
opa test ./policies/templates/ ./policies/tests/ -v --fail
- name: Validate YAML syntax
run: |
for f in $(find policies/ -name '*.yaml'); do
echo "Validating: $f"
kubectl apply -f "$f" --dry-run=client 2>&1 || exit 1
done
- name: Conftest Policy Check
uses: instrumenta/conftest-action@main
with:
files: policies/constraints/
トラブルシューティングガイド
症状1:Gatekeeper Webhookが応答せず全リクエストがブロックされる
これは最も致命的な障害シナリオです。Gatekeeper Podが全てダウンすると、failurePolicy設定によって動作が異なります。
# Webhook設定確認
kubectl get validatingwebhookconfiguration gatekeeper-validating-webhook-configuration -o yaml | \
grep failurePolicy
# failurePolicy: Fail → Gatekeeper障害時に全リクエストブロック(危険!)
# failurePolicy: Ignore → Gatekeeper障害時にポリシー検証をスキップ
緊急対応手順:
# 1. Webhookを一時的に無効化(緊急時)
kubectl delete validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
# 2. Gatekeeper Podの状態確認と復旧
kubectl get pods -n gatekeeper-system
kubectl describe pod -n gatekeeper-system -l control-plane=controller-manager
# 3. Pod復旧後にWebhook再登録(Helm再適用)
helm upgrade gatekeeper gatekeeper/gatekeeper \
--namespace gatekeeper-system \
--reuse-values
# 4. Webhook再登録確認
kubectl get validatingwebhookconfiguration | grep gatekeeper
運用上の推奨事項:本番環境ではfailurePolicy: Ignoreに設定して、Gatekeeper障害がクラスター全体の障害に拡大するのを防ぎます。ただし、Gatekeeperダウン時にはポリシー検証が一時的に無効化されるため、モニタリングアラートを必ず設定します。
症状2:ConstraintTemplate適用後のStatusが「Not Ready」
# ConstraintTemplateステータス確認
kubectl get constrainttemplate k8srequiredlabels -o yaml | grep -A 20 status
# 一般的な原因:Rego構文エラー
# Controller Managerログでコンパイルエラーを確認
kubectl logs -n gatekeeper-system -l control-plane=controller-manager --tail=50 | \
grep -i "error\|compile\|template"
一般的なRego構文の間違い:
input.review.objectパスの誤字- セミコロンの代わりに改行を使う際のインデントエラー
violationルールの戻り値形式に{"msg": msg}が含まれていない
症状3:Auditが違反を検知しない
# Configにリソース同期が設定されているか確認
kubectl get config config -n gatekeeper-system -o yaml
# 監査対象リソースをConfigに登録する必要がある
# Gatekeeper Config:Auditで参照するリソースの登録
apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
name: config
namespace: gatekeeper-system
spec:
sync:
syncOnly:
- group: ''
version: 'v1'
kind: 'Namespace'
- group: ''
version: 'v1'
kind: 'Pod'
- group: 'apps'
version: 'v1'
kind: 'Deployment'
症状4:Constraintが特定のNamespaceを除外しない
# matchブロックでexcludedNamespacesを確認
spec:
match:
excludedNamespaces:
- 'kube-system'
- 'gatekeeper-system'
- 'cert-manager' # システムコンポーネントのNamespace
- 'monitoring' # モニタリングスタック
また、Gatekeeperのグローバル設定で除外Namespaceを指定できます。
# Helm valuesでグローバル除外設定
helm upgrade gatekeeper gatekeeper/gatekeeper \
--namespace gatekeeper-system \
--set 'exemptNamespaces={kube-system,gatekeeper-system}'
ValidatingAdmissionPolicy連携(Kubernetes 1.30以降)
Kubernetes 1.30からValidatingAdmissionPolicy(VAP)がGAになりました。Gatekeeper v3.22からはVAPとの統合が強化され、sync-vap-enforcement-scopeフラグでGatekeeperのenforcement範囲とVAPのenforcement範囲を一致させることができます。
# Gatekeeper 3.22以降でVAP連携を有効化
helm upgrade gatekeeper gatekeeper/gatekeeper \
--namespace gatekeeper-system \
--set 'controllerManager.extraArgs={--sync-vap-enforcement-scope=true}'
VAPは外部Webhook呼び出しなしにAPIサーバー内部でCEL式による検証を行うため、レイテンシが低くなります。単純なポリシーはVAPで、複雑なクロスリソースポリシーはGatekeeperで分担するハイブリッド戦略が効果的です。
運用チェックリスト
RBACチェックリスト
-
system:mastersグループに一般ユーザーが含まれていないか -
escalate、bind、impersonateverbの使用をモニタリングしているか - すべてのServiceAccountに最小権限のみ付与しているか
-
defaultServiceAccountをワークロードで直接使用していないか - 不要なPodに
automountServiceAccountToken: falseを設定しているか - ClusterRoleBindingよりNamespaceスコープのRoleBindingを優先使用しているか
- Aggregated ClusterRoleの実際のルールを定期的にレビューしているか
- RBAC関連の監査ログ(Audit Log)を収集しているか
OPA Gatekeeperチェックリスト
- Gatekeeper Podが3つ以上のレプリカで運用されているか
-
failurePolicy設定が環境に適しているか(本番:Ignore推奨) - すべてのConstraintTemplateにRego単体テストが書かれているか
- 新しいポリシーは必ず
dryrunまたはwarnで先にデプロイしているか - Audit Controllerが正常に動作し違反事項をモニタリングしているか
-
kube-system、gatekeeper-system等のシステムNamespaceが除外されているか - Gatekeeperのリソース(CPU/Memory)使用量をモニタリングしているか
- Webhookの応答レイテンシをモニタリングしているか(P99レイテンシ)
- ポリシー変更はGitベースのPRレビューを経ているか
- 緊急時のWebhook無効化手順がドキュメント化されているか
障害対応優先順位
| 優先順位 | 障害状況 | 即時対応 | 根本対応 |
|---|---|---|---|
| P0 | Webhook障害で全デプロイがブロック | Webhookを削除しサービス復旧 | failurePolicy変更、レプリカ増設 |
| P1 | Audit未作動で違反未検知 | Audit Controller再起動 | Config sync設定確認、ログパイプライン点検 |
| P2 | 特定ポリシーの誤検知(False Positive) | 該当Constraintをdryrunに切り替え | Regoロジック修正およびテスト強化 |
| P3 | ポリシー漏れで違反リソースがデプロイ | 手動監査後リソース修正 | ConstraintTemplate追加、CIパイプライン強化 |
実践シナリオ:最初から最後まで
シナリオ:本番クラスターにイメージレジストリ制限ポリシーを適用
# Step 1: 現状把握 - どのレジストリのイメージが使われているか確認
kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\t"}{range .spec.containers[*]}{.image}{"\n"}{end}{end}' | \
sort | uniq -c | sort -rn | head -20
# Step 2: ConstraintTemplateデプロイ
kubectl apply -f policies/templates/k8s-allowed-repos.yaml
# Step 3: dryrunモードでConstraintデプロイ
cat <<EOF | kubectl apply -f -
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
name: allowed-repos-production
spec:
enforcementAction: dryrun
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces: ["production"]
parameters:
repos:
- "registry.example.com/"
- "gcr.io/my-project/"
EOF
# Step 4: 1-2日後に違反事項確認
kubectl get k8sallowedrepos allowed-repos-production -o json | \
jq '.status.totalViolations'
# Step 5: 違反リソース修正後にwarnに切り替え
kubectl patch k8sallowedrepos allowed-repos-production --type=merge \
-p '{"spec":{"enforcementAction":"warn"}}'
# Step 6: 開発チームのフィードバック収集後にdenyに切り替え
kubectl patch k8sallowedrepos allowed-repos-production --type=merge \
-p '{"spec":{"enforcementAction":"deny"}}'
# Step 7: ポリシー動作検証
kubectl run test-blocked --image=docker.io/nginx:latest -n production
# Error: admission webhook "validation.gatekeeper.sh" denied the request
おわりに
RBACとOPA GatekeeperはKubernetesセキュリティの異なるレイヤーを担当します。RBACは「誰がアクセスできるか」を制御し、Gatekeeperは「どのリソースが許可されるか」を検証します。この2つのレイヤーを併せて運用することで、初めて完全なポリシー体制が構築されます。
核心原則を改めて整理します。
- RBACは最小権限の原則を徹底的に適用する。ClusterRoleBindingよりRoleBindingを、ワイルドカードより明示的なリソース/verb指定を優先します。
- Gatekeeperポリシーは必ずコードとして管理する。Gitリポジトリでバージョン管理し、PRレビューを経て、CIでRegoテストを自動実行します。
- 段階的ロールアウト(dryrun、warn、deny)を必ず守る。本番環境に直接denyをデプロイするのはインシデントの始まりです。
- 障害対応手順を事前に準備する。Webhook削除コマンドをrunbookに含め、定期的に訓練します。
参考資料
- Kubernetes RBAC公式ドキュメント - Using RBAC Authorization
- Kubernetes RBAC Good Practices
- OPA Gatekeeper公式ドキュメント
- Gatekeeper ConstraintTemplateガイド
- Gatekeeper Auditドキュメント
- Gatekeeper Handling Constraint Violations
- Kubernetes Admission Controllers公式ドキュメント
- Kubernetes Dynamic Admission Control
- OPA Gatekeeper GitHub Releases
- Gatekeeper vs Kyverno比較 - Nirmata