Api gateway and microservice architecture with bearer token authorization in KTOR - microservices

I have set up a gateway and a microservice with ktor. I want authentication on microservice level. I have made httpclient for a service in gateway, but i cannot seem to find a way to forward bearer token from api gateway request to httpclient request. There are lots of tutorials where httpclient is created with bearer token.
One way i found was manually add authorization header to every request i make but this is not what i want. I would like this process to be automatic. Any ideas? Maybe ktor might not be good for api gateway?

Related

Disable or bypass OAuth security for microservice-to-microservice communication in Spring Boot

I have some microservices in Spring Boot and my front end application is in angular. I am using OpenID Connect for authentication and authorization. Right now, in my application, when the angular app is loaded, it redirects the user to the authentication server and after login the token is received which is sent by the angular application in each HTTP request to the resource servers. Now I have a question. My microservices also communicate with each other but as each microservice is acting as a resource server and the Rest APIs are secure now, so microservices can not communicate. What I want to achieve is that the requests which are sent by the user from the angular app should contain a token and those requests should be verified but I want to bypass or disable OAuth security for inter service-service communication between microservices. Is there any way to achieve this in Spring Boot?
Do not disable OAuth2 security in your micro-services:
if the inter-services request has the context of user (issued to satisfy part of an authorized request) just forward the original access-token
if inter-services request is not originated by a user request / event / callback,... (scheduled task for instance), then it is possible to acquire an access-token using client credentials flow. Authorization-server should be configured to attach required roles to each client when it issues access-tokens with client credentials flow.
In first case, you can access bearer token from the Authentication in the security context. Add this Bearer string as Authorization header to the requests to other micro-services.
In second case configuring REST client (WebClient, RestTemplate, FeignClient, ...) with client credentials is usually enough for it to automatically fetch an access-token from the authorization-server and add it as bearer header before sending requests to the resource-server.

How do I implement the basic authentication in Spring Cloud API Gateway?

I have 2 secured resource microservices and 1 authentication service and another API Gateway.
Authentication service can generate JWT Token given username and password. It also can validate a JWT token.
So, I want to implement security at the API Gateway only such that on receiving a request, it will first fetch a bearer token from the authentication service and forward the request to the secured resource service. I would like to get some idea how to implement that in API Gateway. Should I make it just in an aggregate fashion, like it would be a sync call which will first make a request to auth service and next forward the request to resource service?
Now, if I want to add the support of OAuth as well, which I know the spring cloud API Gateway already has the support for this via global filters.
But, I am wondering about the legacy bearer token which is generated by the custom authentication service.. How do I ensure this?
Any suggestion would be appreciated.
Thanks in advance!

Relaying the incoming token downstream to other services

I'm trying to understand 100% how a Resource Server works, relaying the incoming token downstream to other services.
I have a microservice architecture with spring boot eureka, with Bearer authentication against an #EnableAuthorizationServer.
I use an Edge Service in zuul with #EnableZuulProxy and #EnableOAuth2Sso for request entry, and I wanted security to be centralized at that point, but of course, I can't leave the microservices without security and each of them is an #EnableResourceServer.
Everything works ok.
The question is:
Either with a security.oauth2.resource.user-info-uri pointing to the oauth server or to the edge service, that bearer token is always validated against the oauth server, i.e. if it passes through 10 microservices a request, will it validate the token 10 times against the oauth server?
Isn't there any way that I don't have to request 10 times to the oauth server if the token is valid?
All right,
It seems that for a Bearer token type, it is always necessary to authenticate on each resource server against the authentication server.
The solution is to use JWT tokens.
As explained in:
https://developer.okta.com/blog/2018/04/02/client-creds-with-spring-boot#extra-credit-reduce-the-number-of-calls-to-the-authorization-server
We use signed JWTs which means you can validate them locally instead of making an additional request from the API service to the authorization server on each request.
That's it.

Implementing authentication and authorization using Zuul Proxy, Oauth2 on REST Microservices

