Search code examples
node.jskubernetesistio

How to separate internal (service to service) and external (public) APIs in Kubernetes pod?


I have a Node.JS server running inside a Kubernetes cluster. I want to understand if there is a proper way to make some APIs endpoints private and some public via Kubernetes.

To simplify this, consider below situation:

  • API 1: /products/:id (Needs to be accessible from outside)
  • API 2: /prices (Needs to be accessible only by other internal Microservices or pods within the same Kubernetes cluster)

Note: I am using Ingress Nginx to route traffic to this pod via the service

Currently, I am achieving this by running 2 instances of Node.js Express servers at different ports which are mapped to 2 Kubernetes services. One (public) of them is mentioned in the Ingress and the other one (private) is not.

I am not a big fan of this approach, since I have to run 2 servers and maintain so much of these details within the service. Is there a better way to achieve this, maybe Istio (has anyone used it for this purpose)?

In past I have used AWS API Gateway to handle this, however I do not have that option this time and am wondering if something from within Kubernetes can handle this.

Happy to provide more details if I am missing something.


Solution

  • An ingress is a full-fledged API gateway, so you can restrict access using the features of NGINX, Istio or whatever. You do not need to split code bases just to avoid exposing particular endpoints.

    Logically in your use case you need to only define routes for whitelisted paths - this nginx answer provides an example. Istio provides similar options in its VirtualService resource, including the ability to express routing rules.

    You can even write your own ingress plugin for more complex logic. In which case, choose an ingress controller that supports this in a high level language. Quite a few of them, including Istio, support the LUA scripting language, which is pretty easy to learn.

    In terms of simplicity though, this is also an API design question. Eg adopting a path such as /internal for endpoints that should not be exposed will keep API routes easy to maintain over time.