LoginSignup
5
0

More than 1 year has passed since last update.

Validating Admission Policyを試してみた

Last updated at Posted at 2022-12-19

Validating Admission Policyとは?

Validating Admission PolicyはValidating Admission Webhookを一部代替できる機能です。Kubernetes v1.26からalpha機能として利用可能になりました。
Validating Admission PolicyはCommon Expression Language (CEL)を用いてValidationのルールを定義します。CELで表現できる範囲に限られますが、Admission Webhookと異なりkube-apiserver内で評価されるため、Admission Webhookとkube-apiserver間のネットワークの問題に影響を考えなくて良いのは大きなメリットでしょう。

Validating Admission Policyの有効化

Validating Admission Policyは新たに追加されたKubernetes APIであるadmissionregistration.k8s.io/v1alpha1を用いて設定します。これはKubernetes v1.26時点ではデフォルト無効となっているので、RuntimeConfigで有効化する必要があります。またValidating Admission Policy自体もデフォルト無効となっているため、Feature Gatesを有効化する必要があります。

kindの場合以下のような設定ファイルで、Validating Admission Policyが利用できるクラスタが作成できます。

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
  "ValidatingAdmissionPolicy": true
runtimeConfig:
  "admissionregistration.k8s.io/v1alpha1": true
nodes:
- role: control-plane
  image: kindest/node:v1.26.0

Validating Admission Policyを試す

Validating Admission Policyは最低限、ValidatingAdmissionPolicyとValidatingAdmissionPolicyBindingの2つリソースが必要となります。ValidatingAdmissionPolicyは以下のように具体的なポリシーを定義します。これはDeploymentの名前がfooから始まらないといけないというポリシーです。

apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
  name: "demo-policy.uesyn.dev"
