Skip to content
50 changes: 15 additions & 35 deletions charts/kagenti-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,14 @@ signatureVerification:
# Feature gates — highest-priority layer in the injection precedence chain.
# Set globalEnabled to false to disable ALL sidecar injection (kill switch).
# Set individual gates to false to disable specific sidecars cluster-wide.
#
# spiffe-helper and client-registration no longer have feature gates:
# * spiffe-helper is bundled inside the combined authbridge images and
# gated per-workload by the SPIRE_ENABLED env var.
# * client-registration is operator-managed (no in-pod sidecar).
featureGates:
globalEnabled: true
envoyProxy: true
spiffeHelper: true
clientRegistration: true
# injectTools controls whether tool workloads (kagenti.io/type=tool) receive
# sidecar injection. Defaults to false — tools are not injected by default.
injectTools: false
Expand All @@ -133,23 +136,24 @@ featureGates:
# Default false — cached mode is faster and sufficient when namespace ConfigMaps
# rarely change. Cache is cleared on webhook pod restart.
perWorkloadConfigResolution: false
# combinedSidecar controls whether injection uses a single combined authbridge
# container instead of separate envoy-proxy + spiffe-helper + client-registration.
# Requires the authbridge image. Default false — separate sidecars.
combinedSidecar: false

# Platform defaults for AuthBridge sidecar injection.
# These are the lowest-priority layer — overridden by feature gates,
# namespace labels/ConfigMaps, and workload labels/AgentRuntime CRs.
#
# Three combined images, selected per workload by deployment mode:
# * envoyProxy (envoy-sidecar mode): Envoy + ext_proc authbridge + spiffe-helper.
# * authbridge (proxy-sidecar mode, default): authbridge-proxy (full plugin set) + spiffe-helper.
# * authbridgeLite (lite mode): authbridge-lite (jwt-validation + token-exchange only,
# parsers dropped) + spiffe-helper. Same listener layout
# as authbridge; for size-constrained deployments.
# proxy-init applies to envoy-sidecar mode only.
defaults:
# Container images with version tags
images:
envoyProxy: ghcr.io/kagenti/kagenti-extensions/authbridge-envoy:latest
authbridgeLight: ghcr.io/kagenti/kagenti-extensions/authbridge-light:latest
proxyInit: ghcr.io/kagenti/kagenti-extensions/proxy-init:latest
spiffeHelper: ghcr.io/kagenti/kagenti-extensions/spiffe-helper:latest
clientRegistration: ghcr.io/kagenti/kagenti-extensions/client-registration:latest
authbridge: ghcr.io/kagenti/kagenti-extensions/authbridge:latest
authbridgeLite: ghcr.io/kagenti/kagenti-extensions/authbridge-lite:latest
proxyInit: ghcr.io/kagenti/kagenti-extensions/proxy-init:latest
pullPolicy: IfNotPresent

# Proxy settings
Expand All @@ -176,34 +180,10 @@ defaults:
limits:
cpu: 10m
memory: 10Mi
spiffeHelper:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 100m
memory: 128Mi
clientRegistration:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 100m
memory: 128Mi
authbridge:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 300m
memory: 384Mi

