I have a spring-boot application with 4 microservices, eureka server and a centralized API gateway.
All external traffic is coming via my API gateway to my microservices.
My API gateway (Zuul) is validating and verifying JWT token.
the JWT token is generated by one of my microservices after user login (the users microservice), the token contain the user Id and his roles/authorities.
Now I want to implement role-based security on methods that are present in microservices other than the gateway.
I have tried to use @PreAuthorize
but it's not working out of the gateway (obviously in order to make it work I have to set a Spring Security authentication object in the SecurityContextHolder
in my microservices and populate it with authorities).
So is there any solution to achieve this type of security?
What is the best design to set up security in microservice architecture?
Authentication at API gateway level and authorization at microservices level?
Do I need to use spring security within the microservices or just pass down the roles (append them to the request) after validating the JWT at API gateway level and for example create my own annotations and use Spring AOP to handle authorization?
Within microservices architecture, this means being “secure by design”—keeping security top of mind at every stage of production, from design to build to deployment. When it comes to writing your code, this means implementing a form of continuous stress testing on your architecture.
Implement security using a shared gateway Another approach to implement security for microservices is to use a shared component to implement security for individual microservices. This shared component can be an API gateway or a security gateway that will sit in front of the microservices layer.
There are several ways of how you can secure communication between services. However, these two are the most common: Mutual Transport Layer Security (mTLS) and Json Web Token (JWT).
Microservices architecture provides teams with a new set of potential security risks which need to be addressed. The best way to secure microservices-based solutions is to implement security best practices and patterns into architecture patterns and design and integrate them into the development lifecycle so that data and apps remain protected.
One common argument that people bring against the microservices architecture is that it increases the security risk of the application by expanding the risk surface. This is true in the sense that when we have more microservices exposing functionality to external consumers, we have to protect each service from external consumers.
This is why it’s crucial, at the outset of a microservices build out, to establish some form of automation for scaling security controls. As an organization updates parts of its system, it needs to test it to catch any issues throughout testing.
Looking specifically at security, effective methods for microservices are substantially different than those that work for monolithic applications. For the latter, security teams often use centralized security modules, which cover authentication, authorization, and a range of other critical security measures.
In Spring5 microservices you will be able to find a base to develop a microservice architecture with several of the requisites you are looking for:
Regarding to security, I have developed two different microservices:
Most important ones are well documented using Swagger, as you can see here, and all documented APIs are accessible using an unique gateway Url.
For all classes of every microservice, Junit tests were developed.
At this point, I took several decisions:
1. Is not the gateway the microservice that verifies the security.
Because use the gateway as "firewall" is a less flexible approach. I wanted to decide which microservices need security and every one should manage internally the roles can access to every endpoint. In summary, every microservice has to work with the authorization/authentication but it don't need to know how that functionality is done.
2. Specific microservice to deal with the security
As I told you, I developed 2 different ones, because I wanted to "play" with different options/approaches. The most important advantage is the encapsulation, if "tomorrow" I decide to change Jwt by any other option, I will only need to modify those ones, the microservices that use them will keep the same code (I will explain you soon how the integration was done)
I will explain how the security functionality was integrated between:
1. Every application that manages user and roles, will include in the security microservice a folder similar to the next one, to define its models, repositories to get the required information, etc
2. Global endpoints of the security microservice are defined here. As you can see, they work basically with 2 Dtos:
The main advantage, only the security microservice knows the details about how that functionality was done, the other ones that use it will receive a well known Dtos with the required information.
3. In pizza-service, the security integration is mainly defined in the next 3 classes:
SecurityManager
.security-jwt-service
with the provided "authorization token" (it doesn't know if it is Jwt or any other thing) and receives a well know UsernameAuthoritiesDto
(transforming it into an object of the Spring class UsernamePasswordAuthenticationToken
)Now you can include in your endpoints the required role based security:
pizza-service
was developed using Webflux, you can see an equivalent integration based on a MVC microservice one in order-service
here (in this case I used the "other security service" but is easy to adapt it).
To improve the security and follow the "Oauth approach", the requests to security-jwt-service
need to include the Basic authentication too. As you can see in SecurityManager
class:
private String buildAuthorizationHeader(String username, String password) {
String auth = username + ":" + password;
byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes());
return "Basic " + new String(encodedAuth);
}
The table in database to store that information is the same one used to manage the security configuration of every application: security.jwt_client_details
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With