I want to know is if we should perform authentication at the API gateway, at the individual service, or both.
Let's frame this question and descussion in the context of new development. Specifically, in my current scenario we're rewriting our software to be a SaaS offering in the cloud using current technologies.
I don't believe this is pertinent to the actual discussion but our model is as follows: The REST services are written in .NET Core and deployed to a Kubernetes cluster with an API gateway provided by Kong.
Naturally any solution, new or old, will need to authenticate requests and insure that the correct users are authorized to perform the requested actions.
Our first intuition is to place this security layer at the API gateway since it represents the public interface to our services. I see the largest advantage of performing the verification at this layer being the elimination of security as a cross-cutting concern. It consolidates the authn/authz to a single layer at the edge of system. Everyone that is external to our secured services must be authenticated.
However, thinking about what this means draws a number of concerns. Yes, placing authn/authz at the edge allows for gated entry into the system, but what about intra-system communication? My assumption is that our services will not exit the boundary that is the internal secured system to come back through the gateway to talk to another service. This is impractical from a performance and financial perspective. If checks perform only at the edge then how can we insure that no inadvertent privilege escalation is performed when one service requests another service to perform some action?
A simple solution to this would be to also perform security checks at the individual services. I have thought that the API gateway could decompose the token and forward on the pertinent pieces of information for the services to evaluate. Yet, I end up coming up with questions such as, what if that information was compromised? What if a bug is introduced with sending or receiving this information? What happens if there is some configuration missed on service deployments?
The next step in my thinking is that the gateway should just forward the token on to the services and let them use it as they need. However, this just defeats the largest purpose that I've identified for having the API gateway, the elimination of the cross-cutting concern of security at the service and keeping security at the edge. Doesn't this just show that performing the authn/authz at the service layer should be preferred in this scenario?
Let me approach the discussion from another angle.
Placing the security at the edge, in the API gateway, means the gateway will be required to have configuration and knowledge of the underlying service above and beyond what I consider the simple understanding that its target lives upstream in the protected realm of the network. If a service provides common API functionality for end-consumers at one route and privileged administrative functionality at a different one it would be necessary to communicate this to the API gateway so that authz could be applied. I don't consider this a simple strategy for the API gateway. Obviously gateway solutions provide for this scenario, but I see it as adding complexity and overhead to deployment. A developer adding a new route that requires different authz now has to insure that it is communicated to the gateway. Furthermore, this configuration must not be missed when the service moves through different sub environments to its eventual in production deployed state.
Also, with modern development stacks there is more emphasis on native security within the stack, ie security becomes a pillar of that particular stack. Let's use ASP.NET Core for example. The authn/authz is baked into the framework with providers that support a number of different IdPs and flows. The restrictions on an endpoint is declared with its implementation. This leads to the service declaring and knowing which endpoints are protected and accessible to specific groups of users. I'm sure other stacks are very similar. This consolidates the security configuration necessary for exposed resources to be kept with its implementation. Ultimately, this leads to reducing the security cross-cutting concerns and pushing them to application configuration, providing the necessary configuration for issuer, token endpoint, etc than code implementation.
Finally, my opinion is that having security placed at the service allows for intra-system communication to complete with just as much security as when the call first enters the system. Each service in a chain of calls could verify that the request was intended for them and is appropriate for the context.
So let's circle back around to the question. What is the benefit of performing authn/authz at the API gateway instead of at the service?
From my standpoint it would seem that services which cannot provide their own authn/authz due to whatever limitations, perhaps some ancient premised service that had no authentication or a service that is designed around a different security technology, are good candidates for having the API gateway handle the security layer. In those scenarios the gateway can be the gatekeeper to handle the task for services that do not handle their own security or transpose from one technology to another (if that makes sense).
So in conclusion, would it then make sense with the above assertion that it is unnecessary to apply API gateway security to those services which can validate that a request is authenticated and the requester has appropriate permissions to perform that action?