# Per-sidecar enable/disable at the platform level (lowest-priority layer).
# These are overridden by feature gates, namespace labels, and workload labels.
sidecars:
envoyProxy:
enabled: true
spiffeHelper:
enabled: true
clientRegistration:
enabled: true
30 changes: 30 additions & 0 deletions kagenti-operator/api/v1alpha1/agentruntime_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,36 @@ type AgentRuntimeSpec struct {
// Trace specifies optional per-workload observability overrides
// +optional
Trace *TraceSpec `json:"trace,omitempty"`

// AuthBridgeMode selects the deployment shape for this workload's
// authbridge sidecar. When unset, the namespace-level
// authbridge-runtime-config ConfigMap's mode is used; if that is
// also unset, the operator falls back to "proxy-sidecar".
//
// Four valid values:
//
// proxy-sidecar HTTP_PROXY env + authbridge-proxy (full plugin
// set, including a2a/mcp/inference parsers) +
// spiffe-helper bundled. No Envoy, no iptables.
// Default mode.
// envoy-sidecar Envoy + ext_proc authbridge + spiffe-helper
// bundled. Requires the proxy-init iptables
// container.
// lite Same listener layout as proxy-sidecar but uses
// the authbridge-lite image (jwt-validation +
// token-exchange only, parsers dropped to shrink
// the binary). For size-constrained deployments
// that don't need protocol-aware abctl events.
// waypoint Standalone deployment, not injected as a
// sidecar. Used by Istio ambient mesh.
//
// Set this when a single workload needs a different shape than the
// namespace default. Most deployments leave it unset and let the
// namespace ConfigMap drive the choice.
//
// +optional
// +kubebuilder:validation:Enum=proxy-sidecar;envoy-sidecar;lite;waypoint
AuthBridgeMode string `json:"authBridgeMode,omitempty"`
}

