今回は Kubernetes と OPA (Open Policy Agent) を組み合わせて「ラベル強制」を試す.
OPA Gatekeeper をインストールする
まず,Kubernetes クラスターに OPA Gatekeeper をインストールする.今回は OPA のドキュメントに載っている kubectl apply
コマンドを使う.他にも Helm を使うこともできる.
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: # Schema for the `parameters` field 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 を試していくぞ!