Skip to content

fix: Default outbound policy to passthrough, preventing token exchange failures#185

Merged
mrsabath merged 2 commits into
rossoctl:mainfrom
mrsabath:fix/passthrough-by-default-outbound-policy
Mar 10, 2026
Merged

fix: Default outbound policy to passthrough, preventing token exchange failures#185
mrsabath merged 2 commits into
rossoctl:mainfrom
mrsabath:fix/passthrough-by-default-outbound-policy

Conversation

@mrsabath

Copy link
Copy Markdown
Contributor

Summary

Fixes the root cause of kagenti/kagenti#882 from the kagenti-extensions side.

The go-processor previously attempted token exchange for all plaintext HTTP outbound traffic when global config (TARGET_AUDIENCE, TARGET_SCOPES) was set. This broke agents using in-cluster HTTP services (Ollama for LLM, otel-collector for telemetry) because non-Keycloak tokens (like API keys) were rejected with "Invalid token" or "invalid_scope" errors. External HTTPS LLM APIs (OpenAI, Anthropic) happened to work only because Envoy TLS passthrough bypasses the ext_proc entirely.

This PR inverts the default: outbound requests that don't match any route pass through unchanged. Token exchange only happens for hosts with explicit entries in an authproxy-routes ConfigMap.

Changes

  • go-processor: Add DEFAULT_OUTBOUND_POLICY env var ("passthrough" default, "exchange" for legacy backward compat) and insert passthrough check in handleOutbound() for unmatched hosts
  • go-processor: Add passthroughResponse() helper to reduce duplication
  • go-processor: Add comprehensive unit tests (TestDefaultOutboundPolicy, TestOutboundPolicyWithRoutes, TestOutboundPolicyRouteMatchExchangeFails) using httptest mock Keycloak
  • webhook: Mount optional authproxy-routes ConfigMap volume (Optional: true so pods don't fail if it doesn't exist)
  • webhook: Add ROUTES_CONFIG_PATH and DEFAULT_OUTBOUND_POLICY env vars to envoy-proxy container
  • github-issue demo: Add authproxy-routes ConfigMap with explicit route entry for github-tool (so token exchange still works for that demo)
  • webhook demo: Add DEFAULT_OUTBOUND_POLICY documentation and commented-out authproxy-routes example
  • docs: Update CLAUDE.md and AuthBridge/CLAUDE.md with new policy, ConfigMap, and behavior

How it works

Outbound HTTP request
  |
  +-- Host matches route? --> Yes, passthrough=true --> Pass through
  |                      |
  |                      +--> Yes, with audience/scopes --> Token exchange
  |
  +-- No match --> DEFAULT_OUTBOUND_POLICY?
                      |
                      +--> "passthrough" (default) --> Pass through unchanged
                      |
                      +--> "exchange" (legacy) --> Exchange with global config

Companion change needed in kagenti/kagenti

The Helm chart in charts/kagenti/templates/agent-namespaces.yaml currently creates authbridge-config with hardcoded TARGET_AUDIENCE: "auth-target" and TARGET_SCOPES: "openid auth-target-aud". With this PR, those values become fallbacks only used when a route matches but doesn't specify its own audience/scopes (or when DEFAULT_OUTBOUND_POLICY=exchange). The Helm chart should be updated to either:

  1. Remove TARGET_AUDIENCE/TARGET_SCOPES from the default authbridge-config (since passthrough is now the default and routes provide per-target config), or
  2. Keep them as fallback values but document that they only apply when routes are configured

The weather agent demo and all other agents will work out-of-the-box after this change without needing the auth-target-aud scope to exist in Keycloak.

Test plan

  • All existing go-processor tests pass (go test ./go-processor/...)
  • All existing resolver tests pass (go test ./go-processor/internal/resolver/...)
  • All webhook tests pass (make test in kagenti-webhook/)
  • New TestDefaultOutboundPolicy validates passthrough for Ollama, otel-collector, and arbitrary hosts
  • New TestDefaultOutboundPolicyLegacyExchange validates backward compat with exchange policy
  • New TestOutboundPolicyWithRoutes validates github-issue pattern (route-based exchange + LLM passthrough)
  • New TestOutboundPolicyRouteMatchExchangeFails validates 503 on Keycloak errors for routed hosts
  • Pre-commit hooks pass (go-fmt, go-vet, trailing-whitespace, yaml-check)
  • Deploy weather agent with Ollama and verify chat works without manual ConfigMap changes
  • Deploy github-issue agent with routes ConfigMap and verify token exchange works for github-tool

mrsabath added 2 commits March 9, 2026 11:59
…cess

Add Step 10 to both demo-manual.md and demo-ui.md demonstrating
scope-based access control: Alice (public only) vs Bob (privileged)
through AuthBridge token exchange.

- Add REQUIRED_SCOPE env var to github-tool-deployment.yaml
- Add Step 10 (10a-10f) with Alice/Bob access control walkthrough
- Update demo.md overview with access control description
- Clarify scope forwarding dependency (rossoctl#139) in flow description
- Explain why Bob explicitly requests github-full-access (realm OPTIONAL scope)
- Update all Keycloak URLs from demo realm to kagenti realm

Depends on: kagenti-extensions#139 (scope forwarding)

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Mariusz Sabath <mrsabath@gmail.com>
…e failures for LLM and telemetry traffic

The go-processor previously attempted token exchange for ALL plaintext HTTP
outbound traffic when global config (TARGET_AUDIENCE, TARGET_SCOPES) was set.
This broke agents using in-cluster HTTP services (Ollama, otel-collector) because
non-Keycloak tokens (like API keys) were rejected by Keycloak with Invalid token
or invalid_scope errors.

This change inverts the default: outbound requests that do not match any route in
routes.yaml now pass through unchanged. Token exchange only happens for hosts with
explicit route entries in authproxy-routes ConfigMap. A DEFAULT_OUTBOUND_POLICY env
var (passthrough default, exchange for legacy) provides backward compatibility.

Changes:
- go-processor: Add DEFAULT_OUTBOUND_POLICY env var and passthrough-by-default logic
- go-processor: Add passthroughResponse() helper, refactor handleOutbound()
- go-processor: Add comprehensive tests for outbound policy behavior
- webhook: Mount optional authproxy-routes ConfigMap volume (Optional: true)
- webhook: Add ROUTES_CONFIG_PATH and DEFAULT_OUTBOUND_POLICY env vars to envoy-proxy
- github-issue demo: Add authproxy-routes ConfigMap with route for github-tool
- webhook demo: Add DEFAULT_OUTBOUND_POLICY docs and commented routes example
- docs: Update CLAUDE.md and AuthBridge/CLAUDE.md with new policy and ConfigMap

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Mariusz Sabath <mrsabath@gmail.com>
@huang195

Copy link
Copy Markdown
Member

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@huang195 huang195 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants