Node.js-based ingress controller for Kubernetes
This is an ingress controller for Kubernetes.
Ingress controllers provide access to services running within a Kubernetes cluster, to clients outside the cluster. They can provide features such as SSL termination, authentication, and more. You can think of an ingress controller as the "front door" to your cluster.
This ingress controller is implemented in Node.js. This doesn't mean you can only use it with Node.js applications. However, if you need to add custom functionality to the ingress controller, you will find it easier if you're familiar with Node.js.
Currently, the most commonly used ingress controller is NGINX Ingress Controller. This works well for many people, and Node.js Ingress Controller does not seek to replace it. Instead, our goals are as follows:
- Small, auditable codebase: An ingress controller is an important part of the security of your Kubernetes cluster. We think it's important that you can read the entire core codebase of your ingress controller and understand how it works. We keep the core codebase as small as possible, with as few dependencies as possible. (See Trusted Computing Base below.) Modern TypeScript features help us make the code readable and robust.
- Access to the Node.js ecosystem: Extensions for NGINX are typically written in Lua. While Lua is an excellent language, and has a great ecosystem of its own, many web application developers are more comfortable with Node.js. With Node.js Ingress Controller, if you need to write an extension to add custom functionality, there's a good chance you'll find a library on NPM to do most of the work for you. Over time, we hope to build up a library of useful and high-quality extensions that you can enable with the flip of a switch.
- Best practices by default: There are some things you'd rather not have to think about. Node.js Ingress Controller aims to handle these things for you, out-of-the-box or with minimal setup required.
In most cases, the setup process should be very similar to that of other ingress controllers such as NGINX Ingress Controller. You can even use the two ingress controllers side-by-side if you want (just remember to put the appropriate kubernetes.io/ingress.class
annotation on each Ingress
to indicate which one you want to use).
The following guide is intended for people who have never set up an ingress controller before. If you already know what you're doing, feel free to do it a different way.
The only strict prerequisite is that you have a Kubernetes cluster of some sort. However, there are a few other things that you'll probably want to set up, assuming you want your Ingress
es to be accessible from the public internet.
- Your Kubernetes cluster needs to be able to allocate a public IP address to the ingress controller's LoadBalancer Service. Most managed cloud Kubernetes providers will do this for you automatically when you deploy Node.js Ingress Controller to your cluster.
- You'll want one or more domain names to point at your ingresses. You can either set these up manually (once you have your public IP address) or use something like external-dns to do it automatically. If you're planning on having just one (or a few) registered domains, and a lot of subdomains under them for your various services, you may find it helpful to set up a DNS zone with your cloud provider and then configure external-dns to manage that zone automatically for you.
- Assuming you're using HTTPS (which you almost always should), you'll need certificates for your hostnames. We recommend installing cert-manager on your cluster, and configuring it to use Let's Encrypt.
Each Ingress
that you want to expose via Node.js Ingress Controller must have the following annotation:
kubernetes.io/ingress.class: nodejs
If you're using cert-manager and Let's Encrypt, you'll also want the following annotations. (Assuming your Issuer
is called letsencrypt
as per the guide.)
cert-manager.io/cluster-issuer: letsencrypt
cert-manager.io/acme-challenge-type: http01
You should also have the following section in the spec
of your Ingress
(replace HOSTNAME_GOES_HERE
with the hostname, and SECRET_NAME_FOR_TLS_CERT
with a unique name for the Secret
that the TLS certificate will be stored in).
tls:
- hosts:
- HOSTNAME_GOES_HERE
secretName: SECRET_NAME_FOR_TLS_CERT
Node.js Ingress Controller is provided as a Helm chart. You can install it as follows:
-
Build the container image and push it to your container registry:
cd fs docker build . -t YOUR_REGISTRY_HERE/ingress-nodejs-controller docker push YOUR_REGISTRY_HERE/ingress-nodejs-controller
-
Configure the settings in
chart/values.yaml
. -
Deploy the Helm chart to your Kubernetes cluster (here we use the example instance name
my-ingress-controller
, but you can use whatever name you want here):cd chart helm install my-ingress-controller .
If all goes well, the following steps should happen automatically over the next few minutes. You shouldn't need to do anything while this happens, but it may help to understand the process in case you need to troubleshoot.
- The
Service
calledmy-ingress-controller-nodejs-ingress-controller
will be allocated a public IP address. - The Node.js Ingress Controller will start running, find all
Ingress
es with the appropriate annotation, and put its public IP address into the.status.loadBalancer.ingress
field of each one. This tells Kubernetes that theIngress
es can be reached via this IP address. - Your external-dns instance (if applicable) will see this, and start pointing DNS records at this IP address. (If you're not using external-dns, you'll have to do this step manually.) Now people on the public internet will be able to reach the ingress controller via the relevant hostnames — but your sites are not quite ready yet.
- Your HTTPS
Ingress
es (i.e. those that have atls
section) need to have certificates provisioned. Assuming you're using cert-manager, it will do this for you as follows:- cert-manager sees that an
Ingress
is configured for HTTPS but does not yet have a certificate. - cert-manager contacts Let's Encrypt to get a "challenge". This is a string that it will use to prove to Let's Encrypt that you control the hostname in question.
- cert-manager sets up a special temporary
Ingress
to serve this challenge at a specific path under your hostname. This is served over HTTP (not HTTPS). - cert-manager does a "self-check" to ensure that the challenge is reachable at the appropriate URL. (This step may fail a few times while the DNS is propagating, but cert-manager will keep retrying until it succeeds.)
- cert-manager tells Let's Encrypt that the challenge is reachable. Let's Encrypt checks for the presence of the challenge at the appropriate URL. Upon successful validation of the challenge, Let's Encrypt issues a certificate for the hostname.
- cert-manager stores the new certificate in the
Secret
whose name you specified in thetls
section of theIngress
.
- cert-manager sees that an
- When Node.js Ingress Controller sees a valid certificate in a
Secret
pointed to by anIngress
, it will start using that certificate to serve HTTPS for theIngress
. Your service is now live!
When thinking about the security (and general code quality) of a system, it is useful to consider the Trusted Computing Base (TCB) of that system. This is the full set of software and hardware that the system relies on.
We think it's important to keep tabs on the TCB of Node.js Ingress Controller to make sure it remains small and auditable as the project evolves. To that end, we document the TCB below. For simplicity, we only cover the software that runs inside the Node.js Ingress Controller container — but you can find discussions of the wider Kubernetes TCB elsewhere. We also do not include indirect NPM dependencies.
Item | Purpose | Used by component | Notes |
---|---|---|---|
Alpine Linux v3.11 | Operating system | All | Lightweight base image. Latest major release. |
Node.js v14 | JS runtime | All | Current long-term support (LTS) release. Only the core modules listed below are referenced directly. |
(http core module) | Handles HTTP requests. | All | |
(https core module) | Handles HTTPS requests. | All | |
(tls core module) | Reads and validates TLS certificates for use by HTTPS server. | All | |
NPM CLI v7 | Package manager | All | Build-time dependency. |
TypeScript v4 | JS preprocessor / static checker | All | TODO: Run this at build time. |
ts-node | Transpiles TS to JS at runtime. | All | TODO: Remove this and run TS transpiler at build time. |
@kubernetes/client-node | Kubernetes client library | Core, K8sCRDSessionStore | |
http-proxy | Facilitates proxying of HTTP connections to backend servers | Core | |
cookie | Parses and generates Cookie /Set-Cookie headers. Used for session management. |
Core | |
uuid | Generates UUIDs. Used for session management. | Core | |
openid-client | Performs OAuth / OIDC flows. | OpenIDConnectPlugin |