LoginSignup
0
0

More than 1 year has passed since last update.

OPA GatekeeperのGatorを使ってManifestにPolicy違反がないか検証する

Last updated at Posted at 2022-10-19

ここではGatorというOPAのPolicyチェックツールについて簡単に紹介する。なお、触り程度の解説なので、verify機能やkind: Suiteには触れていない。

OPA Gatekeeper利用時の課題

OPA Gatekeeperを使っていると、Manifest作成時にそのManifestがPolicy違反になっていないかを確認したくなることがある。
特にGitOpsでManifestをGitに登録する場合、Policy違反が判明するのはArgoCD等デプロイツールが反応したタイミングであり、CI/CDのスピード感を殺すものとなっている。
conftestで事前に刈り取ることも出来るが、conftestで書くRegoとGatekeeperのManifestは一元管理することが出来ず、Gatekeeper側のPolicy変更が入った場合、conftest側のRegoのメンテが漏れてCI/CDが止まってしまうことも考えられる。

この問題を解決するアプローチとして、以下が考えられる。

  • RegoからGatekeeperのManifestを生成する
  • GatekeeperのManifestをPolicyチェックに使う

前者についてはKonstraintというOSSを用いて実現することが出来る。
後者については本日紹介するGatorにて解決することが出来る。

Gatorとは

GatorOPA Gatekeeperで提供されているツールで、Gatekeeper用Manifest(ConstraintTemplateとConstraint)を元に、ManifestがPolicy違反を起こしていないかをチェックしてくれるツールである。

Gatorで利用するGatekeeper用Manifestを生成する

ここはTanzu Mission ControlのPolicy作成機能を利用してGatekeeper用ManifestであるConstraintTemplateリソースとConstraintリソースを作成する。
Tanzu Mission Controlが利用できない人は、Gatekeeperのexampledemo、konstraintのexamplesあたりを参考に作成するとよい。特にkonstraintのexamplesはかなりサンプルが豊富なのでオススメ。

また、末尾の付録に今回作ったManifestを掲載しているので、それを活用してもらってもよい。

以下、Tanzu Mission Controlを使ってGatekeeper用Manifestを作成していく。
Tanzu Mission Controlにログインし、左サイドバーのPolicies->Assignmentsから自身のクラスタを選択し、CREATE SECURITY POLICYをクリックする。
1666153785401.png

ここではBaselineを選択し、Policy nameに適当な名前を与えてCREATE POLICYをクリックしてPolicyを作成する。
1666153875510.png

上記の画面を見てもらうと分かるが、Privilegedなコンテナ作成やhostNetworkの利用などがこれによりNGとなる。
実行後、クラスタでConstraintTemplateリソースが生成されていることが分かる(Gatekeeperもこの時にインストールされる)。

$ kubectl get constrainttemplate
NAME                                              AGE
vmware-system-tmc-allowed-host-paths-v1           48s
vmware-system-tmc-allowed-procmount-types-v1      53s
vmware-system-tmc-allowed-users-v1                56s
vmware-system-tmc-allowed-volumes-v1              50s
vmware-system-tmc-block-host-namespace-v1         47s
vmware-system-tmc-block-privilege-escalation-v1   52s
vmware-system-tmc-block-privileged-container-v1   49s
vmware-system-tmc-enforce-host-networking-v1      46s
vmware-system-tmc-forbidden-sysctls-v1            54s
vmware-system-tmc-linux-capabilities-v1           55s

Privilegedに関するPolicyを確認する。

$ kubectl get constrainttemplate vmware-system-tmc-block-privileged-container-v1 -o yaml
:(省略)
  crd:
    spec:
      names:
        kind: vmware-system-tmc-block-privileged-container-v1
      validation:
        legacySchema: true
  targets:
  - rego: |-
      package k8spspprivileged
      violation[{"msg": msg, "details": {}}] {
          c := input_containers[_]
          c.securityContext.privileged
          msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext])
      }
      input_containers[c] {
          c := input.review.object.spec.containers[_]
      }
      input_containers[c] {
          c := input.review.object.spec.initContainers[_]
      }
    target: admission.k8s.gatekeeper.sh

これより、以下が分かる。

  • ConstaintのCRD名はvmware-system-tmc-block-privileged-container-v1(ConstraintTemplateと同名)
  • Policy違反時はPrivileged container is not allowed: %v, securityContext: %vでコンテナ名とセキュリティコンテキストが表示される。

続いて、Constraintの方を確認する。

