6 September 2023
Microservices provide great flexibility in building complex applications, but securing them brings unique challenges. With multiple independent services, you need to think about security at the architecture level in addition to the implementation in individual services.
In this guide, we'll look at various options for securing microservices using the widely adopted Spring Security framework.
JBI Training is the perfect place to start your journey why not enquire about out Spring Boot Microservices training: Master the art of building microservices with Spring Boot. Understand how to create efficient, production-ready microservices using the Spring framework, enabling rapid development and deployment.
Some key security challenges with microservices:
Traditional monolithic applications have a single authentication and authorization system like a session-based cookie. But microservices require decoupled security mechanisms to authenticate across multiple domains.
Microservice endpoints are exposed on the network, requiring service-to-service calls to be secured. Centralized key management is also more difficult with independent services.
By thinking about these needs up front, we can design appropriate security into our architecture.
Spring Security provides comprehensive security capabilities for Spring-based applications. It supports both authentication at the web request level and authorization to restrict access to specific resources.
Some key features:
We'll cover how these can be applied to common microservices security requirements.
A core requirement is being able to authenticate users across multiple services and authorize access to specific endpoints and data.
For user sign-on across services, Spring Security supports stateless JWT (JSON Web Token) authentication.
The auth service signs and issues JWT tokens upon successful authentication. Other services can then validate the JWT signature to authenticate requests. No shared session state is required.
Configure Spring Security to use JWT:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.jwt();
}
}
The jwt()
configures JWT validation. The token can be passed in the Authorization
header.
To restrict access, services can check authorities or roles embedded in the JWT claims.
http
.authorizeRequests()
.antMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated();
This requires the "ADMIN" role to access /admin
endpoints.
Roles and claims can also be checked in method security:
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
public void adminTask() {
// ...
}
Spring Security provides tight integration with OAuth2 authorization servers like Okta or Auth0 for authentication.
Rather than implementing a custom auth service, you can delegate to an external OAuth2 provider.
Configure a OAuth2LoginConfig
to enable OAuth2 login:
@EnableWebSecurity
public class OAuth2LoginConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login();
}
}
User info is fetched from the provider to perform authentication. No session or tokens are maintained by the app.
Since microservices communicate over the network, we need to secure those service-to-service calls.
Enable TLS in Spring Security to encrypt all traffic:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// ...
.requiresChannel()
.anyRequest().requiresSecure();
}
}
requiresSecure()
enforces HTTPS for all requests.
Service-to-service calls should always use TLS to prevent eavesdropping or man-in-the-middle attacks.
Individual services can be authenticated to each other through certificates or shared keys.
For example, a certificate can be generated for each service and packaged in its Docker image. Other services validate the certificate when calling that service.
Spring Security can validate the certificate and authenticate the calling service:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// ...
http.x509()
.subjectPrincipalRegex("CN=(.*)")
.userDetailsService(customUserDetails);
}
}
The subject principal is extracted from the cert as the user. A custom UserDetailsService
can then load authorities for authorization.
With multiple service instances, clients need to load balance across them.
Spring Cloud LoadBalancer can create a client-side load balancer:
@Bean
LoadBalancerClient loadBalancerClient() {
return new LoadBalancerClient();
}
@Bean
RestTemplate restTemplate(LoadBalancerClient loadBalancerClient) {
return new RestTemplate(loadBalancerClient);
}
The LoadBalancerClient
automatically distributes calls based on service discovery registrations.
Microservices also bring challenges for managing security credentials like keys and certificates.
To simplify key distribution, a centralized service like HashiCorp Vault can be used to generate and rotate keys. Services request keys on startup and renew periodically.
Spring Cloud Vault Sec integrates with HashiCorp Vault for fetching secrets:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${vault.token}")
String vaultToken;
@Bean
VaultTemplate vaultTemplate() {
return new VaultTemplate(vaultToken);
}
@Bean
@DependsOn("vaultTemplate")
DataSource dataSource() {
VaultResponse response = vaultTemplate.read("secret/myapp/config");
return DataSourceBuilder.create()
.username(response.getData().get("username"))
.password(response.getData().get("password"))
.url(response.getData().get("url"))
.driverClassName("com.mysql.jdbc.Driver")
.build();
}
}
Here the Datasource credentials are externalized to Vault secrets. Services access Vault through the VaultTemplate
to securely obtain secrets at runtime.
Finally, we need visibility into how users and services are accessing our systems.
Spring Security provides events for login success/failure that can be used to track authentication activity.
@Component
public class AuthenticationEventsHandler {
@EventListener
public void authenticationSuccess(AuthenticationSuccessEvent event) {
// Handle login success
}
@EventListener(AuthenticationFailureBadCredentialsEvent.class)
public void authenticationFailed(AuthenticationFailureBadCredentialsEvent event) {
// Handle login failure
}
}
These events can be used with monitoring tools to identify suspicious patterns or security incidents.
Access logs also provide audit visibility into authorization failures - requests for data a user can't access. These can indicate compromised credentials or insider threats.
Securing microservices introduces challenges like cross-service authentication, network encryption, and distributed credentials.
Spring Security provides authentication, authorization, TLS, integration with external Identity providers, and events to address these needs.
Centralised user management, service-to-service authentication, and runtime secret injection help overcome distributed security complexities.
Monitoring authentication events and access logs gives visibility into compromised users or services.
Adopting these patterns will help build secure and resilient microservices powered by Spring.
In the world of modern software development, Microservices Architecture stands as a pivotal paradigm for building scalable and maintainable applications. Explore our range of courses at JBI Training, each tailored to empower you with the skills to excel in the realm of microservices and software architecture. You might enjoy our previous article How to Build Microservices with Spring Boot Step-by-Step Guide or consider some of our training.
Enrol in these courses and empower yourself to navigate the dynamic world of microservices architecture and software development. Equip yourself with the tools and knowledge to design, build, and manage microservices-based systems that excel in scalability, flexibility, and performance.
CONTACT
+44 (0)20 8446 7555
Copyright © 2024 JBI Training. All Rights Reserved.
JB International Training Ltd - Company Registration Number: 08458005
Registered Address: Wohl Enterprise Hub, 2B Redbourne Avenue, London, N3 2BS
Modern Slavery Statement & Corporate Policies | Terms & Conditions | Contact Us