spec:
  matchConstraints:
    resourceRules:
    - apiGroups:   ["apps"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["deployments"]
  validations:
  - expression: object.metadata.name.startsWith("foo")

上記のValidatingAdmissionPolicyは定義するだけでは利用できません。以下のようにValidatingAdmissionPolicyBindingが必要となります。具体的に以下のようなリソースを作成すると、default namespaceへ対象を絞ることができます。

apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: "demo-policy-binding.uesyn.dev"
spec:
  policyName: "demo-policy.uesyn.dev"
  matchResources:
    namespaceSelector:
      matchLabels:
        kubernetes.io/metadata.name: "default"

上記をクラスタへapplyし、Deploymentを作成してみます。

# これはValidationされ、許可される
$ kubectl --namespace default create deployment --image=nginx foo-deployment
deployment.apps/foo-deployment created

# これはValidationされ、拒否される
$ kubectl --namespace default create deployment --image=nginx bar-deployment
error: failed to create deployment: deployments.apps "bar-deployment" is forbidden: Validat
ingAdmissionPolicy 'demo-policy.uesyn.dev' with binding 'demo-policy-binding.uesyn.dev' den
ied request: failed expression: object.metadata.name.startsWith("foo")

# これはdefault namespaceではないのでValidationされない
$ kubectl --namespace kube-public create deployment --image=nginx bar-deployment
deployment.apps/bar-deployment created

ちなみにこのValidatingAdmissionPolicyの.spec.matchConstraintsとValidatingAdmissionPolicyBindingの.spec.matchResourcesは名前は異なりますが、中身の指定方法は全く同じです。1 これらの積集合がValidationの対象となるようで、もし積集合がない場合はValidationが実施されないので注意が必要です。

パラメータを利用する

Validating Admission Policyでは、Policyへ外部から値を取得するためのパラメータを利用できます。Kubernetesのオブジェクトの値を参照でき、NativeリソースだけでCustom Resourceの値も参照できる様です。パラメータを利用するには、まずどの種類のKubernetesリソースの値を参照するかをValidatingAdmissionPolicyのspec.paramKindで定義します。
先ほどの例はnameがfoo以外から始まるDeploymentの作成を拒否するものでしたが、そのfooをパラメータを用いて変更できるようにします。今回は手軽にConfigMapから値を取る様にします。パラメータはparams変数でアクセスできます。今回はConfigMapのdataへprefixというキーに設定された値を参照する設定です。

apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
  name: demo-policy.uesyn.dev
spec:
  paramKind:
    apiVersion: v1
    kind: ConfigMap
  matchConstraints:
    resourceRules:
    - apiGroups:   ["apps"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["deployments"]
  validations:
  - expression: object.metadata.name.startsWith(params.data.prefix)

具体的にどのリソースを参照するかは、ValidatingAdmissionPolicyBindingリソースのspec.paramRefで指定します。Cluster Scopedなリソースの場合はnamespaceの指定は不要です。

apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: demo-policy-binding.uesyn.dev
spec:
  paramRef:
    name: demo-policy-param
    namespace: default
  policyName: demo-policy.uesyn.dev
  matchResources:
    namespaceSelector:
      matchLabels:
        kubernetes.io/metadata.name: "default"

参照されるConfigMapは以下の様になります。今回はbarという値であれば許可されるようにします。

apiVersion: v1
kind: ConfigMap
metadata:
  name: demo-policy-param
  namespace: default
data:
  prefix: bar

上記の3つのリリースをapplyして、動作を確認します。

# barをprefixとして持つものは許可される。
$ kubectl --namespace default create deployment --image=nginx bar-deployments
deployment.apps/bar-deployments created

# bar以外をprefiとして持つものは拒否される。
$ kubectl --namespace default create deployment --image=nginx foo-deployments
error: failed to create deployment: deployments.apps "foo-deployments" is forbidden: ValidatingAdmissionPolicy 'demo-policy.uesyn.dev' with binding 'demo-policy-binding.uesyn.dev' denied request: failed expression: object.metadata.name.startsWith(params.data.prefix)

参照されるConfigMapの値をbazへ変更してみましょう。

apiVersion: v1
kind: ConfigMap
metadata:
  name: demo-policy-param
  namespace: default
data:
  prefix: baz
# bazをprefixとして持つものは許可される。
$ kubectl --namespace default create deployment --image=nginx baz-deployments
deployment.apps/baz-deployments created

# baz以外をprefixとして持つものは拒否される。
$ kubectl --namespace default create deployment --image=nginx bar-deployments
error: failed to create deployment: deployments.apps "bar-deployments" is forbidden: ValidatingAdmissionPolicy 'demo-policy.uesyn.dev' with binding 'demo-policy-binding.uesyn.dev' denied request: failed expression: object.metadata.name.startsWith(params.data.prefix)

ちなみに参照されるキーが存在しなかったり、オブジェクトが存在しないと以下の様な挙動となります。

# キーが存在しない場合
$ kubectl --namespace default create deployment --image=nginx foo-deployments
error: failed to create deployment: deployments.apps "foo-deployments" is forbidden: ValidatingAdmissionPolicy 'demo-policy.uesyn.dev' with binding 'demo-policy-binding.uesyn.dev' denied request: expression 'object.metadata.name.startsWith(params.data.prefix)' resulted in error: no such key: data

# paramRefのオブジェクトが存在しない場合
$ kubectl --namespace default create deployment --image=nginx foo-deployments
error: failed to create deployment: deployments.apps "foo-deployments" is forbidden: ValidatingAdmissionPolicy 'demo-policy.uesyn.dev' with binding 'demo-policy-binding.uesyn.dev' denied request: failed to configure binding: demo-policy-param not found

Admission Webhookと同様にValidating Admission PolicyにもfailurePolicyが設定でき、デフォルトではFailのため上記の様に評価に失敗した場合ではオブジェクトの作成はされません。ここでfailurePolicyをIgnoreへ設定を変更します。

apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
  name: demo-policy.uesyn.dev
spec:
  failurePolicy: Ignore
  ...(省略)

Ignoreを指定した場合、先ほどのオブジェクトやキーが存在しない場合でも作成が成功します。
しかしwarningなども出力されないため、これが意図しない挙動の場合は気づくことができません。

$ kubectl --namespace default create deployment --image=nginx foo-deployments
deployment.apps/foo-deployments created

最後に

CELで表現できるものであればAdmission Webhookを作ることなく手軽にValidationできるのは素敵ですね。しかし、エラーメッセージがわかりづらかったり、細かい制御をしたい場合はAdmission Webhookが必要となってきますが、積極的に利用したい機能なのは間違いありません。早くデフォルトで有効化されて欲しいですね!

  1. どちらも同じMatchResources構造体を利用しています。

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