We currently have multiple APIs that are not behind a gateway. The APIs that are exposed publicly use OpenID Connect for authentication and claims authorization. Some of the APIs are internal only and are network secured behind a firewall.
We plan to setup Kong Gateway Enterprise in front of our APIs. We should be able to centralize token validation from public clients at the gateway. We could possibly centralize some basic authorization as well (e.g. scopes). Some logic will probably still need to happen in the upstream API. So, those APIs will still need to know the context of the caller (client and user).
Ideally, we would like to be able to have APIs that can be exposed publicly and also called internally to avoid duplicating logic. I'd like to understand some secure approaches for making this happen with Kong. Exactly how to setup the system behind the gateway is still unclear to me.
Some questions I have are:
- Should we have both an internal gateway and an external? Is there guidance on how to choose when to create separate gateways?
- If we have multiple upstream services in a chain, how do you pass along the auth context?
- Custom headers?
- Pass along the original JWT?
- How can we make a service securely respond to both internal and external calls?
- We could setup up a mesh and use mTLS but wouldn't the method of passing the auth context be different between mTLS and the gateway?
- We could set custom headers from Kong and have other internal services render them as well. But since this isn't in a JWT, aren't we loosing authenticity of the claims?
- We could have every caller, including internal services, get their own token but that could make the number of clients and secrets difficult to manage. Plus, it doesn't handle the situation when those services are still acting on behalf of the user as a part of an earlier request.
- Or we could continue to keep separate internal and external services but duplicate some logic.
Some other possibly helpful notes:
- There is no other existing PKI other than our OIDC provider.
- Services will not all be containerized. Think IIS on EC2.
- Services are mostly REST-ish.
There is a lot there to unpack here, and the answer is: it depends
Generally, you should expose the bare minimum API externally, so a separate gateway in the DMZ with only the API endpoints required by external clients. Your generally going to be making more internal changes so you don't want to expose a sensitive endpoint by accident.
Don’t be too concerned about duplication when it comes to APIs, it’s quite common to have multiple API gateways, even egress gateways for external communication. There are patterns like (BFF - Backend for frontend pattern) where each client has its own gateway for orchestration, security, routing, logging, auditing. The more clients are isolated from each other the easier and less risky it is to make API changes. In regards to propagating the Auth context, it really comes down to trust, and how secure your network and internal actors are. If you're using a custom header then you have to consider the "Confused Deputy Problem". Using a signed JWT solves that, but if the token gets leaked it can be used maliciously against any service in the chain. You can use RFC8693 Token exchange to mitigate that and even combine it with MTLS, but again that could be overkill for your app. If the JWT is handled by an external client, it becomes even riskier. In that case, it should ideally be opaque and only accepted by the external-facing gateway. That GW can then exchange it for a new token for all internal communication.