I am currently in the middle of developing a little webpage. The backend will be consisting of multiple microservices, mostly spring boot and the fronted will be created with angular. When I host the finished services, I plan on using the NGINX reverse proxy as the sites entry point. So far nothing special.
This question arose while researching how to best secure this structure. I want to use Keycloak as the idenetity management system, which is good to know for the examples.
What I found is:
- The Keycloak Client Adapter for Spring Boot, with which I can authenticate and authorize a user wanting to use a specific endpoint.
- The auth_request module for NGINX to authenticate the user before the request is even proxied to the specified endpoint.
So, I researched into those and the question wether I should authenticate every microservice on its own, or authenticate the requests in one central place. Well, logic tells me (and many people on the internet) that the centralized approach has many advantages over the "everyone on its own" one, mostly security and latency reasons.
BUT. Is this really the best approach? From what I found, the module from NGINX can only authenticate; asking Keycloak "is this a logged in user?" which is answered by a HTTP 200 for yes and 401/403 for no, respective flows commencing. But I cannot authorize can I? So I would have to send the token to the services anyway to authorize the user, i.e. check if they have the roles needed to use this endpoint. For which I could use the Keycloak Client Adapter in Spring Boot, which authenticates AND authorizes, but then the authentication would commence twice. Or I could implement my own solution which just authorizes a user. Still isn't it better then to just forward the token from the reverse proxy entirely without it authenticating before?
It doesn't seem to me, that there are many security reasons for which I would have to centralize the authentication or not, so I am drawn to the idea to just push the token through and let the services handle this, with a already well and tested solution the adapter provides. Most of the services do not even talk to each other, so there wouldn't be a redundant auth flow between them.
Am I missing something crucial? Have I missunderstood something? Or are there strong arguments for authentication with NGINX instead?
If any one of you has a fitting answer and/or site or book or whatever where I can educate myself with, I would very much appreciate the help. Thanks in advance and have a nice day.
CodePudding user response:
You might use NGINX as filter for very basic assertions like "is user authorized?", but it will definitely not be as handy as spring security can be for advanced business security requirements like this one: @PreAuthorize("is(#username) or isNice() or onBehalfOf(#username).can('greet')")
.
Don't use Keycloak adapters, it is deprecated (just look at transient dependencies to spring-boot and spring security: versions are scary).
Use either:
spring-boot-starter-oauth2-resource-server
but requires quite some Java conf to setup a decent resource-server micro-service (with CORS, CSRF, authorities mapping, access-denied handler, public and protected routes, ste-less session management, etc.)spring-addons
which provides with a lot of resource-servers configuration from properties and is declined in 4 flavors for servlets / reactive apps using JWT-decoder / token-introspection
Those two solutions are demoed in the tutorials from which is taken first sample