1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Gatekeeperを使ってみた

Last updated at Posted at 2021-01-24

Gatekeeperとは

  • GatekeeperとはOpen Policy Agentのポリシーエンジンの一種であり、Kubernetesクラスタ内でのリソース作成時にポリシーを課すことができ、ポリシーを満たさないリソースの作成を防止してくれるツールです。例えば、「Deploymentにはappタグが必要である」というポリシーを課すことで、そのポリシーを満たさないDeploymentがクラスタに作成されることを防いでくれます。

  • これはAdmission WebhooksのValidationを行う際にポリシーを満たしているかのチェックが行われることで実現されています。そのため、kubectlhelm install、CRD(Custom Resource Definition)からの作成など、あらゆるデプロイ方法に適用されます。

  • 他の代表的なポリシーエンジンとして、Conftestが知られています。こちらはコマンドラインからマニフェストファイルがポリシーを満たしているかをチェックするツールであり、主にCIで使用されています。ただし、ConftestだけだとCRDがクラスタ内部で作成するリソースなど、明示的にマニフェストに明記されていないリソースまでチェックすることができません。そのため、ConftestとGatekeeperを両方とも使用してリソースにポリシーを課す運用がベターだと思います。なお、どちらのツールでもRegoという言語を使用してポリシーを記述します。

インストール

  • Helmでインストールする方法が簡単です。
$ helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
$ helm install gatekeeper/gatekeeper --generate-name
  • これにより必要なリソースと、いくつかのCRDが定義されます。

ポリシーの作成

  • 実際にポリシーを作ってみます。ここでは、Nodeが行う排出処理が成功するよう、pdb(PodDisruptionBudget)のmaxUnavailableに0より大きい値が設定されていることを課すポリシーを作成してみます。主に必要なリソースは以下の2つです。
  • ConstraintTemplate
    • constraintの雛形であり、Regoで記載したポリシーを併せて定義します。これを作成することで、spec.crd.spec.names.kindで定義したCRDが作成されます。
    • targets.regoにポリシーが記載されています。詳細は省略しますが、ポイントは以下の通りです。
      • ルールの名前はviolationである必要があります。
      • input.reviewに適用されるマニフェストの内容が設定されています。ここの値はポリシーを課すリソースによって変更する必要があります。設定の内容については後述。
      • :=は代入を意味し、ここではmaxUnavailableという変数にmaxUnavailableの値を代入しています。
      • maxUnavailableの数値を評価して結果をokという変数に代入し、それを配列satisfiedの要素としています。
      • not allが評価を行っている箇所になります。allは全ての要素がtrueだとtrueを返す関数であり、そこにnotが付与されているため、条件を満たさない場合にtrueを返すことになります。
      • msgはtrueのとき(必要なポリシーを満たしていないとき)に出力するメッセージであり、必須のパラメータです。
constraintTemplate.yaml
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: pdbmaxunavailable
spec:
  crd:
    spec:
      names:
        kind: PdbMaxUnavailable
      validation:
        openAPIV3Schema:
          properties:
            maxUnavailable:
              type: integer
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package pdbmaxunavailable
       
        violation[{"msg": msg, "details": {}}] {
          maxUnavailable := input.review.object.spec.maxUnavailable
          satisfied := [ok | ok := maxUnavailable > 0]
          not all(satisfied)
          msg := "maxUnavailable must be bigger than 0."
        }  
  • PdbMaxUnavailable
    • 上記のConstraintTemplateで定義したConstraintです。
    • spec.match.kinds.kindsで対象のリソースを、spec.match.kinds.apiGroupsでリソースのAPI Groupを指定します。
pdbMaxUnavailable.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: PdbMaxUnavailable
metadata:
  name: maxunavailable-must-be-bigger-than-zero
spec:
  match:
    kinds:
      - apiGroups: ["policy"]
        kinds: ["PodDisruptionBudget"]

稼働確認

  • 上記のconstraintTemplate.yamlpdbMaxUnavailable.yamlをapplyし、pdbを作成します。
  • その後、以下のようにポリシーを満たさないpdbの作成を試みます。
fail/pdb.yaml
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: sample-app
spec:
  maxUnavailable: 0
  selector:
    matchLabels:
      app: sample-app
  • applyするとConstraintTemplateで定義したメッセージが出力され、リソースの作成が失敗します。
Error from server ([denied by maxunavailable-must-be-bigger-than-zero] maxUnavailable must be bigger than 0.): error when creating "fail/pdb.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [denied by maxunavailable-must-be-larger-than-zero] maxUnavailable must be bigger than 0.

その他

デバッグ

  • 上述の通り、ConstraintTemplateを作成する際にinput.review内の要素を指定する必要がありますが、リソース毎に構成が異なるため、設定前に確認する必要があります。これはmsgの出力にinput.reviewを指定したConstraintTemplateを作成することで確認できます。特に条件を指定していないため、全てのpdbの作成時にメッセージが出力されます。
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8sdenyall
spec:
  crd:
    spec:
      names:
        kind: K8sDenyAll
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sdenyall

        violation[{"msg": msg}] {
          msg := sprintf("REVIEW OBJECT: %v", [input.review])
        }

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDenyAll
metadata:
  name: deny-all-pdb
spec:
  match:
    kinds:
      - apiGroups: ["policy"]
        kinds: ["PodDisruptionBudget"]
  • 適当なpdbを作成しようとすると、以下のようにinput.review以下の要素が出力され、この内容を基に評価対象のオブジェクトをRegoで記載しましょう。やや面倒な手順ですが、READMEにも記載されている方法ですので、現状はこの方法しかないようです。
inupt.review(抜粋)
  "object": {
    "apiVersion": "policy/v1beta1",
    "kind": "PodDisruptionBudget",
    "metadata": {
      "name": "myapp",
      "namespace": "default",
      "uid": "da6b703c-83d6-4488-910c-c7492343eddc",
      "generation": 1,
    "spec": {
      "selector": {
        "matchLabels": {
          "run": "myapp"
        }
      },
      "maxUnavailable": 0
    },
  }

リソース作成が失敗した際のログ

  • デフォルトの設定だと、Gatekeeperによってポリシーを満たさないリソース作成が阻止されてもログが出力されません。出力するためにはgatekeeper-controller-managerというDeploymentで、コンテナのargsに--log-deniesを指定する必要があります。
  • リソースの作成が阻止されると以下のようなログが確認できます。
{"level":"info","ts":1611475124.4214969,"logger":"webhook","msg":"denied admission","process":"admission","event_type":"violation","constraint_name":"maxunavailable-must-be-bigger-than-zero","constraint_group":"constraints.gatekeeper.sh","constraint_api_version":"v1beta1","constraint_kind":"PdbMaxUnavailable","constraint_action":"deny","resource_group":"policy","resource_api_version":"v1beta1","resource_kind":"PodDisruptionBudget","resource_namespace":"default","resource_name":"sample-app","request_username":xxxxx"}

まとめ

  • Kubernetesクラスタ内でリソースにポリシーを課し、それを満たさない場合にはリソースの作成を阻止するGatekeeperについてpdbを例として記載しました。
  • ConstraintTemplateにてRegoでポリシーを記載し、Constraintで対象のリソースを指定することで、クラスタ内のリソース作成に関するポリシーを適用することができます。

参考

1
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?