Reputation: 193
I'm working on constructing a system that is based on the microservice architecture. The microservices are created using Asp.Net Core 3.1.
A simplified high level diagram is shown below:
I would like two levels of security in the system:
Microservice authentication
When the ApiGateway receives a request, it receives a "microservice JWT" from the InternalAuthService and includes this JWT in the authorization header when sending requests over http to the other microservices. This JWT contains one or more claims, that are used by the microservices to decide if a request should be accepted or rejected.
The InternalAuthService is implemented using IdentityServer and it seems to work perfectly fine right now. This means CustomerService is rejecting requests if the ApiGateway does not provide a JWT with the required claim.
User authentication
Next, i want to add authentication of users, and this is where i need your help. A few endpoints in ApiGateway does not need user authentication (eg. registration of user and login of users). But lots of other endpoints will need user authentication. I'm pretty sure is can figure this out, as i have done this in other projects.
Because i have used IdentityFramework in the past when constructing small monolithic applications, i would like to use that in this system as well. This is why i have introduced the UserAuthService.
I would like to reject requests in the ApiGateway when a user does not provide a valid "user JWT". This JWT will also contains a number of claims, used to restrict access to the CustomerService endpoints depending on the roles the user have.
The problem
When sending a request from ApiGateway to CustomerService, the "microservice JWT" is placed in the authorization header. The JWT is authenticated in CustomerService's Starup.cs file like so:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:44308"; //url pointing to InternalAuthService
options.RequireHttpsMetadata = false;
options.Audience = "customer_service"; //the claim required by the CustomerService
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
I want to set up the authentication of the "user JWT" in a similar way, but i cannot figure out how to do it.
So the first issue is, where/how i can store the "user JWT" in the request to be able to authorize it when it is received by the CustomerService?
The next issue is, how i can set up authentication of the "user JWT"?
I'm open to replacing IdentityFrameWork with IdentityServer if it makes things easier (but i would prefer not to because, as i mentioned, i have experience with using IdentityFramework).
Upvotes: 1
Views: 2301
Reputation: 31800
My opinion: this security architecture is complex. You can achieve the two levels of security you require by using a single user token and claims based authorisation.
If a call is made to the gateway with the user token, the gateway authenticates the call based on the user token, retrieves the "userId" claim, and injects it into the downstream call to the microservice. To make this work the userId needs to ideally be a component in the service operation path.
So, the URI exposed on the gateway for a given resource is:
GET /resources/{resourceId}
but is exposed on the actual service as:
GET /resources/{userId}/{resourceId}
This means that the downstream microservice can implement it's own measures to prevent access. For example, reject a request from anyone other than the owner of the requested resource from accessing the resource.
This is illustrated here:
If the service path modification is a difficult short term change then user claim injection can be done as a query, header, or even a body parameter.
Upvotes: 2