// IdentitySpec configures workload identity for an AgentRuntime.
Expand Down
7 changes: 2 additions & 5 deletions kagenti-operator/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ func main() {
setupLog.Info("Feature gates updated",
"globalEnabled", fg.GlobalEnabled,
"envoyProxy", fg.EnvoyProxy,
"spiffeHelper", fg.SpiffeHelper,
"clientRegistration", fg.ClientRegistration)
"injectTools", fg.InjectTools,
"perWorkloadConfigResolution", fg.PerWorkloadConfigResolution)
})
if err := featureGateLoader.Watch(ctx); err != nil {
setupLog.Error(err, "Failed to start feature gates watcher")
Expand Down Expand Up @@ -425,12 +425,9 @@ func main() {

// AuthBridge sidecar injection webhook
if authBridgeWebhooksEnabled() {
// Pass false to disable legacy client-registration sidecar injection.
// Client registration is now handled by the operator controller.
podMutator := injector.NewPodMutator(
mgr.GetClient(),
mgr.GetAPIReader(),
false, // disableLegacyClientRegistrationSidecar
configLoader.Get,
featureGateLoader.Get,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,39 @@ spec:
spec:
description: AgentRuntimeSpec defines the desired state of AgentRuntime.
properties:
authBridgeMode:
description: |-
AuthBridgeMode selects the deployment shape for this workload's
authbridge sidecar. When unset, the namespace-level
authbridge-runtime-config ConfigMap's mode is used; if that is
also unset, the operator falls back to "proxy-sidecar".

Four valid values:

proxy-sidecar HTTP_PROXY env + authbridge-proxy (full plugin
set, including a2a/mcp/inference parsers) +
spiffe-helper bundled. No Envoy, no iptables.
Default mode.
envoy-sidecar Envoy + ext_proc authbridge + spiffe-helper
bundled. Requires the proxy-init iptables
container.
lite Same listener layout as proxy-sidecar but uses
the authbridge-lite image (jwt-validation +
token-exchange only, parsers dropped to shrink
the binary). For size-constrained deployments
that don't need protocol-aware abctl events.
waypoint Standalone deployment, not injected as a
sidecar. Used by Istio ambient mesh.

Set this when a single workload needs a different shape than the
namespace default. Most deployments leave it unset and let the
namespace ConfigMap drive the choice.
enum:
- proxy-sidecar
- envoy-sidecar
- lite
- waypoint
type: string
identity:
description: Identity specifies optional per-workload identity overrides
properties:
Expand Down
47 changes: 15 additions & 32 deletions kagenti-operator/internal/webhook/config/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,21 @@ func CompiledDefaults() *PlatformConfig {
// Compiled defaults are overridden at runtime by the platform-config
// ConfigMap (kagenti-platform-config). These serve as fallbacks only.
Images: ImageConfig{
EnvoyProxy: "ghcr.io/kagenti/kagenti-extensions/authbridge-envoy:latest",
AuthBridgeLight: "ghcr.io/kagenti/kagenti-extensions/authbridge-light:latest",
ProxyInit: "ghcr.io/kagenti/kagenti-extensions/proxy-init:latest",
SpiffeHelper: "ghcr.io/kagenti/kagenti-extensions/spiffe-helper:latest",
ClientRegistration: "ghcr.io/kagenti/kagenti-extensions/client-registration:latest",
AuthBridge: "ghcr.io/kagenti/kagenti-extensions/authbridge:latest",
PullPolicy: corev1.PullIfNotPresent,
// authbridge-envoy: combined image for envoy-sidecar mode
// (Envoy + ext_proc authbridge + spiffe-helper bundled).
EnvoyProxy: "ghcr.io/kagenti/kagenti-extensions/authbridge-envoy:latest",
// authbridge: combined image for proxy-sidecar mode (default
// deployment shape) — authbridge-proxy + spiffe-helper
// bundled, no Envoy, no gRPC.
AuthBridge: "ghcr.io/kagenti/kagenti-extensions/authbridge:latest",
// authbridge-lite: size-optimized variant for the "lite"
// mode. Same listener layout as AuthBridge but parsers
// (a2a/mcp/inference) are dropped.
AuthBridgeLite: "ghcr.io/kagenti/kagenti-extensions/authbridge-lite:latest",
// proxy-init: iptables init container, used by
// envoy-sidecar mode only.
ProxyInit: "ghcr.io/kagenti/kagenti-extensions/proxy-init:latest",
PullPolicy: corev1.PullIfNotPresent,
},
Proxy: ProxyConfig{
Port: 15123,
Expand Down Expand Up @@ -46,26 +54,6 @@ func CompiledDefaults() *PlatformConfig {
corev1.ResourceMemory: resource.MustParse("10Mi"),
},
},
SpiffeHelper: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("50m"),
corev1.ResourceMemory: resource.MustParse("64Mi"),
},
Limits: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("100m"),
corev1.ResourceMemory: resource.MustParse("128Mi"),
},
},
ClientRegistration: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("50m"),
corev1.ResourceMemory: resource.MustParse("64Mi"),
},
Limits: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("100m"),
corev1.ResourceMemory: resource.MustParse("128Mi"),
},
},
AuthBridge: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("100m"),
Expand All @@ -89,10 +77,5 @@ func CompiledDefaults() *PlatformConfig {
EnableMetrics: true,
EnableTracing: false,
},
Sidecars: SidecarDefaults{
EnvoyProxy: SidecarDefault{Enabled: true},
SpiffeHelper: SidecarDefault{Enabled: true},
ClientRegistration: SidecarDefault{Enabled: true},
},
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,8 @@ func logFeatureGates(fg *FeatureGates, source string) {
log.Info("[feature-gates] gates",
"globalEnabled", fg.GlobalEnabled,
"envoyProxy", fg.EnvoyProxy,
"spiffeHelper", fg.SpiffeHelper,
"clientRegistration", fg.ClientRegistration,
"injectTools", fg.InjectTools,
"perWorkloadConfigResolution", fg.PerWorkloadConfigResolution,
"combinedSidecar", fg.CombinedSidecar,
)
log.Info("=============================================")
}
20 changes: 10 additions & 10 deletions kagenti-operator/internal/webhook/config/feature_gates.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ package config

