Feature Description
Summary
Change the mutating webhook from targeting workload objects (Deployments, StatefulSets, DaemonSets, Jobs, CronJobs) to targeting Pods at CREATE time. This is the pattern used by Istio, Linkerd, and Vault Agent Injector, and eliminates GitOps drift caused by mutating the workload object stored in etcd.
This change is part of the Summit MVP for the CR-triggered injection model (see design proposal PR #770).
Motivation
The current webhook intercepts workload objects and mutates the PodTemplateSpec inside them. This causes two problems:
-
GitOps drift: Argo CD, Flux, and other GitOps tools compare the workload object in Git with the object in the cluster. The webhook-injected sidecars appear in the cluster's Deployment but not in Git, triggering drift detection and potential revert loops.
-
Ownership conflict: The Deployment object is owned by the developer (or GitOps tool). Mutating it at admission time mixes platform concerns (sidecar injection) into a developer-owned resource.
Targeting Pods at CREATE time solves both:
- The Deployment in etcd stays exactly as the developer defined it
- Sidecars are only visible at the Pod level (
kubectl get pod -o yaml)
- GitOps tools see no drift because the Deployment object is unchanged
Current behavior
MutatingWebhookConfiguration (config/webhook/manifests.yaml):
rules.resources: deployments, statefulsets, daemonsets, jobs, cronjobs
rules.apiGroups: apps, batch
rules.operations: CREATE, UPDATE
Webhook handler (internal/webhook/v1alpha1/authbridge_webhook.go):
Handle() switches on req.Kind.Kind (Deployment, StatefulSet, DaemonSet, Job, CronJob)
- Extracts
PodSpec from each workload type's template
- Passes
PodSpec to injector.PodMutator.InjectAuthBridge()
- Marshals the mutated workload object back
Proposed Solution
Required changes
1. MutatingWebhookConfiguration
File: config/webhook/manifests.yaml
2. Webhook handler
File: internal/webhook/v1alpha1/authbridge_webhook.go
3. AgentRuntime CR lookup (new)
File: internal/webhook/v1alpha1/authbridge_webhook.go or new file
4. Injector updates
File: internal/webhook/injector/pod_mutator.go
5. Tests
Files: internal/webhook/v1alpha1/webhook_suite_test.go, internal/webhook/injector/pod_mutator_test.go
6. Helm chart
Files: charts/kagenti-webhook/
7. Documentation
Progress tracker
Phase 1: Core webhook change
Phase 2: AgentRuntime CR integration
Phase 3: Packaging and docs
Dependencies
| Dependency |
Repo |
Notes |
| AgentRuntime CRD must exist |
kagenti-operator |
Webhook needs to query AgentRuntime CRs. CRD must be installed first. |
| AgentRuntime controller applies labels |
kagenti-operator |
Labels on PodTemplateSpec trigger Pod creation, which triggers the webhook. |
Want to contribute?
Additional Context
No response
Feature Description
Summary
Change the mutating webhook from targeting workload objects (Deployments, StatefulSets, DaemonSets, Jobs, CronJobs) to targeting Pods at CREATE time. This is the pattern used by Istio, Linkerd, and Vault Agent Injector, and eliminates GitOps drift caused by mutating the workload object stored in etcd.
This change is part of the Summit MVP for the CR-triggered injection model (see design proposal PR #770).
Motivation
The current webhook intercepts workload objects and mutates the PodTemplateSpec inside them. This causes two problems:
GitOps drift: Argo CD, Flux, and other GitOps tools compare the workload object in Git with the object in the cluster. The webhook-injected sidecars appear in the cluster's Deployment but not in Git, triggering drift detection and potential revert loops.
Ownership conflict: The Deployment object is owned by the developer (or GitOps tool). Mutating it at admission time mixes platform concerns (sidecar injection) into a developer-owned resource.
Targeting Pods at CREATE time solves both:
kubectl get pod -o yaml)Current behavior
MutatingWebhookConfiguration(config/webhook/manifests.yaml):rules.resources:deployments,statefulsets,daemonsets,jobs,cronjobsrules.apiGroups:apps,batchrules.operations:CREATE,UPDATEWebhook handler (
internal/webhook/v1alpha1/authbridge_webhook.go):Handle()switches onreq.Kind.Kind(Deployment, StatefulSet, DaemonSet, Job, CronJob)PodSpecfrom each workload type's templatePodSpectoinjector.PodMutator.InjectAuthBridge()Proposed Solution
Required changes
1. MutatingWebhookConfiguration
File:
config/webhook/manifests.yamlrules.resourcesfromdeployments;statefulsets;daemonsets;jobs;cronjobstopodsrules.apiGroupsfromapps;batchto""(core)rules.operationsfromCREATE;UPDATEtoCREATEonly (Pods are immutable after creation — no need for UPDATE)objectSelectorto match only pods withkagenti.io/typelabel:namespaceSelector(exclude kube-system, etc.)reinvocationPolicytoIfNeeded(other webhooks may modify the Pod before ours runs)2. Webhook handler
File:
internal/webhook/v1alpha1/authbridge_webhook.goHandle()— remove theswitchon Kind, decode onlycorev1.PodPodSpecdirectly from the Pod object (no more navigating workload templates)pod.Labels(not from template labels)PodSpectoinjector.PodMutator.InjectAuthBridge()as beforeisAlreadyInjected) — works the same on Pod's containersappsv1andbatchv1(no longer needed)3. AgentRuntime CR lookup (new)
File:
internal/webhook/v1alpha1/authbridge_webhook.goor new fileownerReferencesfrom the Pod to find the ReplicaSetownerReferencesfrom the ReplicaSet to find the DeploymenttargetRefmatching the Deployment4. Injector updates
File:
internal/webhook/injector/pod_mutator.goInjectAuthBridge()— it already operates on*corev1.PodSpec, so minimal changes expectedresourceNameparameter: currently receives the workload name, now receives the Pod name. Consider whether sidecar configuration (e.g., client registration name template) needs the workload name instead — if so, pass it from the owner chain resolution5. Tests
Files:
internal/webhook/v1alpha1/webhook_suite_test.go,internal/webhook/injector/pod_mutator_test.gokagenti.io/type: agentlabel → sidecars injectedkagenti.io/type: toollabel → sidecars injected (when feature gate enabled)kagenti.io/typelabel → no injection (should not reach webhook due to objectSelector, but test defense-in-depth)kagenti.io/inject: disabled→ no injectionmake testpasses6. Helm chart
Files:
charts/kagenti-webhook/MutatingWebhookConfigurationtemplate to target Podshelm templaterenders correctlyhelm installon Kind cluster works7. Documentation
ARCHITECTURE.mdto reflect Pod-level targetingREADME.mdif it references the webhook targeting modelProgress tracker
Phase 1: Core webhook change
Phase 2: AgentRuntime CR integration
Phase 3: Packaging and docs
Dependencies
Want to contribute?
Additional Context
No response