I want to understand pron and cons of different implementation of single sign-on authentication and authorization in microservice environment. I came up with 3 solutions (see the diagram below).
What pron and cons does each option have? (I'm using Ocelot as gateway and IdentityServer4 as identity provider). Microservice A and Microservice B have it's own UI (SPA applications), Microservice D is REST API.
I will try to explain my point of view:
Option 1:
I understand that first of all you have to be logged against an identity server using user credentials and then create the cookie. I wouldn't recommend this option, first because as I can see you don't validate the cookie and it contains the userId that it is propagated to the servers, so the user could change the userId to get information about other users. And second, because this approach makes you to have a cookie policy
Option 3:
As I can see, in this option you are doing the login on each application. So, if in the future you have other applications you will have to implement the login page and logic in each of them.
Option 2:
I think it is the best of them, but I would make a change. First of all, it is a good option to have an api gateway that take care of cross concerns like authentication/authorization talking to the identity server to request acces tokens and to try to call the services. Doing this you will have a unique login point and the gateway could check the permissions (scopes) to do the actions required by the user, so the services wouldn't have to take care of this. The only thing I would change is the validation in each of the services. Because the nature of JWT tokens, it will contains all info needed to validate itself (expiration time, issuer, audience.. etc) so this validation won't be necessary. And to avoid the possibility of manipulation, the best approach is to sign the token by trusted certificate and let the gateway check the integrity, so when the token reach the services you have the confidence that this is a valid user with proper rights to do the action
Related
I am developing a new distributed application. I already have some operational microservice and it works fine. I am now implementing authentication/authorization and I have serious doubts.
enter image description here
1.- First I authenticate with the JWT microservice and obtain a token. This token contains the claims that indicate which properties that user has access to.
2.- This token has an expiration of 3 days. So when I make a request to a microservice I attach the token.
3.- However, when the request reaches any microservice controllers, how do I confirm that the token is valid and the user has permisions for this controller function? or if the claims have changed since the token was generated ?
Is it necessary to make another request to the JWT microservice to validate it?
Is there a more efficient way to validate each user's permissions in microservice controllers. I would like to not have to send another request to the JWT microservice again.
I have read that an API Gateway is sometimes implemented as an access point. If so, could the user access permissions be validated in the API Gateway? What technology is the most optimal (Camel, Spring Cloud)? To this, I add that we are deploying these microservices in Google Cloud Kubernetes (GKE).
enter image description here
If someone who has experience in microservices can enlighten me.
Thank you
There are two major approaches to token validation: local and rpc call.
Local is way more popular. This is the approach AWS, GCloud and Azure take. The token itself has all required information - who is the user, what are permissions. And the token is signed.
When this type of token is received on a service (or api gateway), the service can validate the token locally - by checking signature and expiration. Base on validated content of a token, the service decides what to do.
It is worth mentioning, that this approach does not allow token to be revoked. There are few workaround, but most solutions just rely on shorter lived token and issue a refresh token. (please, let me know if this is topic to talk more).
Having local validation also opens an interesting approach to limiting scope - when a system issues an access token, the token can have limited access - subset of whatever a user can do. This is nice feature to limit risks.
The other method is to call some internal service for token validation. This seems like easier to understand approach, but it scales purely.
One more thing to note: where token should be checked - on api gateway or on a service itself. Traditionally, access used to be checked on boundaries - api gateway in your case. These days, companies move to Zero Trust Architecture - which means access is verified on every service - there is no implicit trust.
We are building a web application in microservices architecture.
We have a service that handles the authorization (i.e user's privileges, access credentials, roles etc...) and we are considering how to pass on these credentials in the system.
We have 2 option:
1. Sign those credentials in the gateway (auth and proxy service) using JWT and pass on all the information so every service could verify it (with its public key) and read the user's info.
2. Every service should make a request to the authorization service for querying the user's access on every action.
We are having difficulties on deciding which way is better in terms of high cohesion and loose coupling and of course making it easy for service development.
You have some other options: instead of reinventing the wheel, you can use an OAuth 2.0 identity provider/broker out of the box.
Keycloak is a free open source identity provider and broker that provides all these functionalities.
Auth0 is a managed commercial service that provides all these functionalities too.
And I'm sure there are many other services exist for OAuth 2.0 protocol.
As for your 2 options:
You can extend the JWT with your custom authorisation claims (roles or permissions) and since the JWT will be signed, then it is safe to assume the data is correct by your service. Give that the JWT is a short lived token that need to renew every few minutes.
I'm having a hard time choosing a decent/secure authentication strategy for a microservice architecture. The only SO post I found on the topic is this one: Single Sign-On in Microservice Architecture
My idea here is to have in each service (eg. authentication, messaging, notification, profile etc.) a unique reference to each user (quite logically then his user_id) and the possibility to get the current user's id if logged in.
From my researches, I see there are two possible strategies:
1. Shared architecture
In this strategy, the authentication app is one service among other. But each service must be able to make the conversion session_id => user_id so it must be dead simple. That's why I thought of Redis, that would store the key:value session_id:user_id.
2. Firewall architecture
In this strategy, session storage doesn't really matter, as it is only handled by the authenticating app. Then the user_id can be forwarded to other services. I thought of Rails + Devise (+ Redis or mem-cached, or cookie storage, etc.) but there are tons of possibilities. The only thing that matter is that Service X will never need to authenticate the user.
How do those two solutions compare in terms of:
security
robustness
scalability
ease of use
Or maybe you would suggest another solution I haven't mentioned in here?
I like the solution #1 better but haven't found much default implementation that would secure me in the fact that I'm going in the right direction.
Based on what I understand, a good way to resolve it is by using the OAuth 2 protocol (you can find a little more information about it on http://oauth.net/2/)
When your user logs into your application they will get a token and with this token they will be able to send to other services to identify them in the request.
Example of Chained Microservice Design
Resources:
http://presos.dsyer.com/decks/microservice-security.html
https://github.com/intridea/oauth2
https://spring.io/guides/tutorials/spring-security-and-angular-js/
Short answer : Use Oauth2.0 kind token based authentication, which can be used in any type of applications like a webapp or mobile app. The sequence of steps involved for a web application would be then to
authenticate against ID provider
keep the access token in cookie
access the pages in webapp
call the services
Diagram below depicts the components which would be needed. Such an architecture separating the web and data apis will give a good scalability, resilience and stability
You can avoid storing session info in the backend by using JWT tokens.
Here's how it could look like using OAuth 2.0 & OpenID Connect. I'm also adding username & password login to the answer as I assume most people add it as a login option too.
Here are the suggested components of the solution:
Account-service: a microservice responsible for user creation & authentication. can have endpoints for Google, Facebook and/or regular username & password authentication endpoints - login, register.
On register - meaning via register endpoint or first google/fb login, we can store info about the user in the DB.
After the user successfully logs in using either of the options, on the server side we create a JWT token with relevant user data, like userID. To avoid tampering, we sign it using a token secret we define(that's a string).
This token should be returned as httpOnly cookie alongside the login response. It is recommended that it's https only too for security. This token would be the ID token, with regards to the OpenID connect specification.
Client side web application: receives the signed JWT as httpOnly cookie, which means this data is not accessible to javascript code, and is recommended from a security standpoint. When sending subsequent requests to the server or to other microservices, we attach the cookie to the request(in axios it would mean to use withCredentials: true).
Microservices that need to authenticate the user by the token:
These services verify the signature of the JWT token, and read it using the same secret provided to sign the token. then they can access the data stored on the token, like the userID, and fetch the DB for additional info about the user, or do whichever other logic. Note - this is not intended for use as authorization, but for authentication. for that, we have refresh token & access token, which are out of scope of the question.
I have recently created a detailed guide specifically about this subject, in case it helps someone: https://www.aspecto.io/blog/microservices-authentication-strategies-theory-to-practice/
One more architecture perspective is to use nuget-package (library) which actually do authentication/token validaton. Nuget-package will be consumed by each microservice.
One more benefit is that there is no code duplication.
you can use idenitty server 4 for authentication and authorisation purpose
you must use Firewall Architecture hence you have more control over secutiry , robustness ,scalability and ease of use
I am working on an internal authentication system for users of a set of of RESTful web applications. Our intention is that a user should be able to sign-on once via a web form and have appropriate access to all these RESTful applications in our domain, which may be distributed in a private cloud across many servers. (I understand already that having a single authenticated session is not aligned with a pure RESTful approach, but this is a usability requirement.)
The applications themselves will be written in a variety of programming languages so a language-neutral approach is required. It was suggested to me that we might use OpenID or OAuth or a similar framework to handle the authentication but my understanding is that these are intended for third-party services and not the first-party services that would share data on our internal system. In this case, we might have a central provider service with all the other applications treated as third parties (or relying parties).
Questions:
Are OpenID/OAuth suitable for authentication among first-party services?
If so, how would one be advised to set up authentication for this use case?
Wouldn't a user have to grant individual permission to each first-party server that they wanted to use, just as they would need to grant individual permission to any third-party server? I think this would violate the requirement of having a single sign-on for accessing all the first-party services.
Are there good examples of sites supporting this first-party use case?
What would be a good alternative framework for this first-party use case?
You do not need OAuth for SSO services.
The primary use/advantage of OAuth is, as you know already, granting access to a 3rd party app to access/use your resource in a controlled manner.
Rather than having an authentication/authorization server that you would need for OAuth, why not use a single log in service across all your APIs. An OAuth access token is totally different from what you need.
As far as I understand, what you can have is something like OAuth in a way that your server vends out tokens to the app. (I'm assuming that it's a totally internal system, so tokens cannot be misused).
So basically what I'm proposing is:
When an app tries to access the first API it's redirected to a web-form.
The user enters credentials and is taken to the DB for verification. Let there be a service that generates a token for the user/app
Next API access request would be made with that token - the token uniquely identifies the app
Depending on the level of security you need you can sign some text using HMAC and send it as token, or if its totally internal just generate a unique identifier for the app/user and send it to other API
On receiving the token, each service first calls the main server with the token and internally fetches the corresponding customer/user ID and performs the required function.
In short separate the login + token generation + token verification into a different module. All APIs should use this module for login/token verification.
What I have proposed here works like OAuth but all security aspects have been stripped down since you want to use it in a private cloud.
Oauth supports multiple different kinds of flows. You can use the client crendentials flow from Oauth 2.0 to avoid asking the user to grant permission for every app (this is intended for the cases where you control both the server and the app or where you want to preauthorize certain apps). This post does a good job explaining everything: http://tatiyants.com/using-oauth-to-protect-internal-rest-api/
Suppose I have a front-end application that wants to fetch some data from a back-end service. (I do.) The service will need to verify that the end-user is authenticated, that it is authorized to use the service and possibly filter the returned data based on the user's privileges. In my case, both the front-end app and the back-end service relies on Azure ACS for authentication.
Ideally the front-end would like to act on the behalf of the authenticated user, which sounds like a good fit for using an ActAs token (as specified in WS-Trust). However, it turns out that ACS does not currently support ActAs.
A workaround could be to use the actual bearer token (the bootstrap token in the front-end app) to authenticate to the back-end service. It's not hard to do, but would it be a bad idea for some reason?
From your front-end app, you could certainly pass along the identity data of the end user by either sending the token as is or sending the attributes from it. Both have issues. For the former, if it's also encrypted, the front- and back-ends will have to share the private key needed to decrypt it; they will also have to share audience restrictions, etc. in order for the back-end to consider the token valid for it. In other words, the front- and back-ends will be ONE relying party, not two. Might not be a problem, but be aware. In the latter case, you end up sending user data in a proprietay way which could increase integration and maintenance costs over time. In both cases, you can authenticate the front-end app to the back-end using some other type of credential, e.g., a certificate used at the transport level and, thus, forming a trusted subsystem between them.
One thing that I would suggest you consider instead is OAuth 2. From this blog post, it seems to me that ACS supports it (though I don't have any first hand experience w/ it). The truely wonderful thing about OAuth 2 is that it bakes delegation in, and is NO WHERE near as complex as ActAs in WS-Trust. The net result is the same, i.e., the back-end service will have info about the calling service and the end user, but the amount of effort to get it setup in incomparable. The tokens will still be bearer tokens, but you can mitigate that to a degree by using SSL. Beyond SSL, you can put some additional measures in place, but the best, IMO, would be if Microsoft did something in ACS like Google has done w/ their Access Tokens for service accounts which uses asymmetric keys that are chained up to a PKI. (BTW, for all I know, Microsoft may have already done something like that; if so, you're set.)
Anyway, HTH!