1
0
Files
spring-security-demo/service-to-service/docs/07-choosing.md

54 lines
2.8 KiB
Markdown

# 7. Choosing
*Prev: [6. mTLS](06-mtls.md)*
## Which propagation strategy
| Situation | Use |
|---|---|
| One hop, same team, same trust boundary, audit needs the user | Relay |
| A job with no user: scheduler, message listener, reconciliation | Client credentials |
| The next hop is another team's service, and audit needs the user | Token exchange |
| The next hop is outside your organisation | Client credentials, and a token minted for them |
The honest default is **relay inside a boundary, exchange across one**. Client credentials is
the right answer more often than it is used for work with no user attached, and the wrong answer
whenever somebody will later ask "who did this?".
## Do you need any of this?
A callout that belongs in every article on this subject and is usually missing:
> **If your services are a single deployment behind one ingress, all of this is cost with no
> benefit.** Two Spring Boot applications in one VPC, called by one another, with no
> multi-tenancy and no external partner, do not need an authorization server, a token exchange
> grant or a mesh. Network-level isolation plus a shared secret is a defensible design, and it
> is a design you can reason about at 3am. The machinery in this repository earns its keep when
> there are enough services, enough teams, or enough regulatory pressure that "who called this,
> on whose behalf, with what permission" has to be answerable from a log rather than from
> memory.
## A checklist that is short on purpose
1. Every resource server validates **audience**, not just signature and expiry (chapter 4).
2. No relay reads `SecurityContextHolder` from a thread the request did not create (chapter 2).
3. Every service has a `SecurityFilterChain` bean, so nothing falls back to Boot's Basic default
(chapter 5).
4. Client registrations name `token-uri` / `jwk-set-uri` rather than `issuer-uri`, unless you
want a startup-ordering dependency (chapter 1).
5. If identity arrives in a header, something upstream strips that header from every external
request, and you can name the component that does it (chapter 6).
6. Token lifetimes are short enough that the audience gap in item 1 is bounded even when
somebody forgets.
## Further reading
- [Spring Security Context Propagation](https://ankurm.com/spring-security-context-propagation-complete-guide/) — why the async relay returns 401
- [The Spring Security Filter Chain Explained](https://ankurm.com/spring-security-filter-chain-explained/) — where `BearerTokenAuthenticationFilter` sits
- [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) — token exchange
- [RFC 9068](https://datatracker.ietf.org/doc/html/rfc9068) — the `at+jwt` access token profile
- [RFC 8705](https://datatracker.ietf.org/doc/html/rfc8705) — mTLS client authentication and certificate-bound access tokens
---
*Prev: [6. mTLS](06-mtls.md)*