Demo with Secure Profile
This guide re-runs the weather-agent scenario from Quick Start with Core Profile under the secure profile — the AuthBridge sidecar is injected into the agent, the operator registers a Keycloak client per workload, SPIRE hands out a workload SVID, and every request must carry a valid Bearer token. The tool workload still runs as a plain Deployment with no sidecar; this matches the upstream weather-agent demo pattern and keeps the tool's outbound call to the public geocoding API on the pod's default egress path.
For an even more locked-down variant — AuthBridge on the tool as well, with RFC 8693 token exchange between agent and tool — continue to Demo Advanced after this guide.
TOC
PrerequisitesStep 1: Deploy the MCP tool serverStep 2: Deploy the secured agentStep 3: Verify the secure wiringStep 4: Send an authenticated queryAuthBridge deployment modesSelecting the modeReload after mode changesWhen to use each modeAllowing outbound traffic inproxy-sidecar modeClean upTroubleshootingPrerequisites
Before starting, make sure:
- The secure-profile dependencies are installed — cert-manager, SPIRE, Keycloak, Istio ambient mesh. See Install the Secure-Profile Dependencies.
- The secure profile is enabled on the
Kagentioperand (spec.featureGates.globalEnabled: true,spec.authbridgeConfig.enabled: true,spec.keycloak.publicUrlset). See Enable the Secure Profile. - An InferenceService that serves an OpenAI-compatible chat API is reachable in-cluster. This guide uses
qwen36-27b-ggufinmodels; substitute your own everywhere you see those names — see the model-endpoint recipe in the quick start for how to resolveLLM_API_BASE,LLM_MODEL, andLLM_API_KEY. kubectlaccess to the target cluster.
Create the demo namespace and opt it into the secure profile:
The kagenti-enabled=true label is required. Without it, the operator does not create the per-namespace authbridge-config ConfigMap, Keycloak client registration for the workloads never starts, and every pod stays pending on a missing credentials secret.
Step 1: Deploy the MCP tool server
The tool workload is identical to the core-profile version. It runs as a plain Deployment with no AgentRuntime and no AuthBridge sidecar — sidecar injection into tool workloads is off by default (spec.featureGates.injectTools: false), so tagging the Deployment kagenti.io/type: tool on its own would not inject a sidecar even if you tried. The security posture is inbound-only on the agent: the agent's AuthBridge validates the client's JWT, then the agent → tool call is a plain in-cluster HTTP hop.
READY 1/1 confirms the tool runs as a single container even under the secure profile — no sidecar was injected.
$PORT
Under the secure profile the AuthBridge proxy-sidecar binds the workload's service port, and the operator remaps the application to a different PORT value. An image that hardcodes its port collides with the reverse-proxy (address already in use). The upstream weather_service / weather_tool images honor PORT from v0.1.0 onward, so those work unchanged.
Step 2: Deploy the secured agent
The agent Deployment, Service, and AgentRuntime are the same as in the core-profile quick start — no secure-profile-specific fields are required, because the AuthBridge webhook does all the wiring at admission time based on the Kagenti operand and the namespace label. The AgentRuntime triggers the mutating webhook to inject the sidecar and mount the operator-created Keycloak client secret.
Step 3: Verify the secure wiring
Confirm the AuthBridge sidecar was injected, SPIRE handed out an SVID, and the operator registered a Keycloak client for the workload:
The Secret carries client-id.txt and client-secret.txt for the workload's dynamically-registered Keycloak client (named team1/weather-agent). The webhook mounts it into the agent pod at /shared/, and AuthBridge reads it from there.
With the secure profile on, an unauthenticated request to the agent is rejected by the AuthBridge jwt-validation plugin:
Step 4: Send an authenticated query
Because the workload's own Keycloak credentials Secret is already mounted in-cluster, the simplest way to exercise the secured path is a short pod that:
- Mounts the same credentials Secret at
/creds/. - Does a Keycloak
client_credentialsgrant to obtain an access token. - Sends the A2A
message/sendrequest withAuthorization: Bearer <token>.
No port-forwarding needed, and the client secret never leaves the cluster.
Find the agent's credentials Secret name:
Run the authenticated query from a pod. Replace <credentials-secret> with the name from the previous command:
Read the result and clean up:
You get the same completed A2A task as in the core-profile Step 4 — now through the authenticated, JWT-validated path.
To call the agent from outside the cluster instead, request the token from a Keycloak endpoint exposed via an Ingress/Gateway, then send the request to the agent's exposed endpoint with the same Authorization: Bearer <token> header. The token request is the standard OIDC call: POST <keycloak>/realms/kagenti/protocol/openid-connect/token with grant_type=client_credentials, client_id, and client_secret.
AuthBridge deployment modes
AuthBridge can be injected in one of two shapes. The mode decides which sidecar image is added, how inbound traffic is validated, and how outbound traffic is intercepted. It is a per-namespace default (an admin knob), not a per-workload one — every agent and MCP tool in the namespace shares the same mode.
Selecting the mode
The mode is resolved in this order (first non-empty wins):
- The namespace ConfigMap
authbridge-runtime-config—mode:field insideconfig.yaml. - Cluster-wide default:
proxy-sidecar.
To switch a namespace to envoy-sidecar, apply a ConfigMap and restart the agent + tool deployments (see Reload after mode changes):
envoy-sidecar boots cleanly with mtls.mode: permissive in the current release — the authbridge-envoy binary writes X.509 SVIDs to /opt/svid*.pem in-process via go-spiffe, which is what the operator's Envoy filesystem-SDS config expects. However, two operator-template gaps remain and are being tracked for a follow-up release:
- Inbound auth enforcement: the Envoy config template injects
x-authbridge-direction: inboundat route level, which the router filter applies afterext_proc. AuthBridge therefore classifies inbound requests as outbound and applies the default passthrough policy — the JWT-validation plugin never runs. A follow-up patch moves the header injection into a Lua HTTP filter placed beforeext_proc. - External HTTPS through the sidecar: Envoy's outbound listener assumes HTTP, so a client TLS handshake to an arbitrary public host is parsed as HTTP and mangled. There is no
NO_PROXYescape hatch in this mode; a follow-up will add aspec.egressBypassfield on theKagentioperand that flows through to a proxy-initOUTBOUND_PORTS_EXCLUDE/ hosts allowlist.
Recommendation for the current release: use proxy-sidecar in production. Its inbound JWT validation and the NO_PROXY outbound-egress option (see below) are both verified end-to-end. envoy-sidecar is fine for booting and inspecting the data path but should not be relied on for production auth enforcement until the two items above land.
Reload after mode changes
Both the manager and the per-workload injected config are cached at pod-create time, so a mode change needs three actions:
Confirm the injection happened as expected:
When to use each mode
Use proxy-sidecar (the default) when any of the following applies — this is the tested-and-supported path for the current release:
- You want sidecar-to-sidecar mTLS (
permissiveorstrict). - You are only calling other in-cluster HTTP services (agent → MCP tool, LLM InferenceService, etc.). No
CONNECT-tunnelling needed. - SPIRE is not required for the workloads.
Use envoy-sidecar when you specifically need:
- Envoy's routing / observability features on the data path.
- Transparent iptables interception (no
HTTP_PROXYenv on the app).
Allowing outbound traffic in proxy-sidecar mode
The upstream weather-agent demo pattern this guide follows — no AgentRuntime and no sidecar on tool workloads (spec.featureGates.injectTools: false is the operand default) — sidesteps this issue entirely: the tool runs as a single container without HTTP_PROXY/HTTPS_PROXY env, so its outbound calls to public APIs go direct via the pod's default egress. This is the recommended layout when the tool doesn't need its own inbound JWT validation or outbound token exchange.
The rest of this section applies only when you deliberately inject an AuthBridge sidecar into a workload that also needs external HTTPS — for example when you flip injectTools: true on the Kagenti operand (see Demo Advanced) or add kagenti.io/authbridge-inject: "true" to an individual Deployment. AuthBridge's HTTP forward proxy is HTTP-only — it responds 405 Method Not Allowed to CONNECT, so an injected app making an outbound HTTPS request through the sidecar hits Tunnel connection failed: 405. This is by design: the outbound token-exchange plugin needs to read and modify request headers, which is not possible through an opaque TLS tunnel.
Two consequences worth knowing when you have a sidecar on an outbound-heavy workload:
-
In-cluster HTTP works out of the box (agent → tool, LLM). No configuration needed.
-
External HTTPS (a public API such as
geocoding-api.open-meteo.comused by the weather MCP tool) needs to bypass the sidecar. Add the destination hostnames toNO_PROXYon the app container. The kagenti webhook setsHTTP_PROXY/HTTPS_PROXY/NO_PROXYonly if not already present on the container, so pre-declaringNO_PROXYon the workload cleanly overrides the default:Effect: outbound calls to any host not matched by
NO_PROXYstill route through the AuthBridge sidecar (and remain eligible for outbound token exchange, tracing, etc.); the listed public API calls bypass the sidecar and go direct via the pod's default egress. The cluster's egress network policy — not AuthBridge — governs whether the traffic actually reaches the public destination.INFOOnly add the hosts you need to reach externally. Every entry in
NO_PROXYis a hole in the outbound-inspection path — the sidecar can no longer inject Bearer tokens on that hostname.
Clean up
That removes the demo namespace and everything in it. The cluster-wide secure-profile install (SPIRE, Keycloak, Istio ambient, the Kagenti operand) is untouched.