Reverse proxy with ingress-nginx to a non Kubernetes backend
When running an ingress controller in your Kubernetes cluster (ingress-nginx in this example) you can utilize this as a reverse proxy for services outside of Kubernetes. This is a complete reverse proxy using the ingress controller to be able to leverage things like TLS termination and Let’s Encrypt for a resource outside of Kubernetes. The outside resource can be listening on a different URL then the cluster is proxying and the proxy can do TLS termination for an external HTTP backend.
First we setup a ExternalName(docs)
Service. This type of
Service makes the in-cluster DNS return a CNAME containing the given externalName.
We will make this
Service the backend for our
Ingress resource later.
When applied, this will be the result of DNS lookup in a pod on the cluster:
# nslookup external-service-to-google
external-service-to-google canonical name = google.com
As you can see the in-cluster DNS now resolves the
external-service-to-google with a CNAME to google.com.
To now setup the proxy we will need to create an
Ingress resource which will setup the reverse proxy.
Then we setup an
Ingress pointing to this
Service, the backend port number must be the backend port of the
external backend where the ExternalName
Service points to.
If the backend listens on HTTPS set the
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" annotation.
So for our exercise we set the annotation and the backend port to 443, the port used for HTTPS traffic since google.com
is using TLS.
When the backend listens on a different host then the you will setup in the
Ingress. You must set the
nginx.ingress.kubernetes.io/upstream-vhost annotation, this will do a
proxy_set_header Host <upstream-vhost> header
rewrite on each incoming request. For SNI routing to work we must set the
proxy-ssl-name annotation as well.
If the server doesn’t do SNI you could omit this annotation.
# annotation to use cert-manager to request a Let's Encrypt certificate
# Set this when the backend is listening on HTTPS
# Set this when the backend listens on a different URL
- host: proxy-demo.lansible.com
- pathType: Prefix
Now, as we can see in the browser https://proxy-demo.lansible.com is a full reverse proxy to google.com. Pretty cool!
As stated in the intro, this can be useful to leverage automation that is already working on the Kubernetes clusters. For example the TLS termination with ingress-nginx and certificate management with cert-manager is a great example of this. No more need to manually renew or have that one hacky script to do the TLS renewal on the last VMs still in use.
Another reason could be a ‘stop-gap’ solution for apps that will move to Kubernetes but haven’t just yet (because
legacy). By creating a ExternalName type
Service you can communicate with these services like they are already on the
cluster and resolve them by DNS instead of IP. This also gives you a single source of truth for this IP address when
multiple apps connect to this application.