gashirar's blog

ウイスキーがすき/美味しいものがすき/k8sがすき

Kubernetes Admission Webhook覚書き

はじめに

KubernetesのAdmission Webhookを改めて調べたので、その忘備録です。

Dynamic Admission Controlとは

下記参照

kubernetes.io

kubernetes.io

f:id:gashirar:20201031113614p:plain

上記の図にあるように、KubernetesAPI Serverにリクエストが来た際に

  • オブジェクトの変更(Mutating)
  • オブジェクトの検証(Validating)

が行われます。Kubernetesでは、ここにユーザ独自の処理を挟むことが可能です。
IstioのEnvoy SidecarのInjectionもこのあたりの機能を利用して実装されています。

Mutating Admission Webhookの導入

GitHub - morvencao/kube-mutating-webhook-tutorial: A Kubernetes mutating webhook server that implements sidecar injection

上記リポジトリをもとにMutating Webhookの仕組みを見ていきます。

Webhookの登録

API Serverから他のWebhook Serverに処理をさせるために、API ServerにWebhookの登録を行う必要があります。
Webhookの設定のためのMutatingWebhookConfiguration Resourceが提供されているので、これを使ってをクラスタに登録しましょう。

※20201031現在、MutatingWebhookConfigurationv1になっているので、v1beta1とはパラメータが異なる場合があります。

apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
metadata:
  name: sidecar-injector-webhook-cfg
  labels:
    app: sidecar-injector
webhooks:
- name: sidecar-injector.morven.me
  clientConfig:    # 1
    service:
      name: sidecar-injector-webhook-svc
      namespace: sidecar-injector
      path: "/mutate"
    caBundle: ${CA_BUNDLE}
  rules:    # 2
  - operations: ["CREATE", "UPDATE"]
    apiGroups: [""]
    apiVersions: ["v1"]
    resources: ["pods"]
  namespaceSelector:    # 3
    matchLabels:
      sidecar-injection: enabled

主なポイントは3つです。

  1. Webhook Serverへの通信経路情報
    • sidecar-injector Namespaceに存在するsidecar-injector-webhook-svc Serviceの/mutateにリクエストを送る
  2. Webhook Serverへ送るトリガ
    • PodCREATEUPDATEのリクエストの場合にWebhook Serverへとリクエストを送る
  3. Webhookの対象の制御設定
    • sidecar-injection: enabledが設定されたNamespaceのPodのみ処理の対象とする

上記ではKubernetesクラスタ内のServiceに処理を送ることになりますが、外部のサーバでも可能です。
namespaceSelector以外にもobjectSelectorによるコントロールができたり、Webhookへ到達できなかったなどの想定外の障害時に後続の処理をどうするかなどのfailurePolicyなどの設定もできます。
詳しくはAPI Referenceを参考にしてください。

Webhook Serverのサーバ証明書の作成

API ServerからWebhook Serverへの通信はHTTPS通信で行う必要があるので、Webhook Serverのためのサーバ証明書を作成します。上記リポジトリではCertificateSigningRequest Resourceを利用してKubernetesのCAを使ってサーバ証明書(と鍵)を作成しているようですが、独自でつくっても問題ないです。 (余談ですが、こういった「証明書を作るためのAPI」「それを承認するためのAPI」が用意されているところがプラットフォームという感じがします)

作成したサーバ証明書と鍵はSecretにしたうえでコンテナからマウントする方式になっていますね。

Webhook Serverの処理

Webhook ServerはAPI ServerからAdmissionReviewを受け取り、その中のAdmissionResponseにpatchを格納して返却します。
下記処理でAdmissionReviewAdmissionRequestからPodの情報を取り出して処理をしていることがわかるかと思います。

func (whsvr *WebhookServer) mutate(ar *v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {
    req := ar.Request
    var pod corev1.Pod
    if err := json.Unmarshal(req.Object.Raw, &pod); err != nil {
        glog.Errorf("Could not unmarshal raw object: %v", err)
        return &v1beta1.AdmissionResponse{
            Result: &metav1.Status{
                Message: err.Error(),
            },
        }
    }

    glog.Infof("AdmissionReview for Kind=%v, Namespace=%v Name=%v (%v) UID=%v patchOperation=%v UserInfo=%v",
        req.Kind, req.Namespace, req.Name, pod.Name, req.UID, req.Operation, req.UserInfo)

    // determine whether to perform mutation
    if !mutationRequired(ignoredNamespaces, &pod.ObjectMeta) {
        glog.Infof("Skipping mutation for %s/%s due to policy check", pod.Namespace, pod.Name)
        return &v1beta1.AdmissionResponse{
            Allowed: true,
        }
    }

    // Workaround: https://github.com/kubernetes/kubernetes/issues/57982
    applyDefaultsWorkaround(whsvr.sidecarConfig.Containers, whsvr.sidecarConfig.Volumes)
    annotations := map[string]string{admissionWebhookAnnotationStatusKey: "injected"}
    patchBytes, err := createPatch(&pod, whsvr.sidecarConfig, annotations)
    if err != nil {
        return &v1beta1.AdmissionResponse{
            Result: &metav1.Status{
                Message: err.Error(),
            },
        }
    }

    glog.Infof("AdmissionResponse: patch=%v\n", string(patchBytes))
    return &v1beta1.AdmissionResponse{
        Allowed: true,
        Patch:   patchBytes,
        PatchType: func() *v1beta1.PatchType {
            pt := v1beta1.PatchTypeJSONPatch
            return &pt
        }(),
    }
}

kube-mutating-webhook-tutorial/webhook.go at master · morvencao/kube-mutating-webhook-tutorial · GitHub

f:id:gashirar:20201031140511p:plain

まとめ

  • AdmissionReviewを受け取ってAdmissionResponseを(AdmissionReviewにつめて)返却するサーバを構築し、
  • Webhookの実行ルールをMutatingWebhookConfigurationに記載する

拡張しやすい作りになっていてたすかります。