implementing-opa-gatekeeper-for-policy-enforcement について
KubernetesでOPA Gatekeeperを導入し、Regoポリシーをリソース要求の受付時に適用する方法を説明するスキルです。クラスターやセキュリティの担当者向けに、制約の設定、監査、ポリシー監視を扱います。
主な機能
- 01Regoによるポリシー記述
- 02テンプレートと制約によるポリシー定義
- 03受付時の要求の検証または拒否
- 04dryrun、deny、warnモード
- 05監査違反とメトリクスの確認
活用シーン
- 01Kubernetesリソースへのラベル必須化
- 02特権コンテナのデプロイ防止
- 03コンテナイメージレジストリの制限
- 04リソース制限や読み取り専用ルートファイルシステムの監査
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill implementing-opa-gatekeeper-for-policy-enforcementインストール後、Claude Code で/implementing-opa-gatekeeper-for-policy-enforcementを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSEassets/template.mdreferences/api-reference.mdstandards.mdworkflows.mdscripts/agent.pyprocess.py詳細
ポリシー適用のための OPA Gatekeeper の実装
概要
OPA Gatekeeper は、Rego で記述されたポリシーを適用する Kubernetes アドミッションコントローラーです。ConstraintTemplate(Rego ロジックを含むポリシーのひな形)と Constraint(パラメーターを指定してインスタンス化したポリシー)を使用し、アドミッション時に Kubernetes リソースのリクエストを検証、変更、または拒否します。
使用するタイミング
- 環境で opa gatekeeper for policy enforcement の機能をデプロイまたは設定するとき
- コンプライアンス要件に沿ったセキュリティ統制を確立するとき
- この分野のセキュリティアーキテクチャを構築または改善するとき
- この実装が必要なセキュリティ評価を実施するとき
前提条件
- Kubernetes クラスター v1.24 以降
- Helm 3
- cluster-admin 権限を持つ kubectl
- Rego ポリシー言語の基本的な理解
Gatekeeper のインストール
# Install via 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
# Verify
kubectl get pods -n gatekeeper-system
kubectl get crd | grep gatekeeper
インストールの確認
# Check webhook
kubectl get validatingwebhookconfigurations gatekeeper-validating-webhook-configuration
# Check CRDs
kubectl get crd constrainttemplates.templates.gatekeeper.sh
kubectl get crd configs.config.gatekeeper.sh
ConstraintTemplate の例
1. リソースへのラベル必須化
# template-required-labels.yaml
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
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("Missing required labels: %v", [missing])
}
# constraint-require-team-label.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: require-team-label
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
- apiGroups: ["apps"]
kinds: ["Deployment"]
parameters:
labels:
- "team"
- "environment"
2. 特権コンテナーのブロック
# template-block-privileged.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sblockprivileged
spec:
crd:
spec:
names:
kind: K8sBlockPrivileged
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sblockprivileged
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
container.securityContext.privileged == true
msg := sprintf("Privileged container not allowed: %v", [container.name])
}
violation[{"msg": msg}] {
container := input.review.object.spec.initContainers[_]
container.securityContext.privileged == true
msg := sprintf("Privileged init container not allowed: %v", [container.name])
}
# constraint-block-privileged.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sBlockPrivileged
metadata:
name: block-privileged-containers
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces:
- "production"
- "staging"
3. コンテナーイメージレジストリの制限
# template-allowed-repos.yaml
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_matches(container.image)
msg := sprintf("Container image %v is not from an allowed registry. Allowed: %v", [container.image, input.parameters.repos])
}
violation[{"msg": msg}] {
container := input.review.object.spec.initContainers[_]
not image_matches(container.image)
msg := sprintf("Init container image %v is not from an allowed registry. Allowed: %v", [container.image, input.parameters.repos])
}
image_matches(image) {
repo := input.parameters.repos[_]
startswith(image, repo)
}
# constraint-allowed-repos.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
name: restrict-image-repos
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
repos:
- "gcr.io/my-project/"
- "ghcr.io/my-org/"
- "registry.k8s.io/"
4. リソース制限の適用
# template-require-limits.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequirelimits
spec:
crd:
spec:
names:
kind: K8sRequireLimits
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequirelimits
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.resources.limits.cpu
msg := sprintf("Container %v has no CPU limit", [container.name])
}
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.resources.limits.memory
msg := sprintf("Container %v has no memory limit", [container.name])
}
5. latest イメージタグのブロック
# template-block-latest-tag.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sblocklatesttag
spec:
crd:
spec:
names:
kind: K8sBlockLatestTag
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sblocklatesttag
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
endswith(container.image, ":latest")
msg := sprintf("Container %v uses ':latest' tag. Use specific version tags.", [container.name])
}
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not contains(container.image, ":")
msg := sprintf("Container %v has no tag (defaults to latest). Use specific version tags.", [container.name])
}
6. ルートファイルシステムの読み取り専用化
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sreadonlyroot
spec:
crd:
spec:
names:
kind: K8sReadOnlyRoot
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sreadonlyroot
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.securityContext.readOnlyRootFilesystem
msg := sprintf("Container %v must have readOnlyRootFilesystem set to true", [container.name])
}
監査モードと適用モード
# Dry-run mode (audit only, don't block)
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sBlockPrivileged
metadata:
name: block-privileged-dryrun
spec:
enforcementAction: dryrun # dryrun | deny | warn
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
監査違反の確認
# List all constraint violations
kubectl get k8sblockprivileged block-privileged-containers -o yaml | grep -A 20 violations
# Check all constraints audit status
kubectl get constraints -o json | jq '.items[] | {name: .metadata.name, violations: (.status.violations // [] | length)}'
Gatekeeper の設定(除外する名前空間)
apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
name: config
namespace: gatekeeper-system
spec:
match:
- excludedNamespaces:
- kube-system
- gatekeeper-system
- calico-system
processes:
- "*"
モニタリング
# Check Gatekeeper metrics
kubectl port-forward -n gatekeeper-system svc/gatekeeper-webhook-service 8443:443
# Prometheus metrics
kubectl get --raw /metrics | grep gatekeeper
ベストプラクティス
- dryrun から開始する - まず
dryrunモードで Constraint をデプロイして違反を確認し、その後denyに切り替えます - ポリシーライブラリを利用する - 既製のテンプレートには https://github.com/open-policy-agent/gatekeeper-library を活用します
- システム名前空間を除外する - kube-system と gatekeeper-system は必ず除外します
- ポリシーをバージョン管理する - ConstraintTemplate と Constraint を Git に保存します
- 監査結果を監視する - Constraint の
.status.violationsを定期的に確認します - Rego ポリシーをテストする - デプロイ前に
opa testまたは Rego Playground を使用します - アドミッション Webhook と組み合わせる - 多層防御のため、Gatekeeper を Pod Security Admission と組み合わせます
コメント
Markdown 対応