今回は Kubernetes と OPA (Open Policy Agent) を組み合わせて「ラベル強制」を試す.
OPA Gatekeeper をインストールする
まず,Kubernetes クラスターに OPA Gatekeeper をインストールする.今回は OPA のドキュメントに載っている kubectl apply
コマンドを使う.他にも Helm を使うこともできる.
open-policy-agent.github.io
kubectl apply
コマンドでインストールをすると,多くの Kubernetes オブジェクトが適用される.重要なのは CRD (Custom Resource Definition) で,以下の4種類の CRD が適用されている.
configs.config.gatekeeper.sh
(kind: Config
)
constraintpodstatuses.status.gatekeeper.sh
(kind: ConstraintPodStatus
)
constrainttemplatepodstatuses.status.gatekeeper.sh
(kind: ConstraintTemplatePodStatus
)
constrainttemplates.templates.gatekeeper.sh
(kind: ConstraintTemplate
)
$ kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-3.5/deploy/gatekeeper.yaml
namespace/gatekeeper-system created
resourcequota/gatekeeper-critical-pods created
customresourcedefinition.apiextensions.k8s.io/configs.config.gatekeeper.sh created
customresourcedefinition.apiextensions.k8s.io/constraintpodstatuses.status.gatekeeper.sh created
customresourcedefinition.apiextensions.k8s.io/constrainttemplatepodstatuses.status.gatekeeper.sh created
customresourcedefinition.apiextensions.k8s.io/constrainttemplates.templates.gatekeeper.sh created
serviceaccount/gatekeeper-admin created
podsecuritypolicy.policy/gatekeeper-admin created
role.rbac.authorization.k8s.io/gatekeeper-manager-role created
clusterrole.rbac.authorization.k8s.io/gatekeeper-manager-role created
rolebinding.rbac.authorization.k8s.io/gatekeeper-manager-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/gatekeeper-manager-rolebinding created
secret/gatekeeper-webhook-server-cert created
service/gatekeeper-webhook-service created
deployment.apps/gatekeeper-audit created
deployment.apps/gatekeeper-controller-manager created
poddisruptionbudget.policy/gatekeeper-controller-manager created
validatingwebhookconfiguration.admissionregistration.k8s.io/gatekeeper-validating-webhook-configuration created
$ kubectl get crds
NAME CREATED AT
configs.config.gatekeeper.sh 2021-07-05T07:00:00Z
constraintpodstatuses.status.gatekeeper.sh 2021-07-05T07:00:00Z
constrainttemplatepodstatuses.status.gatekeeper.sh 2021-07-05T07:00:00Z
constrainttemplates.templates.gatekeeper.sh 2021-07-05T07:00:00Z
CRD k8srequiredlabels.constraints.gatekeeper.sh
を追加する
さっそく「ラベル強制」のために必要な設定を適用する.まず,ConstraintTemplate から「ラベル強制」をする CRD として K8sRequiredLabels を作る.強制するためには Rego を使って実装をする必要があるけど,詳細は割愛して,今回は OPA の GitHub リポジトリに公開されているサンプルとして,k8srequiredlabels_template.yaml
をそのまま使う.
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema:
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("you must provide labels: %v", [missing])
}
kubectl apply
コマンドで k8srequiredlabels_template.yaml
を適用すると,新しく CRD として k8srequiredlabels.constraints.gatekeeper.sh
が追加された.
$ kubectl apply -f k8srequiredlabels_template.yaml
$ kubectl get crds
NAME CREATED AT
configs.config.gatekeeper.sh 2021-07-05T00:00:00Z
constraintpodstatuses.status.gatekeeper.sh 2021-07-05T00:00:00Z
constrainttemplatepodstatuses.status.gatekeeper.sh 2021-07-05T00:00:00Z
constrainttemplates.templates.gatekeeper.sh 2021-07-05T00:00:00Z
k8srequiredlabels.constraints.gatekeeper.sh 2021-07-05T00:01:00Z
Namespace で「ラベル強制」を試す
まず,Namespace で「ラベル強制」を試す.以下のように K8sRequiredLabels でマニフェストを作る.ポイントは Namespace に対して app
ラベルを強制するため,もし app
ラベルが付いていない場合はリソースの作成に失敗する.
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: namespace-app-label
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
parameters:
labels: ["app"]
実際に namespace-app-label.yaml
を適用する.
$ kubectl apply -f namespace-app-label.yaml
$ kubectl get k8srequiredlabels.constraints.gatekeeper.sh
NAME AGE
namespace-app-label 30s
さっそく以下の3種類のマニフェストを適用する.
- 🆖
ns1.yaml
... app
ラベルなし
- 🆖
ns2.yaml
... app
ラベルなし(env
ラベルあり)
- 🆗
ns3.yaml
... app
ラベルあり(env
ラベルあり)
📁 ns1.yaml
apiVersion: v1
kind: Namespace
metadata:
name: kakakakakku-ns
📁 ns2.yaml
apiVersion: v1
kind: Namespace
metadata:
labels:
env: dev
name: kakakakakku-ns
📁 ns3.yaml
apiVersion: v1
kind: Namespace
metadata:
labels:
app: my-app
env: dev
name: kakakakakku-ns
結果として ns1.yaml
と ns2.yaml
は「ラベル強制」の結果エラーになる.you must provide labels: {"app"}
というエラーも出ている.
$ kubectl apply -f ns1.yaml
Error from server ([namespace-app-label] you must provide labels: {"app"}): error when creating "ns1.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [namespace-app-label] you must provide labels: {"app"}
$ kubectl apply -f ns2.yaml
Error from server ([namespace-app-label] you must provide labels: {"app"}): error when creating "ns2.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [namespace-app-label] you must provide labels: {"app"}
$ kubectl apply -f ns3.yaml
namespace/kakakakakku-ns created
Pod で「ラベル強制」を試す
次に,Pod で「ラベル強制」を試す.同じく K8sRequiredLabels でマニフェストを作る.ポイントは Pod に対して app
ラベルを強制するため,もし app
ラベルが付いていない場合はリソースの作成に失敗する.
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: pod-app-label
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
labels: ["app"]
実際に pod-app-label.yaml
を適用する.
$ kubectl apply -f pod-app-label.yaml
$ kubectl get k8srequiredlabels.constraints.gatekeeper.sh
NAME AGE
namespace-app-label 15m
pod-app-label 30s
さっそく以下の3種類のマニフェストを適用する.
- 🆖
pod1.yaml
... app
ラベルなし
- 🆖
pod2.yaml
... app
ラベルなし(env
ラベルあり)
- 🆗
pod3.yaml
... app
ラベルあり(env
ラベルあり)
📁 pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: kakakakakku-pod
spec:
containers:
- name: nginx
image: nginx:1.21
📁 pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: kakakakakku-pod
labels:
env: dev
spec:
containers:
- name: nginx
image: nginx:1.21
📁 pod3.yaml
apiVersion: v1
kind: Pod
metadata:
name: kakakakakku-pod
labels:
app: my-app
env: dev
spec:
containers:
- name: nginx
image: nginx:1.21
結果として pod1.yaml
と pod2.yaml
は「ラベル強制」の結果エラーになる.you must provide labels: {"app"}
というエラーも出ている.
$ kubectl apply -f pod1.yaml
Error from server ([pod-app-label] you must provide labels: {"app"}): error when creating "pod1.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [pod-app-label] you must provide labels: {"app"}
$ kubectl apply -f pod2.yaml
Error from server ([pod-app-label] you must provide labels: {"app"}): error when creating "pod2.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [pod-app-label] you must provide labels: {"app"}
$ kubectl apply -f pod3.yaml
pod/kakakakakku-pod created
まとめ
今回は Kubernetes と OPA (Open Policy Agent) を組み合わせて「ラベル強制」を試した.Namespace と Pod に対して,もし app
ラベルが付いていない場合はリソースの作成に失敗するようにできた.引き続き OPA を試していくぞ!