The era of "Castle and Moat" security is over.
We used to think that if we just had a really strong firewall, we were safe. But in a cloud-native world, the bad guys are already inside the castle. Code injection, compromised containers, and side-channel attacks mean we cannot trust a request just because it comes from 192.168.x.x.
Zero Trust means exactly what it says:
- Verify explicitly.
- Use least privilege access.
- Assume breach.
In this guide, we will implement this in a Spring Boot ecosystem using mTLS and Custom Authorization Managers.
How does mTLS enforce zero trust between Spring Boot microservices?
Before we even talk about Users, Services must trust each other.
Standard SSL implies the server has a certificate. mTLS implies the client has one too. It's like checking ID at the door, both ways.
In Spring Boot, enabling this is configuration-driven.
server:
ssl:
client-auth: need # This enforces mTLS
key-store: classpath:identity/service-keystore.p12
key-store-password: changeit
trust-store: classpath:identity/truststore.p12
trust-store-password: changeit
When Service A calls Service B, it must present a valid certificate signed by your internal CA (Certificate Authority). If a rogue container tries to curl your API without the cert, the connection is dropped at the TCP handshake level. Brutal, but effective.
Why is JWT propagation essential for zero trust service communication?
Just because Service A is allowed to talk to Service B (mTLS), doesn't mean the User initiating the request is allowed to see the data.
We must propagate the user's JWT token across the mesh.
Using Spring Cloud Gateway or manual WebClient filters, we forward the Authorization header.
// Propagating the Token
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
return ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.map(auth -> {
if (auth.getCredentials() instanceof AbstractOAuth2Token token) {
return ClientRequest.from(request)
.headers(h -> h.setBearerAuth(token.getTokenValue()))
.build();
}
return request;
})
.flatMap(next::exchange);
}How does ABAC replace role-based access in zero trust architectures?
Roles (ROLE_ADMIN) are often too broad. Zero Trust demands context.
Existing @PreAuthorize annotations are great, but for complex logic, you want a Custom Authorization Manager.
Let's build a policy that allows access only if:
- The user has the
readscope. - The user is in the same
regionas the resource. - The request comes from a trusted device IP.
@Component
public class ContextAwarePolicyManager
implements AuthorizationManager<RequestAuthorizationContext> {
@Override
public AuthorizationDecision check(
Supplier<Authentication> authentication,
RequestAuthorizationContext object
) {
Authentication auth = authentication.get();
HttpServletRequest request = object.getRequest();
// 1. Check Scope
boolean hasScope = auth.getAuthorities().stream()
.anyMatch(a -> a.getAuthority().equals("SCOPE_read"));
if (!hasScope) return new AuthorizationDecision(false);
// 2. Check Custom Attribute (Region)
String userRegion = ((Jwt) auth.getPrincipal())
.getClaimAsString("region");
String resourceRegion = request.getParameter("region");
if (!Objects.equals(userRegion, resourceRegion)) {
return new AuthorizationDecision(false);
}
// 3. Risk Engine Check (Mock)
boolean isSafeIp = RiskEngine.evaluateIp(request.getRemoteAddr());
return new AuthorizationDecision(isSafeIp);
}
}Applying the Policy
Now, wire it into your security chain.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
// Apply our custom manager to specific detailed routes
.requestMatchers("/api/v1/sensitive/**")
.access(new ContextAwarePolicyManager())
.anyRequest().authenticated()
);
return http.build();
}Conclusion
Zero Trust is not a product you buy; it's a discipline you practice. By combining transport security (mTLS) with identity propagation and rigorous, attribute-based policy enforcement, you build effective defense-in-depth for your microservices.
For further reading, see the NIST Special Publication 800-207: Zero Trust Architecture, the Spring Security Authorization Architecture, and the mTLS with Spring Boot Guide.
Keep Reading
- The Component Revolution: Mastering Spring Security 6.x — The SecurityFilterChain foundation this guide's policies plug into.
- Full-Stack Social Identity: Spring Security + Next.js + Auth.js — Add OAuth2 and JWT propagation to your zero trust mesh.
- AI-Driven Anomaly Detection with Spring Security — Detect threats in real time using Spring Security events and AI.