// FeatureGates controls which sidecars are globally enabled/disabled.
// This is the highest-priority layer in the injection precedence chain.
//
// Spiffe-helper and client-registration are no longer separate-sidecar
// features:
// - spiffe-helper is bundled inside the EnvoyProxy and AuthBridge
// combined images and starts conditionally on the per-workload
// SPIRE_ENABLED env var.
// - client-registration is now operator-managed entirely (the in-pod
// sidecar path is gone). See operator-managed-client-registration.md.
type FeatureGates struct {
GlobalEnabled bool `json:"globalEnabled" yaml:"globalEnabled"`
EnvoyProxy bool `json:"envoyProxy" yaml:"envoyProxy"`
SpiffeHelper bool `json:"spiffeHelper" yaml:"spiffeHelper"`
ClientRegistration bool `json:"clientRegistration" yaml:"clientRegistration"`
GlobalEnabled bool `json:"globalEnabled" yaml:"globalEnabled"`
EnvoyProxy bool `json:"envoyProxy" yaml:"envoyProxy"`
// InjectTools controls whether tool workloads (kagenti.io/type=tool) receive
// sidecar injection. Defaults to false — tools are not injected by default.
InjectTools bool `json:"injectTools" yaml:"injectTools"`
Expand All @@ -16,9 +22,6 @@ type FeatureGates struct {
// true → resolved path: webhook reads namespace ConfigMaps at
// admission time and injects literal env var values.
PerWorkloadConfigResolution bool `json:"perWorkloadConfigResolution" yaml:"perWorkloadConfigResolution"`
// CombinedSidecar controls whether injection uses a single combined authbridge
// container instead of separate envoy-proxy + spiffe-helper + client-registration sidecars.
CombinedSidecar bool `json:"combinedSidecar" yaml:"combinedSidecar"`
}

// DefaultFeatureGates returns feature gates with sidecar injection enabled for
Expand All @@ -27,11 +30,8 @@ func DefaultFeatureGates() *FeatureGates {
return &FeatureGates{
GlobalEnabled: true,
EnvoyProxy: true,
SpiffeHelper: true,
ClientRegistration: true,
InjectTools: false,
PerWorkloadConfigResolution: false,
CombinedSidecar: false,
}
}

Expand Down
19 changes: 5 additions & 14 deletions kagenti-operator/internal/webhook/config/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,9 @@ func logConfig(cfg *PlatformConfig, source string) {
log.Info("[config] source", "source", source)
log.Info("[config] images",
"envoyProxy", cfg.Images.EnvoyProxy,
"authBridge", cfg.Images.AuthBridge,
"authBridgeLite", cfg.Images.AuthBridgeLite,
"proxyInit", cfg.Images.ProxyInit,
"spiffeHelper", cfg.Images.SpiffeHelper,
"clientRegistration", cfg.Images.ClientRegistration,
"pullPolicy", cfg.Images.PullPolicy,
)
log.Info("[config] proxy",
Expand All @@ -208,13 +208,9 @@ func logConfig(cfg *PlatformConfig, source string) {
"requests", cfg.Resources.ProxyInit.Requests,
"limits", cfg.Resources.ProxyInit.Limits,
)
log.Info("[config] resources.spiffeHelper",
"requests", cfg.Resources.SpiffeHelper.Requests,
"limits", cfg.Resources.SpiffeHelper.Limits,
)
log.Info("[config] resources.clientRegistration",
"requests", cfg.Resources.ClientRegistration.Requests,
"limits", cfg.Resources.ClientRegistration.Limits,
log.Info("[config] resources.authBridge",
"requests", cfg.Resources.AuthBridge.Requests,
"limits", cfg.Resources.AuthBridge.Limits,
)
log.Info("[config] tokenExchange",
"tokenUrl", cfg.TokenExchange.TokenURL,
Expand All @@ -225,10 +221,5 @@ func logConfig(cfg *PlatformConfig, source string) {
"trustDomain", cfg.Spiffe.TrustDomain,
"socketPath", cfg.Spiffe.SocketPath,
)
log.Info("[config] sidecars",
"envoyProxy.enabled", cfg.Sidecars.EnvoyProxy.Enabled,
"spiffeHelper.enabled", cfg.Sidecars.SpiffeHelper.Enabled,
"clientRegistration.enabled", cfg.Sidecars.ClientRegistration.Enabled,
)
log.Info("=============================================")
}
Loading
Loading