LoginSignup
0
0

More than 1 year has passed since last update.

EKS上でOpenPolicyAgentのワークショップ資料を使ってOPA Gatekeeperの振る舞いを確認する

Last updated at Posted at 2022-09-21

EKSのOPAのワークショップの内容を確認した時のメモ。
ワークショップの内容だけだと理解が難しいため、実施している内容にコメントをつけて補足した。
言葉の定義などの理解が怪しいので、ご指摘あればコメント欄にて是非。

インストール

こちらより最新版のOPA Gatekeeperのバージョンを確認し、インストールする。

export OPA_GK_VERSION=3.9
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-${OPA_GK_VERSION}/deploy/gatekeeper.yaml 

Podがあがっていることを確認する。

$ kubectl get pod -n gatekeeper-system
NAME                                             READY   STATUS    RESTARTS   AGE
gatekeeper-audit-779ffb6c54-hshsd                1/1     Running   0          21s
gatekeeper-controller-manager-7b4c8d7b97-57d77   1/1     Running   0          21s
gatekeeper-controller-manager-7b4c8d7b97-pmqmv   1/1     Running   0          21s
gatekeeper-controller-manager-7b4c8d7b97-zkqn9   1/1     Running   0          20s

制約の実施

kind: ConstraintTemplateというカスタムリソースを利用し、Kubernetesリソースに対して制約を強制するためのテンプレートを作成することができる。

以下の例はprivileged=trueが含まれるとリクエストを拒否するテンプレートとなる。

cat > /tmp/constrainttemplate.yaml <<EOF
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8spspprivilegedcontainer
spec:
  crd:
    spec:
      names:
        kind: K8sPSPPrivilegedContainer
  targets:
    - target: admission.k8s.gatekeeper.sh
      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[_]
        }
EOF

Manifestを1つ1つ読み解いていく。

以下の部分はCRDを新しく作っている。

  crd:
    spec:
      names:
        kind: K8sPSPPrivilegedContainer

K8sPSPPrivilegedContainerというカスタムリソースを作成する時に上記のテンプレートが適用されることになる。制約発動の条件をCRDで定義したと思うと良さそう。

以下はRegoによって制約を定義している箇所になる。

  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |

targets.targetは説明が見当たらなかったため、一旦おまじないとして考えておく。

以下からRego本体になる。Regoを読み解くのにはOPA/Rego入門公式ドキュメントを参考にした。

        package k8spspprivileged

package k8spspprivilegedはこのregoの名前のようなもので、必ず定義する必要がある。

        violation[{"msg": msg, "details": {}}] {
            c := input_containers[_]
            c.securityContext.privileged
            msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext])
        }

violationではルール違反を定義する。[]内はルール違反時に出力する文字列を設定している。
後述のinput_containersを呼び出し、k8sリソース内のspecのsecurityContext.privilegedtrueかどうかを確認している。
msg変数にはメッセージを設定する。
カッコ内の各行はそれぞれが評価式となり、AND条件で評価されるため、全てがTrueであればルール違反として判定される動きとなる。

以下はinput_containersの定義となる。

        input_containers[c] {
            c := input.review.object.spec.containers[_]
        }

        input_containers[c] {
            c := input.review.object.spec.initContainers[_]
        }

それぞれ、入力元(input.review.object)のspec.containersおよびinitContainersを取得している。複数定義した場合、上書きするのではなく、それぞれで値を引っ張ってくる模様。なので、ここではinput_containersはk8sリソースのspec.containersとspec.initContainersを取得することになる。
なお、[_]で複数取得(リストとかシーケンスの取得)ができるようになっている。

次に上記のテンプレートを利用して制約を適用する。制約を適用するには、先程作成したCRDを使う。

cat > /tmp/constraint.yaml <<EOF
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
  name: psp-privileged-container
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
EOF

ここの記載方法の詳細はこちらの公式ドキュメントが参考になる。

なお、作成したリソースは自分で設定したkindもしくはkind: Constraintを参照することで確認できる。

$ kubectl get K8sPSPPrivilegedContainer
NAME                       ENFORCEMENT-ACTION   TOTAL-VIOLATIONS
psp-privileged-container                        46
$ kubectl get constraint
NAME                       ENFORCEMENT-ACTION   TOTAL-VIOLATIONS
psp-privileged-container                        46

describeで見ると、statusのところでVIOLATIONSの詳細として、どのPodがviolationとなったか、またRegoで定義したメッセージが確認できる。

$ kubectl describe constraint psp-privileged-container 
:(省略)
  Total Violations:  46
  Violations:
    Enforcement Action:  deny
    Group:
    Kind:                Pod
    Message:             Privileged container is not allowed: calico-node, securityContext: {"privileged": true}
    Name:                calico-node-2l6cl
    Namespace:           calico-system
    Version:             v1
    Enforcement Action:  deny
    Group:
    Kind:                Pod
    Message:             Privileged container is not allowed: flexvol-driver, securityContext: {"privileged": true}
    Name:                calico-node-2l6cl
    Namespace:           calico-system
    Version:             v1
:(省略)

この状態でprivileged: trueを含むPodを作成する。

cat > /tmp/example.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: bad-nginx
  labels:
    app: bad-nginx
spec:
  containers:
  - name: nginx
    image: nginx
    securityContext:
      privileged: true
EOF
kubectl create -f /tmp/example.yaml

実行結果として、以下のエラーが出力され、Podが作成できなかったことが分かる。

Error from server (Forbidden): error when creating "/tmp/example.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [psp-privileged-container] Privileged container is not allowed: nginx, securityContext: {"privileged": true}

チュートリアルにはなかったが、せっかくなのでInit Containerに対する制約も試してみる。

cat > /tmp/example.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: bad-nginx
  labels:
    app: bad-nginx
spec:
  initContainers:
  - name: nginx-init
    image: nginx
    securityContext:
      privileged: true
  containers:
  - name: nginx
    image: nginx
EOF
kubectl create -f /tmp/example.yaml

結果は先ほどと同じくPodの作成に失敗した。

Error from server (Forbidden): error when creating "/tmp/example.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [psp-privileged-container] Privileged container is not allowed: nginx-init, securityContext: {"privileged": true}

エラーメッセージより、Init Containerのコンテナであるnginx-initで失敗したことが分かる。

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