blog.anqou.net
rss
author
tags

ValidatingAdmissionPolicy で PVC の誤削除を防ぐ

Kubernetes 1.30 から GA になった ValidatingAdmissionPolicy を使うと、リソースへの操作に対して validation をかけることができます。ここでは、特定のアノテーションがついている PVC に対して削除が実行されようとしたときにそれを弾くことで、PVC の誤削除を防ぐようにしてみます。

まず以下のような ValidatingAdmissionPolicy リソースを作ります:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: prevent-deletion.admission.ket.anqou.net
  namespace: admission
spec:
  matchConstraints:
    resourceRules:
      - apiGroups:
          - ""
        apiVersions:
          - v1
        operations:
          - DELETE
        resources:
          - persistentvolumeclaims
  validations:
    - expression: |
        !("admission.ket.anqou.net/prevent-deletion" in variables.annots) ||
        variables.annots["admission.ket.anqou.net/prevent-deletion"] != "true"
      message:
        all pvcs annotated with "admission.ket.anqou.net/prevent-deletion" must
        not be deleted
  variables:
    - expression:
        "has(oldObject.metadata.annotations) ? oldObject.metadata.annotations
        : {}"
      name: annots
  failurePolicy: Fail

.spec.matchConstraints を使い、どのリソースに対するどういった操作に干渉したいかを書きます。ここでは persistentvolumeclaims に対する DELETE を対象にします。

.spec.validations に validation を書きます。記述言語として CEL が採用されています。ここでは admission.ket.anqou.net/prevent-deletion: true という annotation がついていないことを記述しています。なお、式中では variables.annots という変数を使っています。この変数の定義は .spec.variables に書いています。

.spec.failurePolicy で、validation が失敗したときの挙動を決定できます。Fail にしておくと、操作(今回なら DELETE)を失敗させます。

さて、上記のように作った ValidatingAdmissionPolicy を有効化するためには ValidatingAdmissionPolicyBinding リソースを作り、どの namespace に対して有効化するかを決める必要があります。今回はすべての namespace に存在する PVC に対して動いてほしいので、以下のような ValidatingAdmissionPolicyBinding を作ります:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: prevent-deletion.admission.ket.anqou.net
  namespace: admission
spec:
  policyName: prevent-deletion.admission.ket.anqou.net
  validationActions:
    - Deny

実際に使ってみます。Minikube v1.34.0 を使って Kubernetes v1.30.5 の環境を作り、上 2 つのリソースを apply します。その後 PVC を作り、それに admission.ket.anqou.net/prevent-deletion annotation をつけた上で、削除を試みると、失敗することが分かります:

$ cat <<EOS | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  annotations:
    admission.ket.anqou.net/prevent-deletion: "true"
  name: test-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: topolvm-provisioner
EOS

persistentvolumeclaim/test-pvc created

$ kubectl delete pvc test-pvc
The persistentvolumeclaims "test-pvc" is invalid: : ValidatingAdmissionPolicy 'prevent-deletion.admission.ket.anqou.net' with binding 'prevent-deletion.admission.ket.anqou.net' denied request: all pvcs annotated with "admission.ket.anqou.net/prevent-deletion" must not be deleted