Map the API
Draw API trust boundaries
Trace identity, data, and authority across clients, gateways, services, queues, databases, caches, and third-party APIs.
Internal traffic is not automatically trusted. A compromised service or leaked worker token is still an attacker path, and “it sits behind the load balancer” is not an authorization policy.
Trace one request end to end
Follow an invoice request through every hop and mark three things: where authentication changes form, where authorization decisions happen, and where data leaves your control.
browser --TLS--> gateway --mTLS--> invoices-service ----> postgres
| | |
cookie verifies JWT, trusts X-User-Id
adds X-User-Id from the gateway only
Record ambient credentials added by platforms and proxies along the way. Validate every boundary according to its own threat model.
Queues and caches are boundaries too. A message consumed by a worker and a cached response served to another user both carry authority across the diagram, and each hop deserves the same question: who proved this identity?
The forged header problem
A gateway may add X-User-Id after authentication. If the application also accepts that header directly from the internet, a caller can choose another identity:
# bypassing the gateway, talking to the service directly
curl -i http://invoices-service.internal:8080/invoices \
-H "X-User-Id: 42"
# HTTP/1.1 401 Unauthorized <- what you want
# HTTP/1.1 200 OK <- identity spoofing, one header away
The fix is structural. The service accepts identity headers only over the mutually authenticated connection from the gateway, and rejects them on any other path. Network reachability alone must never imply identity.
Document header ownership
Document which component may create, replace, or remove every security header. A short table is enough:
X-User-Id created by gateway, stripped if present on ingress
X-Forwarded-For appended by gateway, never trusted from the client
Authorization verified by gateway, not forwarded downstream
Then the direct-service test can prove the application rejects identity claims outside that trusted network path. Without the table, nobody can say whether a header arriving at the service is a platform feature or an attack in progress.
Trace one invoice request from client to database and label who creates each identity value. Bypass the gateway in a test and prove a forged identity header cannot authorize the request.
Lesson completed