Note: The go-processor ext_proc server has been removed. Auth logic now lives in the unified authbridge binary. This directory contains the proxy-init iptables setup, combined sidecar image, demo app, and quickstart.
AuthProxy is a token validation and exchange sidecar for Kubernetes workloads. It enables secure service-to-service communication by:
- Validating incoming requests with JWT token verification (inbound)
- Exchanging tokens for ones with the correct audience for downstream services (outbound)
AuthProxy solves a common challenge in microservices architectures: how can a service call another service when each service expects tokens with different audiences?
When a caller obtains a token, it's typically scoped to a specific audience (often the caller itself). If the caller tries to use that token to call a different service, the request will be rejected because the target service expects a different audience.
┌─────────────┐ ┌──────────────┐
│ Caller │ ── Token A ────────► │ Target │ ❌ REJECTED
│ (aud: svc-a)│ │ (expects │ Wrong audience!
└─────────────┘ │ aud: target)│
└──────────────┘
AuthProxy intercepts outgoing requests and exchanges the token for a new one with the correct audience:
┌─────────────┐ ┌──────────────────────────┐ ┌─────────────┐
│ Caller │ ── Token A ──►│ AuthProxy │─ Token B ──► │ Target │ ✅ AUTHORIZED
│ │ │ 1. Intercept request │ │ │
│ Token: │ │ 2. Exchange for new aud │ │ (expects │
│ (aud: svc-a)│ │ 3. Forward request │ │ aud: target)│
└─────────────┘ └──────────────────────────┘ └─────────────┘
│
▼
┌─────────────────┐
│ Keycloak │
│ (Token Exchange)│
└─────────────────┘
AuthProxy is a single sidecar container that consists of:
The sidecar runs an Envoy proxy with an external processor (ext-proc) filter:
- Envoy Proxy (port 15123 outbound, port 15124 inbound): Intercepts all traffic from and to the application container
- Ext Proc Filter (unified authbridge binary, port 9090): Handles both directions:
- Inbound: Validates JWT tokens (signature, issuer) using JWKS. Returns 401 Unauthorized for invalid tokens.
- Outbound HTTP: Performs OAuth 2.0 Token Exchange (RFC 8693), replacing the
Authorizationheader with an exchanged token for the target audience. - Outbound HTTPS: Envoy detects TLS via
tls_inspectorand passes traffic through as-is usingtcp_proxy(no ext_proc, no token exchange). This ensures HTTPS connections are not broken by the sidecar. - Direction is detected via the
x-authbridge-directionheader injected by Envoy's inbound listener.
To automatically route traffic, an init container (proxy-init) configures iptables rules:
- Outbound (OUTPUT chain): Redirects outgoing traffic to the Envoy outbound listener (port 15123)
- Inbound (PREROUTING chain): Redirects incoming traffic to the Envoy inbound listener (port 15124)
This ensures transparent interception in both directions without requiring any changes to the application code.
The main.go file in this directory is not a core component of AuthProxy. It is an example pass-through proxy that forwards requests to a target service. JWT validation is handled entirely by the Ext Proc on the inbound path. Any application can benefit from AuthProxy simply by being deployed alongside the sidecar—no code changes required.
When deployed as a sidecar, AuthProxy intercepts both inbound and outbound traffic via iptables:
Incoming request
│
▼
┌───────────────────────────────────────────────────────────-───────┐
│ POD │
│ │
│ ┌─────────────┐ ┌──────────────────────────────────────┐ │
│ │ proxy-init │ │ AuthProxy Sidecar │ │
│ │ (iptables) │ │ │ │
│ └──────┬──────┘ │ ┌────────────┐ ┌────────────┐ │ │
│ │ │ │ Envoy │◄──►│ Ext Proc │ │ │
│ │ │ │ :15123 │ │ :9090 │ │ │
│ ▼ │ │ :15124 │ │ │ │ │
│ ┌─────────────┐ │ └─────┬──────┘ └──────┬─────┘ │ │
│ │ │◄──────┼────────│ (inbound) │ │ │
│ │ Application ├───────┼───────►│ (outbound) │ │ │
│ │ (any app) │ │ │ │ │ │
│ └─────────────┘ └────────┼──────────────────┼──────────┘ │
│ │ │ │
└─────────────────────────────────┼──────────────────┼──────────────┘
│ │
▼ ▼
┌──────────────────┐ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ┐
│ Target Service │ Keycloak
└──────────────────┘ │(token exchange) │
─ ─ ─ ─ ─ ─ ─ ─ ─
How it works:
Inbound (incoming requests):
- proxy-init (init container): Sets up iptables PREROUTING rules to redirect incoming traffic to Envoy
- Envoy (port 15124): Intercepts incoming traffic, injects
x-authbridge-direction: inboundheader, calls Ext Proc - Ext Proc (port 9090): Validates JWT token (signature + issuer via JWKS). Returns 401 if invalid.
- Envoy: Forwards validated request to the application
Outbound (outgoing requests):
- proxy-init (init container): Sets up iptables OUTPUT rules to redirect outbound traffic to Envoy
- Envoy (port 15123): Intercepts outbound traffic, uses
tls_inspectorto detect the protocol:- HTTP (plaintext): Calls Ext Proc via gRPC for token exchange, then forwards with the new Authorization header
- HTTPS (TLS): Passes traffic through as-is via
tcp_proxy(no token exchange, preserving the original TLS connection)
The application requires no code changes—traffic interception is completely transparent.
The Ext Proc reads token exchange configuration directly from environment variables at startup:
| Variable | Description | Source |
|---|---|---|
TOKEN_URL |
Keycloak token endpoint URL | Environment variable |
ISSUER |
Expected JWT issuer for inbound validation. Must match Keycloak's frontend URL (the iss claim in tokens). Required for inbound JWT validation. |
Environment variable |
CLIENT_ID |
Client ID for token exchange and inbound audience validation | /shared/client-id.txt file or CLIENT_ID env var |
CLIENT_SECRET |
Client secret | /shared/client-secret.txt file or CLIENT_SECRET env var |
Note:
CLIENT_IDandCLIENT_SECRETare preferentially loaded from/shared/files (when using dynamic client registration with SPIFFE). If files are not available, environment variables are used as fallback.
Note: Target audience and scopes for outbound token exchange are configured per-route in the
authproxy-routesConfigMap, not as global environment variables. See the AuthBridge CLAUDE.md for theauthproxy-routesformat.
Token exchange is typically configured via a Kubernetes Secret:
apiVersion: v1
kind: Secret
metadata:
name: auth-proxy-config
stringData:
TOKEN_URL: "http://keycloak:8080/realms/kagenti/protocol/openid-connect/token"
ISSUER: "http://keycloak.example.com:8080/realms/kagenti" # Required: must match Keycloak's frontend URL (iss claim in tokens)
CLIENT_ID: "authproxy" # Also used for inbound audience validation
CLIENT_SECRET: "<your-client-secret>"The Ext Proc performs OAuth 2.0 Token Exchange as defined in RFC 8693:
POST /realms/kagenti/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&client_id=<client-id>
&client_secret=<client-secret>
&subject_token=<original-jwt>
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&requested_token_type=urn:ietf:params:oauth:token-type:access_token
&audience=<target-audience>
&scope=<target-scopes>
Response:
{
"access_token": "<new-jwt-with-target-audience>",
"token_type": "Bearer",
"expires_in": 300
}This section provides instructions to run the example application with the AuthProxy sidecar, without the full AuthBridge setup (no SPIFFE, no client-registration).
- Kubernetes cluster (Kind recommended)
- Keycloak deployed (or use Kagenti installer)
- Docker/Podman for building images
cd authbridge/authproxy
# Build all images
make build-images
# Load into Kind cluster (set KIND_CLUSTER_NAME if not using default)
make load-images
# Deploy example app with AuthProxy sidecar
make deployThis deploys:
auth-proxy- Example pass-through proxy (port 8080) running alongside the AuthProxy sidecar (Envoy + Ext Proc). JWT validation is handled by the inbound Ext Proc.demo-app- Sample target application (port 8081) that validates exchanged tokens
Port-forward Keycloak (in a separate terminal):
kubectl port-forward service/keycloak-service -n keycloak 8080:8080Run the setup script to create necessary Keycloak clients:
cd quickstart
# Setup Python environment
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# Configure Keycloak
python setup_keycloak.pyThe script creates:
application-callerclient - for obtaining tokens (password grant)authproxyclient - for token exchangedemoappclient - target audience for token exchangeauthproxy-audanddemoapp-audscopes- A test user (
test-user/password)
Create the secret for token exchange credentials, then test the flow. See the Quickstart Guide for detailed instructions covering:
- Creating the
auth-proxy-configKubernetes Secret - Port-forwarding the services
- Testing inbound validation (401 for missing/invalid tokens)
- Testing outbound token exchange (200 for valid tokens)
# Example application logs
kubectl logs deployment/auth-proxy -c auth-proxy
# Ext proc logs (inbound validation + outbound token exchange)
kubectl logs deployment/auth-proxy -c envoy-proxy
# Demo app (target service) logs
kubectl logs deployment/demo-app
# Follow ext proc logs in real-time
kubectl logs -f deployment/auth-proxy -c envoy-proxy# Remove deployments
make undeploy
# Delete Kind cluster (if desired)
make kind-delete📘 For detailed standalone instructions, see the Quickstart Guide.
When running the example deployment:
# Example application logs
kubectl logs <pod-name> -c auth-proxy
# AuthProxy sidecar logs (shows token exchange)
kubectl logs <pod-name> -c envoy-proxy- AuthBridge - Complete AuthBridge overview with token exchange flow
- AuthBridge Demos - Demo scenarios and getting started
- Client Registration - Automatic Keycloak client registration with SPIFFE
- OAuth 2.0 Token Exchange (RFC 8693)
- Envoy External Processing