📚

Admission Webhookのすゝめ

2022/09/10に公開

はじめに

最近公私ともにContoller開発を行うに当たり、validateやmutateを行うWebhookについて触れる機会が多いのです。そこで、自分なりに理解している範囲で現在のwebhook事情についてまとめてみます。

Webhookライブラリの種類

  • kubernetes-sigs/controller-runtime
    言わずと知れたcontroller開発ライブラリです。
    この中で提供されているwebhookを利用することで、kubebuilderなどのフレームワークでもwebhookが簡単に実装可能となっています。
  • knative/pkg/webhook
    サーバーレスな基盤を構築することが可能なknativeですが、パッケージが個別で公開されており、その中でwebhookライブラリが使用できます。若干学習コストが高いです。
  • slok/kubewebhook
    非常に軽量でシンプルなライブラリです。サンプルが提供されており、これをいじるだけで実装出来ます。上記2つと異なり、証明書の自動ローテーションを行うには工夫が必要。
  • snorwin/k8s-generic-webhook
    kubebuilderなどフレームワークで作成するwebhookによく似たコードで実装可能なシンプルなライブラリです。フレームワークでの開発経験がある方であれば、使いこなせるのではないでしょうか。

今回はシンプルで拡張性の高いkubewebhookに絞って紹介します。(私のお気に入りだからというのは内緒

特徴

実装が非常に簡単であり、ライブラリ自体のコードも読みやすく書かれています。
また、通常のvalidateやmutateだけでなく、各処理をchainとしてつなげることが可能です。

  • 以下validatorの該当箇所抜粋

https://github.com/slok/kubewebhook/blob/master/pkg/webhook/validating/validator.go

type chain struct {
	validators []Validator
	logger     log.Logger
}

// NewChain returns a new chain of validators.
// - If any of the validators returns an error, the chain will end.
// - If any of the validators returns an stopChain == true, the chain will end.
// - If any of the validators returns as no valid, the chain will end.
func NewChain(logger log.Logger, validators ...Validator) Validator {
	return chain{
		validators: validators,
		logger:     logger,
	}
}

chainを用いた実装は以下のコードを確認ください。
https://github.com/slok/kubewebhook/tree/master/examples/multiwebhook/pkg/webhook

kubewebhook提供サンプル

以下のサンプルを確認いただくと分かる通り、ほぼこれだけでmutateが完結します。
★流れ
実際のmutate処理作って

MutatorFunc()に食わせてあげて

Webhookの呼び出しをしてあげるだけ。
注意点として、処理対象のリソースの型をmetav1.Objectにアサーションしてあげるくらいです。
https://github.com/slok/kubewebhook/blob/master/examples/pod-annotate/main.go

本番で使用する場合のサンプルまであります。最高です。

https://github.com/slok/k8s-webhook-example

kubewebhookを使用した実装サンプル

Image tagが付与されていない場合にlatesttagをデフォルト値として付与するMutatorを作成してみました。(すでにkubernetesのデフォルトはlatestであると理解していますが、kubectl describeの見た目を変えたかったのです。

https://github.com/jnytnai0613/default-imagetag-webhook

出力結果

kubewebhookでmutateなりvaidateなりを行うと以下のようにjsonで出力され、opからどのようなoperationがなされたのかがわかるようになっています。今回はImage tagの書き換えをおこなったため、replaceとなっていますが、Fieldの追加を行うと、addと出力されます。また、どのような変更がされたかも確認可能となっており、非常に親切なログの出し方と思います。

$ kubectl logs default-imagetag-webhook-5bd6b8b685-t26t4 -f
time="2022-07-11T00:41:14Z" level=info msg="Listening on :8080"
time="2022-07-11T00:42:12Z" level=debug msg="Webhook mutating review finished with: '[{\"op\":\"replace\",\"path\":\"/spec/containers/0/image\",\"value\":\"nginx:latest\"}]' JSON Patch" dry-run=false kind=v1/Pod name= ns=default op=create path=/mutate request-id=682f8ab2-6ace-4663-a748-96299cf4f650 trace-id= webhhok-type=mutating webhook-id=imageTagMutator webhook-kind=mutating wh-version=v1
time="2022-07-11T00:42:12Z" level=info msg="Admission review request handled" dry-run=false duration=276.777541ms kind=v1/Pod name= ns=default op=create path=/mutate request-id=682f8ab2-6ace-4663-a748-96299cf4f650 svc=http.Handler trace-id= webhook-id=imageTagMutator webhook-kind=mutating wh-version=v1

証明書ローテーションについて

WebhookのPodとkube-apiserver[1]間はTLSで認証にて通信を行います。
そのため、kube-apiserverで証明書がローテーションされる[2]と、Webhook PodにあるHTTPサーバの証明書も何らかの方法でローテーションしてあげる必要があります。
ただ、kubewebhookには証明書の自動ローテーション機能は実装されていません。
そこで、contoroller-runtimeのcertwatcherを利用することで自動ローテーションが可能です。
https://github.com/kubernetes-sigs/controller-runtime/tree/master/pkg/certwatcher

使い方は、同じくcontoroller-runtimeのpkg/webhook/server.goをご確認ください。

https://github.com/kubernetes-sigs/controller-runtime/blob/master/pkg/webhook/server.go#L212-L296

certwatcherは証明書の変更を監視しており、変更があるとロード対象の証明書を変更します。
そして、webhook側はcertWatcher.GetCertificateでtls.ClientHelloInfoを待ち受けているので、リクエストがあるたびに証明書をロードします。そのため、常に最新の証明書が使えるというわけです。

func (s *Server) Start(ctx context.Context) error {
:
	cfg := &tls.Config{ //nolint:gosec
		NextProtos:     []string{"h2"},
		GetCertificate: certWatcher.GetCertificate,
		MinVersion:     tlsMinVersion,
	}
:

参考リンク

https://github.com/kubernetes-sigs/controller-runtime/tree/master/pkg/webhook
https://github.com/knative/pkg/tree/main/webhook
https://github.com/slok/kubewebhook
https://github.com/snorwin/k8s-generic-webhook

脚注
  1. ここでいうkube-apiserverとはValidatingWebhookConfigurationやMutatingWebhookConfigurationを指します。 ↩︎

  2. ValidatingWebhookConfigurationやMutatingWebhookConfigurationの証明書のローテーションはcert-managerで自動で行うか、自前で行うかの2択です。 ↩︎

Discussion