How It Works
The PandoCore admission webhook uses Kubernetes' MutatingAdmissionWebhook API to automatically inject the PandoCore sidecar into pods at creation time.
When a pod is created with the label pandocore.xyz/protect: "true", the webhook intercepts the request and adds:
- The
pando-sidecarcontainer with health probes, resource limits, and security context shareProcessNamespace: true(required for /proc-based entropy collection)- The
pando-sidecarservice account reference - License key from a Kubernetes Secret (not inline)
- Downward API environment variables (
POD_NAME,POD_NAMESPACE)
This is the same injection performed by inject-pandocore.sh, but automated cluster-wide.
Label Reference
| Label / Annotation | Type | Values | Description |
|---|---|---|---|
pandocore.xyz/protect |
Label | "true" |
Enables sidecar injection for pods with this label |
pandocore.xyz/mode |
Annotation | "monitor", "enforce", "debug" |
Overrides the default operating mode for this pod |
Configuration
The webhook is configured via Helm values:
| Value | Default | Description |
|---|---|---|
licenseKey |
(required) | Your PandoCore license key |
defaultMode |
monitor |
Default operating mode for injected sidecars |
excludedNamespaces |
[kube-system, kube-public, kube-node-lease] |
Namespaces where injection is always skipped |
sidecar.image |
Latest sidecar from registry | Sidecar container image to inject |
replicas |
2 |
Webhook server replicas (2 recommended for HA) |
tls.certManager |
false |
Use cert-manager for TLS (otherwise self-signed) |
Per-Namespace Setup
Each namespace with protected pods needs two resources:
# 1. ServiceAccount for the sidecar
kubectl create serviceaccount pando-sidecar -n your-namespace
# 2. RoleBinding to the cluster-wide sidecar ClusterRole
kubectl create rolebinding pando-sidecar \
--clusterrole=pando-sidecar \
--serviceaccount=your-namespace:pando-sidecar \
-n your-namespace
# 3. Copy the license Secret into the namespace
kubectl create secret generic pando-license \
--from-literal=license-key="YOUR_LICENSE_KEY" \
-n your-namespace
Upgrading
# Upgrade the webhook (picks up new sidecar image + webhook config)
helm upgrade pando-webhook \
oci://us-central1-docker.pkg.dev/pandocore-prod/charts/pando-webhook \
--namespace pando-system \
--set licenseKey="YOUR_LICENSE_KEY"
# Existing pods are NOT affected. To inject the new sidecar version,
# restart protected deployments:
kubectl rollout restart deployment/your-app -n your-namespace
Troubleshooting
Sidecar not being injected
- Verify the label:
kubectl get pod <name> --show-labels - Check the namespace is not excluded:
helm get values pando-webhook -n pando-system - Check webhook logs:
kubectl logs -n pando-system -l app.kubernetes.io/name=pando-webhook - Verify the webhook is registered:
kubectl get mutatingwebhookconfigurations
TLS certificate issues
- Check the TLS setup job completed:
kubectl get jobs -n pando-system - Verify the TLS secret exists:
kubectl get secret -n pando-system | grep tls - If using cert-manager, check the Certificate resource:
kubectl get certificates -n pando-system
Pod creation failing
The webhook is configured with failurePolicy: Ignore, so webhook failures will not block pod creation. If pods are failing for other reasons after injection, check:
- The license Secret exists in the pod's namespace
- The
pando-sidecarServiceAccount exists in the pod's namespace - The sidecar image is pullable (check image pull secrets)