I am trying to implement the above architecture in the workflow with Spring Boot.
Web client makes a request to Resource Server (Microservices Endpoints) through Zuul Proxy.
Zuul Proxy redirects to oauth2 server for authentication.
Oauth2 redirects to Zuul Proxy if the request is authenticated or not.
If not authenticated, Zuul redirects Web client with an unauthenticated response.
If Authenticated, Zull proxy redirects to the requested microservice endpoint.
Microservice endpoint checks if the user is authorized (user level access) to access the resource or not.
Microservice also could make internal rest call to other microservice.
Finally, the requested resource is sent back to the client.
I want to make sure I am following the correct workflow.
I would like to know if there is any solution which has implemented a similar kind for securing microservices APIs.
I have confusion on:
How can we pass the user details to the microservices so that the microservices can do their own level of user authorization?
Should the OAuth2 Access Token header be passed to each microservices such that microservices can validate the token separately?
Should each Microservice use secret credentials to validate the access token so that the token cannot be forged along the request chain?
I know its a bit of lengthy question. But I have not found a proper solution to above architecture.
Unfortunately, I don't have complete answer, only some parts:
Once JWT token is available to the zuul proxy then every microservice can authorize requests by configuring its resource server, e.g.
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().anyRequest().access("#oauth2.hasScope('microserviceA.read')").and()
.csrf().disable()
.httpBasic().disable();
}
Scopes could be managed by the oauth microservice with a database - basing on the client credentials it will take the scopes info and encode into JWT token.
What I don't know at the moment - how to make the zuul proxy to use "web client" credentials to authorize itself by the oauth - I don't want to hard-code zuul proxy credentials because then the web-client creds won't be used.
I've just posted similar question on this topic:
Authorizing requests through spring gateway with zool via oauth server
update:
I've found article describing almost this configuration (without eureka, but it doesn't that add much complexity from my experience): https://www.baeldung.com/spring-security-zuul-oauth-jwt, there is github project with source code. The source code is unfortunately not polished as it's being used by the author for his commercial courses.
But I've managed to build from his examples working set.
Summary: in the described architecture every resource server (microservice A, B, ..) receive JWT token forwarded by the zuul proxy/gateway from the requesting client. The token is forwarded in a request header. If there is no valid token provided then the gateway will redirect the request to authorization page.
Also every resource server can check the token with the oauth service and if required do scope checking as I wrote above.
I've been struggling with same security design issue for microservice architecture based on spring cloud solution. I only find this article shedding some light on it: https://developer.okta.com/blog/2018/02/13/secure-spring-microservices-with-oauth
But it's pertaining to Okta sso service provider, not a generic solution to other oauth2 server like keycloak.
I also saw some solutions on how to protect gateway and microservice with oauth2 server like this one:
https://github.com/jgrandja/oauth2login-gateway
But it doesn't take into consideration the web client.
I am not sure whether you were able to resolve this, I can see this is not answered yet, but there is a way you can pass all information from JWT to all downstream microservices.
Write your own ZuulAuthenticationFilter, and then create below method
private void addClaimHeaders(RequestContext context, String token) {
try {
Map<String, Claim> claims = jwtTokenVerifier.getAllClaims(token);
claims.forEach((key, claim) -> {
context.addZuulRequestHeader("x-user-info-"+key, String.valueOf(claim.as(Object.class)));
});
}catch(Exception ex) {
log.error("Error in setting zuul header : "+ex.getMessage(), ex);
}
}
this way, you will get information from JWT in headers in each microservice, headers that starts with "x-user-info-" will have your JWT details
There is an implementation of the above architecture in following link:
https://www.baeldung.com/spring-security-zuul-oauth-jwt

How to pass on the original Oauth2 bearer token between Spring microservices

We have a few Spring micro services which communicate with each other via rest (Spring's RestTemplate). There is Oauth2 authorization applied in all of them and the JWT token is extended with a few custom fields (i.e. userRole, userId etc).
My problem is the following:
When we call a service which also calls another micro service via RestTemplate, the original bearer token (Oauth2) is not forwarded when the micro services are communicating with each other. We can't get a response from other services, because we are unauthorized. I can't find a neat solution.
Note, that we do not want to acquire a new token for the second call, because that would affect our performance. That is what OAuth2RestTemplate is doing, but we just want to pass the original bearer token.
As I researched on Stackoverflow, one solution would be to manually add the bearer + token as an Authorization header, and use .exchange() , but I think there should be a configuration in spring, which will make RestTemplate pass on the original Authorization header, or something similar.
I had the same issue while testing in local. The below configuration in my application.yml file fixed it. The token gets passed from one service call to another.
hystrix:
command:
default:
execution:
isolation:
strategy: SEMAPHORE
thread:
timeoutInMilliseconds: 5000

Resources