cocoon-webhook

Overview

cocoon-webhook is a Kubernetes admission webhook that admits VM-backed pods only from the CocoonSet controller, rejects scale-down of cocoon workloads, and validates CocoonSet and CocoonHibernation resources beyond what the CRD’s OpenAPI schema can express. It hosts four admission endpoints plus health and metrics surfaces:

Endpoint Type Resources What it does
POST /mutate Mutating Pod CREATE / UPDATE Rejects pods that enter the cocoon gate (the virtual-kubelet.io/provider toleration or the vm.cocoonstack.io/name annotation) without a CocoonSet owner or without an allowlisted requester identity (POD_CREATORS); owner references are client-settable, so the authenticated requester is what actually gates. On UPDATE only a pod that newly acquires the toleration or the annotation is checked, so the operator’s and vk-cocoon’s runtime patches on gated pods pass untouched. Legitimate pods pass through unmutated.
POST /validate Validating Deployment / StatefulSet UPDATE, including the deployments/scale and statefulsets/scale subresources Rejects scale-down on cocoon-tolerated workloads. A /scale request — the ordinary kubectl scale path — makes the handler GET the parent workload to check its toleration, and it denies fail-closed (“cannot verify parent workload”) if that fetch fails. Bypass path for hand-rolled Deployments/StatefulSets carrying the cocoon toleration — the CocoonSet main flow creates Pods directly and does not traverse this endpoint.
POST /validate-cocoonset Validating CocoonSet CREATE / UPDATE Checks cross-field rules, toolbox name uniqueness, static-mode prerequisites and the derived VM/snapshot name budget. Spec-unchanged updates are skipped so finalizer cleanup remains possible. See Validation rules.
POST /validate-cocoonhibernation Validating CocoonHibernation CREATE Checks spec.desire against {Hibernate, Wake}, requires metadata.name to equal spec.podRef.name (one CR per pod, named after it, so racing duplicate CREATEs collide on name uniqueness), and rejects a CR whose pod already has one — live or still terminating — so two CRs can never fight over one VM. Retargeting an existing CR is blocked by the CRD’s CEL rule on spec.podRef. See Validation rules.
GET /healthz Liveness — Always 200 once the binary is running.
GET /readyz Readiness — Always 200 once the binary is running (liveness-equivalent stub; does not probe apiserver reachability).
GET /metrics Prometheus — Plain HTTP on :9090, separate from the admission TLS port. Exposes cocoon_webhook_admission_total{handler,result,reason}, with handler ∈ {mutate, validate, validate_cocoonset, validate_cocoonhibernation} and result ∈ {allow, deny, error, skipped}.

The /mutate and /validate registrations carry a namespaceSelector that excludes kube-system, kube-node-lease, kube-public, cocoon-system, cert-manager and sandbox-system, so a webhook outage under failurePolicy: Fail cannot block the pods those namespaces need to recover (the webhook’s own included). The flip side: a cocoon-tolerated pod or workload placed in one of them is neither gated at creation nor protected against scale-down. Cocoon workloads belong in ordinary namespaces.

sandbox-system is excluded for a different reason. The pod gate keys on the virtual-kubelet.io/provider toleration key, and a pod that tolerates a virtual-kubelet taint with operator: Exists carries no value to match on, so every virtual-kubelet provider’s pods look like cocoon VM pods here. vk-sandbox taints its node with that key and value sandboxd, and sandbox-operator’s pods have no CocoonSet owner, so without this exclusion every sandboxd-runtime Sandbox is denied. Any further provider sharing the key needs the same treatment. The /validate-cocoonset and /validate-cocoonhibernation registrations carry no namespaceSelector and gate every namespace, including cocoon-system.

The admission TLS listener reloads its certificate and key from disk whenever their mtime changes, so a cert-manager rotation lands without a pod restart.