Microservice protection

Over the past few days, I have been playing with the microservice template, and everything is going well, but security seems to puzzle me.

Therefore, if I can ask a question: How to handle user authentication on a separate service? I am currently submitting a Gateway API request that connects to the service in turn. Strike>

Editing Question Please see below

Whereas individual services should not know about each other. Gateway is an aggregator as such.

Current architecture.

enter image description here

A small code to simulate a request:

Frontend - client application

 public class EntityRepository<T> { private IGateway _gateway = null; public EntityRepository(IGateway gateway) { this._gateway = gateway; } public IEnumerable<T> FindAll() { return this._gateway.Get(typeof(T)).Content.ReadAsAsync<IEnumerable<T>>().Result; } public T FindById(int id) { return this._gateway.Get(typeof(T)).Content.ReadAsAsync<T>().Result; } public void Add(T obj) { this._gateway.Post(typeof(T), obj); } public void Update(T obj) { this._gateway.Post(typeof(T), obj); } public void Save(T obj) { this._gateway.Post(typeof(T), obj); } } //Logic lives elsewhere public HttpResponseMessage Get(Type type) { return Connect().GetAsync(Path(type)).Result; } public HttpResponseMessage Post(Type type, dynamic obj) { return Connect().PostAsync(Path(type), obj); } private string Path(Type type) { var className = type.Name; return "api/service/" + Application.Key + "/" + className; } private HttpClient Connect() { var client = new HttpClient(); client.BaseAddress = new Uri("X"); // Add an Accept header for JSON format. client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json")); return client; } 

I use generics to determine where it should fire when it enters the gateway. Therefore, if the Type Category , it starts the Category service by calling:

 public IEnumerable<dynamic> FindAll(string appKey, string cls) { var response = ConnectTo.Service(appKey, cls); return (appKey == Application.Key) ? (response.IsSuccessStatusCode) ? response.Content.ReadAsAsync<IEnumerable<dynamic>>().Result : null : null; } 

The gateway does not contain physical files / type classes.

After a little code, I was hoping someone could give me a little demo or a better approach for handling security / user authentication with the current architecture.

Case scenario 1 A user enters a web application and logs in, at which point users encrypt email and the password is sent to the Gateway API , which is then passed to the User Service and decides whether the user is checked - all is well and good, but now I want to retrieve all messages from the Message Service that the user received. I can’t tell in Gateway if the user is authenticated, retrieves messages, because this does not solve the problem of calling Message Service outside the Gateway API

I also can’t add authentication for each individual service, because this will require all the relevant services that speak to the User Service , and this defeats the purpose of the template.

Corrections: Allow the gateway to allow Services. Requests for services outside the gateway should be blocked.

I know that security is a broad topic, but in the current context, I hope that someone can guide me with the best action to solve the problem.

I currently have Hardcoded a Guid in all applications, which in turn retrieve data if the application is equal.

+6
source share
2 answers

Edit

This answer applies to the Gateway ↔ Micro communications service. Of course, the user must be authenticated correctly when the application is talking to the gateway

end edit

First of all, micro-services should not be accessible from the Internet. They should be accessible only from the gateway (which can be grouped).

Secondly, you need to determine the current user. You can do this by passing UserId as an HTTP header. Create a WebApi filter that takes this header and creates a custom IPrincipal from it.

Finally, you need to somehow make sure that the request comes from a gateway or other microservice. An easy way to do this is to use HMAC authentication on the token.

Save the key in web.config for each service and gateway. Then just send a token with each request (which you can authenticate with a WebApi authentication filter)

To create a hash, use the HMACSHA256 class in .NET:

 private static string CreateToken(string message, string secret) { secret = secret ?? ""; var keyByte = Encoding.ASCII.GetBytes(secret); var messageBytes = Encoding.ASCII.GetBytes(message); using (var hasher = new HMACSHA256(keyByte)) { var hashmessage = hasher.ComputeHash(messageBytes); return Convert.ToBase64String(hashmessage); } } 

So, in your MicroServiceClient you would do something like this:

 var hash = CreateToken(userId.ToString(), mySharedSecret); var myHttpRequest = HttpRequest.Create("yourUrl"); myHttpRequest.AddHeader("UserId", userId); myHttpRequest.AddHeader("UserIdToken", hash); //send request.. 

And in the microservice, you create a filter such as:

 public class TokenAuthenticationFilterAttribute : Attribute, IAuthenticationFilter { protected string SharedSecret { get { return ConfigurationManager.AppSettings["SharedSecret"]; } } public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken) { await Task.Run(() => { var userId = context.Request.Headers.GetValues("UserId").FirstOrDefault(); if (userId == null) { context.ErrorResult = new StatusCodeResult(HttpStatusCode.Forbidden, context.Request); return; } var userIdToken = context.Request.Headers.GetValues("UserIdToken").FirstOrDefault(); if (userIdToken == null) { context.ErrorResult = new StatusCodeResult(HttpStatusCode.Forbidden, context.Request); return; } var token = CreateToken(userId, SharedSecret); if (token != userIdToken) { context.ErrorResult = new StatusCodeResult(HttpStatusCode.Forbidden, context.Request); return; } var principal = new GenericPrincipal(new GenericIdentity(userId, "CustomIdentification"), new[] {"ServiceRole"}); context.Principal = principal; }); } public async Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken) { } public bool AllowMultiple { get { return false; } } private static string CreateToken(string message, string secret) { secret = secret ?? ""; var keyByte = Encoding.ASCII.GetBytes(secret); var messageBytes = Encoding.ASCII.GetBytes(message); using (var hasher = new HMACSHA256(keyByte)) { var hashmessage = hasher.ComputeHash(messageBytes); return Convert.ToBase64String(hashmessage); } } } 
+3
source

Option 1 (preferred)

The easy way is that microservices should be located behind the gateway, so you should use white lists to connect to them, which means access only to authorized and trusted parties (i.e. only to the gateway). Customers should not have direct access to them. Gateway - your bouncer in a nightclub.

Option 2

You can use JWT or some form of token and share the secret key between services. I use JWT authorization token tokens.

Other services do not need to request a user service, they just need to know that the token is valid, then they have permission to use the API. I receive the JWT transmitted from the client to the gateway and insert it into the request, which is sent to another service behind, only through a direct pass.

A microservice should have the same JWT consumption as a gateway for authorization, but, as I already said, this is just a definition of a valid token, not a request from a valid user.

But this has a problem that, as soon as someone is resolved, they can switch to other user data if you have not included something like a claim in the token.

My thoughts

The part that I found the call from Monolith to Micro Services was that you had to switch to where you trust. At Monolithic, you control everything you need. The point of Micro Services is that other services have full control over their domain. You must trust this other service to fulfill your obligations and do not want to double-check and repeat everything at all levels, in addition to what is necessary.

+2
source

Source: https://habr.com/ru/post/989322/


All Articles