Tanzu Mission Controlで学ぶOpen Policy Agent Part-3
この記事はTanzu Mission Controlで学ぶ Open Policy Agentシリーズです。
シリーズ
第一回 : 概要
第二回 : TMCのOpen Policy Agentを遊んでみる
第三回 : TMCのOpen Policy Agentを解剖する < いまここ
第四回 : TMCからOPAポリシーを自作する
はじめに
概要編の記事にあるよう、OPAは以下のようなフローでKubernetesのリクエストに対しポリシーを定義します。
TMCからSecurity Policyを有効にした際これと同じ仕組みのものがうごいています。
以下TMCで、Security Policyを有効にした際に、どのような方法で第二回目でのPodの起動を阻止していたのかを解剖します。
TMCで管理された環境がある前提です。上の"With Admission Controller"のフロー図をみながら参照してください。
API > Admission Controller
TMCでは、以下のリソースがAPIをインターセプトするAdmission Controllerとして定義されています。
1kubectl get validatingwebhookconfigurations gatekeeper-validating-webhook-configuration
2NAME CREATED AT
3gatekeeper-validating-webhook-configuration 2020-09-30T14:43:48Z
validatingwebhookconfigurations
リソースがAdmission Controllerの挙動を定義しています。詳細はマニュアルのDynamic Admission Controlを参照してください。
筆者が確認した時点では、中身は以下のようになっていました。 主要な部分のみ抜粋します。
1apiVersion: admissionregistration.k8s.io/v1
2kind: ValidatingWebhookConfiguration
3metadata:
4 name: gatekeeper-validating-webhook-configuration
5webhooks:
6- admissionReviewVersions:
7 - v1beta1
8 clientConfig:
9 service:
10 name: gatekeeper-webhook-service
11 namespace: gatekeeper-system
12 path: /v1/admit
13 port: 443
14 failurePolicy: Ignore
15 matchPolicy: Exact
16 name: validation.gatekeeper.sh
17 namespaceSelector:
18 matchExpressions:
19 - key: admission.gatekeeper.sh/ignore
20 operator: DoesNotExist
21 objectSelector: {}
22 rules:
23 - apiGroups:
24 - '*'
25 apiVersions:
26 - '*'
27 operations:
28 - CREATE
29 - UPDATE
30 resources:
31 - '*'
32 scope: '*'
この中の以下の部分ですが、中身を見ると、全てのAPI、全てのリソースのCREATE、UPDATEの際にAdmission Webhookを発報することを意味しています。
1rules:
2- apiGroups:
3 - '*'
4 apiVersions:
5 - '*'
6 operations:
7 - CREATE
8 - UPDATE
9 resources:
10 - '*'
11 scope: '*'
さらに、以下の部分で、Webhookを送信先が記載されています。
1clientConfig:
2 service:
3 name: gatekeeper-webhook-service
4 namespace: gatekeeper-system
5 path: /v1/admit
6 port: 443
つまり、まとめると以下のことがわかります。
validatingwebhookconfigurations
リソースでAdmission Controllerが定義されている- 全てのAPI、全てのリソースのCREATE、UPDATEの際にAdmission Webhookを発報している
- Admisson Webhookの送信先は、
gatekeeper-system
のgatekeeper-webhook-service:443/v1/admit
次にいきます。
Admission Controller > Policy Engine
Webhook先の稼働しているサービスを確認します。
前のステップのgatekeeper-webhook-service:443
でサービスが起動していることがわかります。
1kubectl get svc -n gatekeeper-system
2NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
3gatekeeper-webhook-service ClusterIP 10.101.28.83 <none> 443/TCP 18h
このサービスのSelectorは以下の通りです。
1# kubectl get svc -n gatekeeper-system -o yaml
2apiVersion: v1
3items:
4...
5- spec:
6...
7 selector:
8 control-plane: controller-manager
9 gatekeeper.sh/operation: webhook
10 gatekeeper.sh/system: "yes"
該当するラベルで検索をかけます。すると以下のgatekeeper-controller-manager-*
が3つ、つまりHAの状態でデプロイされていることが確認できます。
なお、これ自体はOPA Gatekeeperと呼ばれる、Kubernetesに対応したOPAのイメージです。
1kubectl get pods -l control-plane=controller-manager -n gatekeeper-system
2NAME READY STATUS RESTARTS AGE
3gatekeeper-controller-manager-c97765cd6-bgkjx 1/1 Running 0 18h
4gatekeeper-controller-manager-c97765cd6-hnvx2 1/1 Running 0 18h
5gatekeeper-controller-manager-c97765cd6-znhqk 1/1 Running 0 18h
つまり、まとめると以下のことがわかります。
- Webhookを発報した先には、OPA GatekeeperがHA化された状態で起動している
次に行きます。
PolicyそしてRego言語
さて、いよいよOPAの中身をみていきます。 OPAには2つのリソースがあります。
- constrainttemplates : 各リソースについて、どのようなポリシーを定義するかをRego言語で記載
- constraints : constrainttemplates 内容を元にどのように、Constraint(縛り)を設けるか定義
詳細はOPA GatekeeperのGithubのREADMEを参照してください
ここでは、第二回目でPod起動の際の以下のエラーがどのように出力されたかをみてきます。
1[denied by tmc.cgp.strict] Sharing the host namespace is not allowed: verybad
ConstraintTemplates
上記のエラーの定義は以下のファイルで行われています。
1kubectl get constrainttemplate vmware-system-tmc-block-host-namespace-v1
2NAME AGE
3vmware-system-tmc-block-host-namespace-v1 22h
筆者が確認したときは中身は以下のようになっていました。 主要な部分のみ抜粋しています。
1apiVersion: templates.gatekeeper.sh/v1beta1
2kind: ConstraintTemplate
3metadata:
4 name: vmware-system-tmc-block-host-namespace-v1
5spec:
6 crd:
7 spec:
8 names:
9 kind: vmware-system-tmc-block-host-namespace-v1
10 targets:
11 - rego: |-
12 package k8spsphostnamespace
13 violation[{"msg": msg, "details": {}}] {
14 input_share_hostnamespace(input.review.object)
15 msg := sprintf("Sharing the host namespace is not allowed: %v", [input.review.object.metadata.name])
16 }
17 input_share_hostnamespace(o) {
18 o.spec.hostPID
19 }
20 input_share_hostnamespace(o) {
21 o.spec.hostIPC
22 }
23 target: admission.k8s.gatekeeper.sh
ポイントが以下の箇所です。
1- rego: |-
2 package k8spsphostnamespace
3 violation[{"msg": msg, "details": {}}] {
4 input_share_hostnamespace(input.review.object)
5 msg := sprintf("Sharing the host namespace is not allowed: %v", [input.review.object.metadata.name])
6 }
7 input_share_hostnamespace(o) {
8 o.spec.hostPID
9 }
10 input_share_hostnamespace(o) {
11 o.spec.hostIPC
12 }
ここで使われているのがRegoといわれる言語です。 これをもう一段階理解するために、RegoのOnline Viewerを使います。
https://play.openpolicyagent.org/p/EWQB9RPi3K
上のリンクでは、Inputに第二回目のverybad.yaml
をAdmissionControllerから変換したものを記載しています。
コードには、ここに含まれているコードを含めています。
Input側の"hostPID"
をTrue、Falseに切り替えてEvaluate結果をみてましょう。
Trueのときは以下のようにOutputが表示されます。
1{
2 "violation": [
3 {
4 "details": {},
5 "msg": "Sharing the host namespace is not allowed: verybad"
6 }
7 ]
8}
Falseのときは以下のようにOutputが表示されます。
1{
2 "violation": []
3}
結果からみて分かる通り、"hostPID": "true"
の時に"violation"
に値をいれます。
そのなかには、msg
は実際にうけとったメッセージと一致しています。
つまり、このRegoという言語で、TMCのSecurity Policyがどのように定義されているかわかります。
Constraint
そしてもう一つ確認するものがConstraintです。これは先ほどRegoで定義したルールがどういう場合に有効かを定義します。
違和感ありますが、ConstraintTemplate名でkubectl get
をします。
すると以下のようにみえてきます。
1kubectl get vmware-system-tmc-block-host-namespace-v1
2NAME AGE
3tmc.cgp.strict 23h
筆者が確認した時点では中身が以下のようになっていました。 主要な部分のみ抜粋しています。
1apiVersion: v1
2items:
3- apiVersion: constraints.gatekeeper.sh/v1beta1
4 kind: vmware-system-tmc-block-host-namespace-v1
5 metadata:
6 name: tmc.cgp.strict
7 spec:
8 match:
9 kinds:
10 - apiGroups:
11 - ""
12 kinds:
13 - Pod
14 namespaceSelector:
15 matchExpressions:
16 - key: e2e-run
17 operator: DoesNotExist
spec.match
にどういった場合に、このConstraintが定義されているか記載されています。このルールではPodの操作がすべて定義されています。
よってまとめると
- TMCでは、自動でConstraintTemplate,Constraintsが作成され、ユーザーから透過的に操作がされる
Policy Insightsのからくり
さて、前回はPolicy Insigtsというすごい機能で、ルール違反を一覧できるというものを紹介しました。
このカラクリですが、OPAのAudit機能を使っています。
https://github.com/open-policy-agent/gatekeeper#audit
これもConstraintの中身を確認するとCLIからも確認できます。 例えば、以下のようになっている場合
1status:
2 totalViolations: 1
3 violations:
4 - enforcementAction: dryrun
5 kind: Pod
6 message: 'Sharing the host namespace is not allowed: verybad'
7 name: verybad
8 namespace: default
PolicyInsight側では以下のようになります。
つまりこの機能もOPAをつかっていることがわかります。
まとめ
- TMCのSecurity PolicyはAdmissionController、OPA、そしてConstraintTemplateとConstraintsの仕組みを使っている
- ConstraintTemplateはRegoとよばれる言語で記載できる
- OPAはPolicy Insights機能にもつかわれている
なお、全三回の予定でしたが、この記事をかいた数日後にまた新しい機能が追加されることがアナウンスされました。この内容も第四回としてまとめます。