Kyvernoとは?
Kyvernoは、Validation(検証機能)とMutation(ミューテーション = 追加、更新、削除)機能を備えたKubernetesポリシーエンジンです。いわゆるPolicy-as-code(PaC)ソリューションの1つです。もともとNirmataからのオープンソースプロジェクトであり、後にCNCFに寄贈されているようです。
追記 2022/7/13: KyvernoはCNCF incubating Projectになりました - Kyverno moves to the CNCF Incubator
Kuberentesにおける代表的なPolicy as Code (PaC)ソリューションの紹介
ちなみに、2022 InfoQ Trends Report によると、Policy as Code (PaC)は Early Adoptersとして報告されています。参考までにKyverno以外で有名なPolicy as Code (PaC)ソリューションを2つ紹介します。
Pod Security Policies (PSP)
Kubernetesのポリシー機能といえば、 Pod Security Policies (PSP)があります。 PSPはPodとその属性に対して一連のValidation機能を提供します。その名前のとおり、Podに対する機能であり、Podの作成や更新に対して制御はできるが、Mutation機能は提供しません。残念ながらPSPはKubernetes v1.21でdeprecatedとなり、v1.25で削除の予定となっています。
Open Policy Agent (OPA) / Gatekeeper
Open Policy Agent (以下、OPA)は汎用的なポリシーエンジン機能を提供するOSSで、Regoと呼ばれるカスタム言語を介してKubernetesだけでなく、さまざまなプラットフォームで汎用的な利用が可能です。これもPolicy-as-code(PaC)ソリューションの1つです。Gatekeeperは、Kubernetesに特化したOPAの実装ソリューションであり、リクエストのValidation(検証機能)と、最近ではMutation(ミューテーション = 追加、更新、削除)機能も提供します。
KyvernoとOPA/Gatekeeperの機能比較
Kubernetes Policy Comparison: OPA/Gatekeeper vs Kyverno記事に分かりやすい機能比較テーブルがあったのでそれを貼り付けておきます。
(Source: Kubernetes Policy Comparison: OPA/Gatekeeper vs Kyverno)
事前準備
それではようやく本題であるKyvernoを活用して特定条件にマッチするKuberentesリソースにポリシーを適用する試験を行っていきます。 まずは、デプロイ先となるk8sクラスタとkyvernoのインストールを行います。
KINDでKubernetesクラスタ作成
k8sクラスタをkind (Kubernetes in Docker)でローカルに構築します。
まずは、次のようなcontrol planeノード x 1、 workerノード x 1のk8sクラスタのためのkindクラスタ構成ファイル(cluster.yaml)を作成します。
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
次に、kind cliコマンドで、k8s v1.21.10のノードイメージでk8sクラスタを作成します。
K8S_NODE_IMAGE=v1.21.10
kind create cluster --name my-kind-cluster \
--image=kindest/node:${K8S_NODE_IMAGE} \
--config cluster.yaml
クラスタ構築が完了したら念の為にクラスタにアクセスしてみます。
kubectl get node
NAME STATUS ROLES AGE VERSION
my-kind-cluster-control-plane Ready master 37m v1.21.10
my-kind-cluster-worker Ready <none> 37m v1.21.10
kyvernoのインストール
QuickStartに従い下記のように作成したクラスタにkyvernoをインストールします。なお、他にもHelm chartからのインストールも可能です。詳しくはQuickStartください。
kubectl create -f https://raw.githubusercontent.com/kyverno/kyverno/main/config/install.yaml
kyvernoで特定ネームスペース作成されるPodにラベルを追加する
いよいよ本題の試験を行います。kyvernoのk8sリソースのMutateルール機能をつかって特定ネームスペース作成されるPodにラベルを追加してみます。
なお、mutateルールは、指定する条件にマッチするリソースを変更するために使用でき、以下のRFC 6902 JSONパッチ、もしくはStrategic mergeパッチのいづれかの方式が利用可能です。
-
patchesStrategicMerge
- Strategic Merge PatchというKubernetes独自のマージの方法
- 追加、置き換え、削除が可能。patchesJson6902よりはシンプルに記述が可能
-
patchesJson6902
- JSONPatch - RFC 6902 formatフォーマットでマージ記述が可能。
- patchesStrategicMergeと比べて細やかな指定が可能。追加、置き換え、削除が可能
また、補足情報として、ポリシーとルールの関係を説明します。
- ポリシーはルールの集合である。
- 各ルールは
match
宣言と、オプショナルでexclude
宣言と,validate
,mutate
,generate
, もしくはverifyImages
宣言のいづれか1つで構成される - ポリシーは、クラスター全体のリソース(kind:
ClusterPolicy
)またはネームスペースごとのソース(kind:Policy
)として定義できる。
(Source: https://kyverno.io/docs/kyverno-policies/)
ClusterPolicyポリシーをデプロイ(patchesStrategicMerge)
ここでは、match
とmutate
宣言で構成されるルールを含むClusterPolicy
リソースを作成します。また、パッチ方式にはpatchesStrategicMerge
を指定します。
次のように、set-label-policy
という名前のClusterPolicyリソースをクラスタにデプロイします。 このClusterPolicyリソースにはネームスペースtestns1
に作成されるPodに、foo=bar
というラベルを追加するルールを定義しています。
kubectl apply -f - << EOF
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: "set-label-policy"
spec:
rules:
- name: "set-label"
match:
any:
- resources:
kinds:
- Pod
namespaces:
- testns1
mutate:
patchStrategicMerge:
metadata:
labels:
foo: bar
EOF
サンプルPodをデプロイしポリシーが適用されることを確認する
まずは、テストで利用するネームスペース(testns1
とtestns2
)を作成します。
create namespaces
kubectl apply -f - << EOF
apiVersion: v1
kind: Namespace
metadata:
name: testns1
---
apiVersion: v1
kind: Namespace
metadata:
name: testns2
EOF
次に、サンプルアプリケーションのマニフェストをapp.yamlに出力します。
cat << EOF > app.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: httpbin
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
spec:
ports:
- name: http
port: 8000
targetPort: 80
selector:
app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
template:
metadata:
labels:
app: httpbin
spec:
serviceAccountName: httpbin
containers:
- image: docker.io/kennethreitz/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
command: ["gunicorn", "--access-logfile", "-", "-b", "0.0.0.0:80", "httpbin:app"]
ports:
- containerPort: 80
EOF
testns1
とtestns2
の両ネームスペースにサンプルアプリケーションをデプロイします。
kubectl apply -f app.yaml -n testns1
kubectl apply -f app.yaml -n testns2
最後に、下記のように両ネームスペースにデプロイされたPodのラベルをチェックします。
kubectl get po -n testns1 --show-labels
NAME READY STATUS RESTARTS AGE LABELS
httpbin-6fdcdc89fc-b9wl6 1/1 Running 0 8m56s app=httpbin,foo=bar,pod-template-hash=6fdcdc89fc
kubectl get po -n testns2 --show-labels
NAME READY STATUS RESTARTS AGE LABELS
httpbin-75bc8bcf78-p7m4l 1/1 Running 0 9m58s app=httpbin,pod-template-hash=75bc8bcf78
無事、ClusterPolicyset-label-policy
のルールが適用され、testns1に作成されたPodにfoo=bar
というラベルを追加されていることがわかります。
patchesJson6902パッチ方式のClusterPolicyポリシー
参考までに、上述しているClusterPolicyポリシーと同じ振る舞いをpatchesJson6902パッチ方式で定義すると次のようになります。
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: "set-label-policy"
spec:
rules:
- name: "set-label"
match:
any:
- resources:
kinds:
- Pod
namespaces:
- testns1
mutate:
patchesJson6902: |-
- path: "/metadata/labels/foo"
op: add
value: "bar"
その他補足情報
Policy制御のためのオプション
Policyにはルールとは別に下記のPolicyの振る舞いを制御するオプションの設定が可能です。
-
validationFailureAction: Validationポリシールールを追加した場合、その失敗により、Admission Reviewリクエストをブロック(
enforce
)するか、Admission Reviewリクエストを許可(audit
)して、ポリシーレポートでポリシーの失敗を報告するかを制御する。 デフォルトはaudit
- validationFailureActionOverrides: ネームスペースごとにClusterPolicy属性として指定するvalidationFailureAction。 特定ネームスペースに指定されたvalidationFailureActionをオーバーライドする。
-
background: バックグランドのスキャンにより既存のリソースに対してもポリシー適用するかどうかを指定.デフォルトは
true
-
schemaValidation: Policyのvalidationチェックを適用するかどうかを制御。 デフォルトは
true
。KyvernoはPolicyのスキーマのValidationを試み、そのリソースのOpenAPIスキーマ定義を満たしていると判断できない場合は失敗する。 ValidationまたはMutationのPolicyが該当。 スキーマのValidationをスキップするにはfalse
に設定する -
failurePolicy: defines the API server behavior if the webhook fails to respond. Allowed values are “Ignore” or “Fail”. Defaults to “Fail”. Webhookが応答失敗した場合のAPIサーバーの挙動を定義。
Ignore
orFail
を指定可能。 デフォルトはFail
。 -
webhookTimeoutSeconds: このPolicy適用のタイムアウトを秒単位で指定。 デフォルトのタイムアウトは
10秒
(値:1〜30秒)
(Source: Policy Settings)
特に個人的に重要だと思ったオプションとして、backgroundがあります。これをtrue
にすると、既存のリソースに対してもポリシーの適用ができます。また、validationFailureActionやfailurePolicyも忘れず見ておきたいオプションかと思います。