Currently doing some research to setup an (azure) api gateway with oauth (jwt token) security.
an external partner/app sends a request to an api endpoint published on the gateway including a valid JWT-token in the header that gets validated by the gateway against AzureAD for example. When validated the request is routed to the backend service. No problems here.
My question is, what is best practice for the external app to obtain that JWT-token (to use for the api call) ?
Obviously, It could send a request to AzureAD with a clientid+secret to obtain a valid JWT token. But to do so it has to call my internal AzureAD directly ? Is this the way to do it ?
or should I expose a 'get-jwt-token' api on my api gateway and route that request to AD ? How should I secure that API ? with basic auth ?
or am I missing something, and is there a much better best/proven practice ?
HOSTING BEST PRACTICE
A reverse proxy or API gateway is placed in front of both APIs and the Authorization Server (AS). This ensures that an attacker who somehow gains access to the back end entry point cannot access data sources.
OAUTH REQUESTS TO GET TOKENS
OAuth requests are typically proxied straight through the reverse proxy / API gateway to the AS with no extra logic. All credentials, auditing of login attempts etc remain in the AS.
MANAGED SERVICES
If using Azure AD as a cloud managed AS, this is a special case: the system is already hardened for internet clients, so most companies don't add their own proxying - though it is possible to do so.
FURTHER INFO
The first of these covers the infra setup and the second gives you an idea of extensibility options once a reverse proxy / gateway is in place.
IAM Primer
API Gateway Guides
Related
I see different opinions among software engineers regarding where to place authentication in a Microservice architecture.
Many support the idea that authentication should be placed at the API gateway level and only the Authorization at Microservice level.
For authentication I mean checking a JWT that was issued after authentication with credentials, for example...
Now, if the API gateway is the only entry point of our backend then it is reasonable to have it in the Frontline when it comes to authenticate the requests.
The problem is that the API gateway, being a proxy, shouldn't really be bound to the underlying services, right?
Let's say that some of the endpoints require authentication and some of them are publicly accessible. I feel that in this case it's better to have it at the Microservice, since the Microservice knows all the details of the API that it exposes.
Otherwise the API gateway should ask the Microservice if the endpoint is public or not or get this information from a database.
But wouldn't be too much of overhead to perform this request to the service/database everytime the gateway is hit?
Furthermore, depending on the framework we use to implement the security layer we might not have the chance to check the accessibility of an endpoint at runtime. So, whenever we make an endpoint public we should redeploy the gateway to get the new information about what requires authentication and what not.
What are your suggestions regarding this topic?
Looking at it strictly from a security perspective.
From what I have seen with microservice architectures, the gateway only performs authentication, each micro service / endpoint needs to handle its own authorization checks at a bare minimum.
So for your public URLs, the gateway would not perform any authentication checks.
For your private/secured endpoints, the gateway will perform authentication checks and authorization checks at a microservice level, but you will still need to handle the business rules to be followed.
Example:
/public/article1 - does not need any authentication or authorization checks
/private/newsletter - requires authentication from gateway, but may not require authorization checks from the microservice
/private/account - should require both authentication + authorization check from gateway as well as from the microservice to make sure you are accessing only your account.
I have a on-premise API that use OAuth, so I use the "Authorization:Bearer ..." header when calling it from on-prem. Now I want to call this API from external using Azure Application Proxy with authentication. I know how to acquire a Bearer Token to authenticate against the Application Proxy.
The problem is that in the same HTTP Call to the on-prem API from external, I need to have 2 different "Authorization:Bearer ..." headers, one for the Application Proxy and one for the on-prem API.
I cannot just have 2 Authorization headers, right? So how do I call my on-prem API from external?
Edit : I've never found the real solution so I built an "On-Premise Proxy" that swap Authorization:Bearer after the Azure App Proxy. Here's how it works :
The outside app inserts 2 headers with the call to Azure App Proxy (AAP). First is Authorization:Bearer with the token required by AAP. The second is a dummy header "AuthorizationOnPrem" with the token that is required by the app behind the Azure Proxy (on-prem).
The Azure Proxy redirect the call to my custom "On-Premise Proxy".
This On-Prem Proxy copy the token from AuthorizationOnPrem to Authorization.
Then the On-Prem Proxy call the real on-prem app with the same data that it got called but with the right token.
I know it's quite patched but it worked for me with the on-prem app I needed. And it was surprisingly easy to do. Might not scale well though.
I'm trying to build a microservice architecture. I've learned some benefits of API gateway like: load balancing, invoking multiple microservices and aggregating the results, cache management etc. So I decided to include it in my system.
My question is whether I should implement authorization in gateway layer or separately in each microservice endpoints ? For example authenticating user on gateway and passing user claims in decrypted form to be used in authorization logic to each service call ?
It seems like it make sense and saves processing time to authorize some aggregates before even calling each service. However, authorization logic is really a concern of individual service.
What is your advice ?
each microservices endpoint. implementing the authorization in API gateway will make your system rigid. If at any later stage you have to separate logic for authorization (say, internal user, external user, open api). This will be very difficult to incorporate.
Authorization should happen at each API level.
You can use API Gateway Pattern / API Gateway. Then you can also offload the authentication/authorization responsibility of the microservice. It will be easy for user or developer that is calling the services. API GW support External /Internal GW even. It may support Role base permissions. eg: WSO2 APIM.
You will get below advantages when you have API /MS GW:
An API Gateway is the single point of entry for any microservice call.
It can work as a proxy service to route a request to the concerned microservice.
It can aggregate the results to send back to the consumer.
This solution can create a fine-grained API for each specific type of client.
It can also convert the protocol request and respond.
I'm reading a tutorial provided by AWS explaining how to break up a monolithic NodeJS application into a microservice architectured one.
Here is a link to it.
One important piece is missing from the simple application example they've provided and that is user authentication.
My question is, where does authentication fit into all this?
How do you allow users to authenticate to all these services separately?
I am specifically looking for an answer that does not involve AWS Cogntio. I would like to have my own service perform user authentication/management.
First, there is more than one approach for this common problem.
Here is one popular take:
Divide your world to authentication (you are who you say you are) and authorization (you are permitted to do this action).
As a policy, every service decides on authorization by itself. Leave the authentication to a single point in the system - the authentication gateway - usually combined inside the API gateway.
This gateway forwards requests from clients to the services, after authenticating, with a trusted payload stating that the requester is indeed who they say they are. Its then up to the service to decide whether the request is allowed.
An implementation can be done using several methods. A JWT is one such method.
The authenticator creates a JWT after receiving correct credentials, and the client uses this JWT in every request to each service.
If you want to write your own auth, it can be a service like the others. Part of it would be a small client middleware that you run at all other service endpoints which require protection (golang example for middleware).
An alternative to a middleware is to run a dedicated API Gateway that queries the auth service before relaying the requests to the actual services. AWS also has a solution for those and you can write custom authentication handlers that will call your own auth service.
It is important to centralize the authentication, even for a microservices approach for a single product. So I'm assuming you will be looking at having an Identity Service(Authentication Service) which will handle the authentication and issue a token. The other microservices will be acting as the service providers which will validate the token issued.
Note: In standards like OpenID connect, the id_token issued is in the format of JWT which is also stateless and self-contained with singed information about the user. So individual Microservices doesn't have to communicate with the authentication service for each token validation. However, you can look at implementing or using Refresh tokens to renew tokens without requiring users to login again.
Depending on the technology you choose, it will change the nature how you issue the tokens and validate.
e.g:
ExpressJS framework for backend - You can verify the tokens and routes in a Node Middleware Handler using Passport.
If you use API Gateway in front of your Microservice endpoints you can use a Custom Authorizer Lambda to verify the tokens.
However, it is recommended to use a standard protocol like OpenID connect so that you can be compatible with Identity Federation, SSO behaviors in future.
Since you have mentioned that you are hoping to have your own solution, it will come also with some challenges to address,
Password Policies
Supporting standards (OpenID Connect)
Security (Encryption at rest and transit especially for PIDs)
SSO, MFA & Federation support etc.
IDS/IPS
In addition to non-functional requirements like scalability, reliability, performance. Although these requirements might not arise in the beginning, I have seen many come down the line, when products get matured, especially for compliance.
That's why most people encourage to use an identity server or service like Cognito, Auth0 & etc to get a better ROI.
I tried to implement custom Authentication via a authentication endpoint in an azure mobile app. I've created an Api Controller, that creates the Jwt using Azures AppServiceLoginHandler.CreateToken method. When I post to this controller with turned off Azure App Service Authentication, I get a token, but when I want to use it later, I always receive a "401 Unauthorized".
But when I turn the setting on in the Azure Portal, and send the very same request
I get:
The requested resource does not support http method 'GET'.
I'm not changing any code, and I'm certainly using a POST request - The exact same request, that works with turned off App Service Authentication.
My Code is essentially the same as here:
https://www.newventuresoftware.com/blog/custom-authentication-with-azure-mobile-apps
Could someone enlighten me here? Do I need additional configuration somewhere?
As adrian hall's book about Custom Authentication states as follows:
You must turn on Authentication / Authorization in your App Service. Set the Action to take when request is not authenticated to Allow Request (no action) and do not configure any of the supported authentication providers.
For custom authentication, you need to turn on the Authentication / Authorization in your app service for authenticating your token. Moreover, I would recommend you leverage fiddler to capture the network traces to narrow this issue. Additionally, you need to make sure that you send the custom login request with HTTPS. Details, you could follow this similar issue.