准备证书
创建cert.yaml,内容如下,执行kubectl apply -f cert.yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: admission-webhook-demo-issuer
namespace: default
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: admission-webhook-demo-tls-secret
namespace: default
spec:
duration: 8760h
renewBefore: 8000h
subject:
organizations:
- xx.com
commonName: admission-webhook-demo.default
isCA: false
privateKey:
algorithm: RSA
encoding: PKCS1
size: 2048
usages:
- digital signature
- key encipherment
- server auth
dnsNames:
- admission-webhook-demo
- admission-webhook-demo.default
- admission-webhook-demo.default.svc
- admission-webhook-demo.default.svc:443
issuerRef:
kind: Issuer
name: admission-webhook-demo-issuer
secretName: admission-webhook-demo-certs
准备webhook
webhook内annotations的cert-manager.io/inject-ca-from对应的值一定要和上面的Certificate的namespace和name一致
创建webhook.yaml,内容如下,执行kubectl apply -f webhook.yaml
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: validation-webhook-demo-cfg
annotations:
cert-manager.io/inject-ca-from: default/admission-webhook-demo-tls-secret
webhooks:
- name: tenant-labels.xx.com
admissionReviewVersions:
- v1
clientConfig:
caBundle: ""
service:
name: admission-webhook-demo
namespace: default
port: 443
path: /pods/validate
rules:
- operations: ["CREATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
namespaceSelector:
matchLabels:
admission-webhook-demo: enabled
failurePolicy: Fail
matchPolicy: Exact
sideEffects: None
demo
创建main.go,内容如下,构建镜像webhook-demo:v0.1
package main
import (
"context"
"net/http"
"log/slog"
admissionv1 "k8s.io/api/admission/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)
var (
scheme = runtime.NewScheme()
)
func init() {
clientgoscheme.AddToScheme(scheme)
}
func main() {
server := webhook.NewServer(webhook.Options{
CertDir: "/tls",
})
decoder := admission.NewDecoder(scheme)
server.Register("/pods/validate", &webhook.Admission{Handler: &podValidationHandler{decoder}})
if err := server.Start(ctrl.SetupSignalHandler()); err != nil {
slog.Error("failed to Start", "err", err)
return
}
}
type podValidationHandler struct {
decoder *admission.Decoder
}
func (h *podValidationHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
switch req.Operation {
case admissionv1.Create:
return h.HandleCreate(ctx, req)
default:
return webhook.Allowed(string(req.Operation))
}
}
func (h *podValidationHandler) HandleCreate(ctx context.Context, req admission.Request) admission.Response {
pod := &corev1.Pod{}
if err := h.decoder.Decode(req, pod); err != nil {
return webhook.Errored(http.StatusBadRequest, err)
}
if len(pod.Labels) == 0 {
return webhook.Denied("missing labels")
}
if pod.Labels["tenant"] != "dev" {
return webhook.Denied("invalid tenant")
}
return admission.Allowed("allowed")
}
创建service.yaml,内容如下,执行kubectl apply -f service.yaml
apiVersion: v1
kind: Service
metadata:
name: admission-webhook-demo
namespace: default
spec:
ports:
- port: 443
protocol: TCP
targetPort: 9443
selector:
app: admission-webhook-demo
type: ClusterIP
创建deployment.yaml,内容如下,执行kubectl apply -f deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: admission-webhook-demo
namespace: default
spec:
selector:
matchLabels:
app: admission-webhook-demo
template:
metadata:
labels:
app: admission-webhook-demo
spec:
containers:
- image: webhook-demo:v0.1
name: app
volumeMounts:
- mountPath: /tls
name: tls
readOnly: true
dnsPolicy: ClusterFirst
volumes:
- name: tls
secret:
defaultMode: 420
secretName: admission-webhook-demo-certs












网友评论