You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Investigate swapping AuthBridge in as the egress data plane for dam-agents/dam — which is internally the Go module github.com/kagenti/platform, i.e. a Kagenti sister project. DAM's egress design turns out to be nearly isomorphic to AuthBridge's proxy-sidecar model, just built from stock Envoy instead of authbridge-proxy. This issue captures the architecture comparison and a phased swap-in plan.
What DAM does today (verified by source read)
Paired-pod, not sidecar. A Go controller (packages/controller, the only Go component; reconciles Agent/Fork CRDs) provisions, per agent: an agent StatefulSet + a separate -gateway StatefulSet running stock Envoy (gateway.go, envoy.go).
Egress capture = iptables + NetworkPolicy. An egress-lockdown init container DROPs all agent egress except loopback/ESTABLISHED/gateway-IP (iptables_init.go:64-67), plus a namespace default-deny + allow-only-gateway NetworkPolicy (network_policy.go:33-51). The agent opts out of Istio ambient (dataplane-mode: none) so NetworkPolicy sees real destinations. Agent env: HTTPS_PROXY=<gateway IP>, NODE_EXTRA_CA_CERTS=/etc/platform/ca/ca.crt (resources.go:159-180); no SA token.
The gateway Envoy does three things:
CONNECT forward proxy + tls_inspector SNI.
ext_authz callout to a TypeScript gRPC gate (apps/ext-authz/grpc.ts, ext-authz-gate.ts) — allow/deny plus a synchronous human-in-the-loop hold (holds the request up to holdSeconds for a Slack verdict, fail-closed). Allow/deny only; no header mutation.
Per-host TLS MITM with a cert-manager leaf, then Envoy's native credential_injector filter pulling the real secret from an SDS file and writing it into Authorization/x-api-key (envoy.go:658-732). Credential Secrets mount only into the gateway pod — the agent never holds them.
Identity: cert-manager leaf certs + Istio-SPIFFE SA principals + Keycloak JWT. No SPIRE. No OBO/token-exchange — static API keys / OAuth access tokens injected verbatim (oauth-flow.ts is plain auth-code, not RFC-8693).
Mapping to AuthBridge
Concern
DAM
AuthBridge
Swap difficulty
Egress capture
iptables init + NetworkPolicy + HTTPS_PROXY
proxy-init iptables + HTTP_PROXY
reuse DAM's as-is
Data plane
stock Envoy (paired pod)
authbridge-proxy (Go)
the swap point
CONNECT + SNI
Envoy tls_inspector
forward proxy
parity
TLS interception
Envoy terminate w/ cert-manager leaf
tlsbridge: forge leaf from CA, re-originate SAN-verified
The clean cut point is one container. DAM's controller builds the gateway StatefulSet in gateway.go:BuildGatewayStatefulSet → envoy.go:envoyContainer(). Replace that container + its bootstrap renderer with an authbridge-proxy container + config. Everything around it is data-plane-agnostic and stays: the paired-pod model, NetworkPolicy, iptables lockdown, cert-manager leaf, the agent's HTTPS_PROXY/NODE_EXTRA_CA_CERTS env, warm-pools/hibernation. That is what makes this tractable — the hard k8s scaffolding is already built and doesn't care what the gateway binary is.
AuthBridge's forward proxy is a functional superset of DAM's Envoy on the data path (CONNECT, SNI, TLS bridge, re-origination all parity), so the real work is the two mismatches:
Static credential injection. DAM injects static keys / OAuth access tokens; AuthBridge is OBO-centric. Add a small static-header-inject plugin to AuthBridge's pipeline, fed from the same mounted Secret. Do not migrate DAM's connections to OBO in phase 1 (that touches DAM's OAuth flow + UI).
HITL hold. DAM's differentiator; AuthBridge lacks it. Cheapest path: have AuthBridge's pipeline make an ext_authz-style callout to DAM's existing TS gate service for the verdict — leaving DAM's Slack-approval UX untouched.
Bonus simplification: DAM cryptographically pins each per-instance ext-authz Service to the calling SA because policy (TS) is split from the Envoy data plane. If AuthBridge runs policy in-process, that pinning apparatus can be dropped — unless HITL is kept via callout, in which case only that one hop needs securing.
Proposed phases
Phase 1 — drop-in data-plane swap (contained): replace envoyContainer() with authbridge-proxy; add a static-cred-inject plugin; bridge HITL via a callout to DAM's existing gate. Reuse all surrounding scaffolding.
Phase 2 — unify identity: adopt OBO + SPIRE to align with the Kagenti identity stack. Bigger — connection-model/OAuth/UI churn + adds SPIRE to DAM's deploy.
Caveat / trade-off
DAM today rides 100% upstream Envoy filters (credential_injector, ext_authz, tls_inspector, SDS) with zero custom data-plane code. Swapping in authbridge-proxy trades that for custom Go: you gain OBO/redaction/richer pipeline and a single Kagenti-consistent data plane, but take on maintaining proxy code where DAM currently gets it free from Envoy. Decision-owners should weigh this explicitly.
Open questions
Does DAM's roadmap actually want OBO, or is static injection a deliberate choice? (Determines whether Phase 2 is desirable at all.)
Can AuthBridge's pipeline cleanly express the synchronous HITL hold semantics (timeout, fail-closed) via a callout, or does HITL need to become a first-class pipeline primitive?
DAM egress: packages/controller/pkg/reconciler/{gateway.go,envoy.go,resources.go,network_policy.go,iptables_init.go}, packages/api-server/src/apps/ext-authz/
Summary
Investigate swapping AuthBridge in as the egress data plane for
dam-agents/dam— which is internally the Go modulegithub.com/kagenti/platform, i.e. a Kagenti sister project. DAM's egress design turns out to be nearly isomorphic to AuthBridge's proxy-sidecar model, just built from stock Envoy instead ofauthbridge-proxy. This issue captures the architecture comparison and a phased swap-in plan.What DAM does today (verified by source read)
packages/controller, the only Go component; reconcilesAgent/ForkCRDs) provisions, per agent: an agent StatefulSet + a separate-gatewayStatefulSet running stock Envoy (gateway.go,envoy.go).egress-lockdowninit container DROPs all agent egress except loopback/ESTABLISHED/gateway-IP (iptables_init.go:64-67), plus a namespace default-deny + allow-only-gateway NetworkPolicy (network_policy.go:33-51). The agent opts out of Istio ambient (dataplane-mode: none) so NetworkPolicy sees real destinations. Agent env:HTTPS_PROXY=<gateway IP>,NODE_EXTRA_CA_CERTS=/etc/platform/ca/ca.crt(resources.go:159-180); no SA token.tls_inspectorSNI.apps/ext-authz/grpc.ts,ext-authz-gate.ts) — allow/deny plus a synchronous human-in-the-loop hold (holds the request up toholdSecondsfor a Slack verdict, fail-closed). Allow/deny only; no header mutation.credential_injectorfilter pulling the real secret from an SDS file and writing it intoAuthorization/x-api-key(envoy.go:658-732). Credential Secrets mount only into the gateway pod — the agent never holds them.oauth-flow.tsis plain auth-code, not RFC-8693).Mapping to AuthBridge
HTTPS_PROXYHTTP_PROXYauthbridge-proxy(Go)credential_injector(static, SDS)NODE_EXTRA_CA_CERTSHow the swap works
The clean cut point is one container. DAM's controller builds the gateway StatefulSet in
gateway.go:BuildGatewayStatefulSet→envoy.go:envoyContainer(). Replace that container + its bootstrap renderer with anauthbridge-proxycontainer + config. Everything around it is data-plane-agnostic and stays: the paired-pod model, NetworkPolicy, iptables lockdown, cert-manager leaf, the agent'sHTTPS_PROXY/NODE_EXTRA_CA_CERTSenv, warm-pools/hibernation. That is what makes this tractable — the hard k8s scaffolding is already built and doesn't care what the gateway binary is.AuthBridge's forward proxy is a functional superset of DAM's Envoy on the data path (CONNECT, SNI, TLS bridge, re-origination all parity), so the real work is the two mismatches:
Bonus simplification: DAM cryptographically pins each per-instance ext-authz Service to the calling SA because policy (TS) is split from the Envoy data plane. If AuthBridge runs policy in-process, that pinning apparatus can be dropped — unless HITL is kept via callout, in which case only that one hop needs securing.
Proposed phases
envoyContainer()withauthbridge-proxy; add a static-cred-inject plugin; bridge HITL via a callout to DAM's existing gate. Reuse all surrounding scaffolding.Caveat / trade-off
DAM today rides 100% upstream Envoy filters (
credential_injector,ext_authz,tls_inspector, SDS) with zero custom data-plane code. Swapping inauthbridge-proxytrades that for custom Go: you gain OBO/redaction/richer pipeline and a single Kagenti-consistent data plane, but take on maintaining proxy code where DAM currently gets it free from Envoy. Decision-owners should weigh this explicitly.Open questions
kagenti/platformvskagenti-extensions)?References
github.com/kagenti/platform)packages/controller/pkg/reconciler/{gateway.go,envoy.go,resources.go,network_policy.go,iptables_init.go},packages/api-server/src/apps/ext-authz/authlib/tlsbridge/, capture atauthlib/listener/forwardproxy/Assisted-By: Claude Code