$ kubectl get vmware-system-tmc-block-privileged-container-v1
NAME                       AGE
tmc.cp.opa-baseline-test   5m28s
$ kubectl get vmware-system-tmc-block-privileged-container-v1 -o yaml tmc.cp.opa-baseline-test
:(省略)
  match:
    excludedNamespaces:
    - kube-*
    - vmware-*
    - tanzu-*
    - gatekeeper-system
    - tkg-system
    - istio-system
    - velero
    - wavefront
    - kube-dns
    - kube-node-lease
    - kube-proxy
    - kube-public
    - kube-system
    - tanzu-observability-saas
    - tanzu-package-repo-global
    - tanzu-system
    - tanzu-system-registry
    - tanzu-system-auth
    - tanzu-system-ingress
    - tanzu-system-logging
    - vmware-system-auth
    - vmware-system-cloud-provider
    - vmware-system-csi
    - vmware-system-tmc
    - vmware-system-tsm
    kinds:
    - apiGroups:
      - ""
      kinds:
      - Pod
    namespaceSelector:
      matchExpressions:
      - key: e2e-run
        operator: DoesNotExist

特定のNamespaceは例外とし、Podを対象としていることが分かる。
以下のサンプルを試しにapplyすると、期待していたエラーが表示された。

cat <<EOF > ./testpod-privileged.yaml
kind: Pod
apiVersion: v1
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
    securityContext:
      privileged: true
$ kubectl apply -f testpod-privileged.yaml -n default
Error from server ([tmc.cp.opa-baseline-test] Privileged container is not allowed: nginx, securityContext: {"privileged": true}): error when creating "testpod-privileged.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [tmc.cp.opa-baseline-test] Privileged container is not allowed: nginx, securityContext: {"privileged": true}

これで適切なConstraint,ConstraintTemplateがk8sリソースとして存在しているのが確認できたので、これをファイルとして取り出す。

mkdir privileged-policy/
kubectl get vmware-system-tmc-block-privileged-container-v1 -o yaml tmc.cp.opa-baseline-test > privileged-policy/constraint.yaml
kubectl get constrainttemplate -o yaml vmware-system-tmc-block-privileged-container-v1 > privileged-policy/constrainttemplate.yaml 

なお、statusフィールドを残して出力しているが、特に残っていても問題ないようであり、動作確認時もstatusのフィールドを残して確認した。
ただ、実利用時は保守面等からkubectl neatなどでキレイにしたものを使った方がよいと思われる。

Manifestの検証

作成したManifestを利用してさっそく検証する。
今回、検証として先程作った以下のManifestを利用する。

  • 検証対象のManifest:testpod-privileged.yaml
  • Policy定義:constraint.yaml、constrainttemplate.yaml

Gatorをインストールしていない人は、CLIをインストールする。goによるインストールとbrewによるインストールが提供されており、今回はbrewでインストールした。

brew install gator

インストールが終われば、早速動作確認する。

$ cat testpod-privileged.yaml | gator test -f privileged-policy/
Message: "Privileged container is not allowed: nginx, securityContext: {\"privileged\": true}"

適切にPolicy違反が検出できた。なお、戻り値は以下のようになっており、パイプラインに組み込んで処理を止めることも容易となる。

$ echo $?
1

付録:利用したManifest

ディレクトリ構造は以下となる。

.
├── privileged-policy
│   ├── constraint.yaml
│   └── constrainttemplate.yaml
└── testpod-privileged.yaml

それぞれのファイルの中身は以下となる。(kubectl neatで整形済み)

constraint.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: vmware-system-tmc-block-privileged-container-v1
metadata:
  labels:
    tmc.cloud.vmware.com/crd-type: tmc-managed
    tmc.cloud.vmware.com/managed: "true"
  name: tmc.cp.opa-baseline-test
spec:
  match:
    excludedNamespaces:
    - kube-*
    - vmware-*
    - tanzu-*
    - gatekeeper-system
    - tkg-system
    - istio-system
    - velero
    - wavefront
    - kube-dns
    - kube-node-lease
    - kube-proxy
    - kube-public
    - kube-system
    - tanzu-observability-saas
    - tanzu-package-repo-global
    - tanzu-system
    - tanzu-system-registry
    - tanzu-system-auth
    - tanzu-system-ingress
    - tanzu-system-logging
    - vmware-system-auth
    - vmware-system-cloud-provider
    - vmware-system-csi
    - vmware-system-tmc
    - vmware-system-tsm
    kinds:
    - apiGroups:
      - ""
      kinds:
      - Pod
    namespaceSelector:
      matchExpressions:
      - key: e2e-run
        operator: DoesNotExist
constrainttemplate.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  labels:
    tmc.cloud.vmware.com/crd-type: tmc-managed
    tmc.cloud.vmware.com/managed: "true"
  name: vmware-system-tmc-block-privileged-container-v1
spec:
  crd:
    spec:
      names:
        kind: vmware-system-tmc-block-privileged-container-v1
      validation:
        legacySchema: true
  targets:
  - rego: |-
      package k8spspprivileged
      violation[{"msg": msg, "details": {}}] {
          c := input_containers[_]
          c.securityContext.privileged
          msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext])
      }
      input_containers[c] {
          c := input.review.object.spec.containers[_]
      }
      input_containers[c] {
          c := input.review.object.spec.initContainers[_]
      }
    target: admission.k8s.gatekeeper.sh
testpod-privileged.yaml
kind: Pod
apiVersion: v1
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
    securityContext:
      privileged: true
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0