Cheat sheet — Identity-Aware Access (Pomerium)¶
Companion to Module 06 — Identity-Aware Access · CC BY 4.0 — print it, pin it, share it.
Last reviewed: 2026-07
Pomerium — the identity-aware proxy¶
Pomerium bundles three services (split in production, one container in the lab): authenticate (OIDC redirect dance) · authorize (policy against claims) · proxy (forwarding).
# config.yaml — a route with an inline policy (PPL)
routes:
- from: https://app.example.com
to: http://backend:8080 # upstream — no public listener
policy:
- allow:
and:
# bind to IdP-managed GROUPS/roles, not raw email strings
- claim/groups: [engineering]
- domain: [corp.com]
- deny:
or:
- user: [contractor@corp.com]
pomerium -config config.yaml # run the proxy
# the proxy signs its assertion with a key published at:
curl -s https://app.example.com/.well-known/pomerium/jwks.json | jq # JWKS for backend verification
The identity header the backend must trust¶
The proxy injects X-Pomerium-Jwt-Assertion — a JWT signed by Pomerium's key. The backend verifies:
1. Fetch Pomerium's public key from /.well-known/pomerium/jwks.json (cache it).
2. Verify the assertion's SIGNATURE against that key.
3. Check aud (this service), iss (your Pomerium), exp (not expired).
4. ONLY THEN read the identity/claims inside — never before.
Test the deny path (the part AI-drafted policy skips)¶
# 1. no token → dropped, not a 401 login page reaching the backend
curl -sS -o /dev/null -w "%{http_code}\n" https://app.example.com/ # expect a redirect/deny, never 200 from backend
# 2. FORGE a client-supplied identity header — must be ignored
curl -H "X-Forwarded-User: admin@corp.com" https://app.example.com/ # must NOT authenticate you
curl -H "X-Forwarded-Email: admin@corp.com" https://app.example.com/ # same — a plain header is free to set
# 3. DIRECT-TO-BACKEND bypass — the backend must refuse a request that skipped the proxy
curl -sS -o /dev/null -w "%{http_code}\n" http://backend:8080/ # must not be reachable around the proxy
# 4. a valid session → trace the injected assertion the backend actually verifies
curl -H "Cookie: _pomerium=$SESSION" -i https://app.example.com/whoami
Gotchas worth remembering¶
- Trust only the signed assertion — never a plain client-supplied header.
curl -H "X-Forwarded-User: admin@corp.com"costs nothing; a backend that believes an unsigned identity header has handed authentication to the attacker. VerifyX-Pomerium-Jwt-Assertionagainst the JWKS +aud/iss/expbefore reading any claim. CVE-2026-40575 (OAuth2 Proxy, CVSS 9.1) is this exact class made into a CVE. - No bypass. Every path to the backend must pass through the proxy. A published port, a flat-network
route, or a teammate's
docker run -pmakes the whole deny path moot — no request ever hits the identity check. "No open ports" is a precondition, not a nice-to-have. - Header-forgery and bypass are duals of one rule: every path traverses the proxy, and the backend believes only what the proxy cryptographically signs. Test both deny paths, not just the allow path.
- Bind policy to IdP-managed groups/roles, not email-domain strings.
allow if email ends in @corp.combreaks the moment the IdP also issues@corp-partner.comtokens or you must distinguish a finance analyst from a junior dev. The IdP is the system of record; the proxy is the enforcement point. - A deny is not a 401 — it's a dropped packet. No valid token means the backend never sees the request. Attackers scanning the IP see nothing.
- AI policy skews permissive. The only way to know a policy is tight is to send a request that should fail and confirm it does — encode that verdict as a regression test so a future edit can't silently reopen the deny path.
Comments
Sign in with GitHub to comment. Choose the type: Feedback (errors or suggestions on this page) · Hints (help for fellow learners — no spoilers) · General (anything else).