Advanced kubernetes ingress
In the last post I described how to install Nginx-Ingress on a kubernetes cluster. In this post I’ll show how to setup a more complex ingress example.
Path-based Routing
The application in this example has an api-server and a separate ui server. The api-server should be accessible via /api and the frontend should be accessible via /. But they shall be available via the same domain name. Therefore ingress allows you to define path based routing. In the following part you see the ingress definition for our ui:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-ui
namespace: application
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: application.koudingspawn.de
http:
paths:
- path: /
backend:
serviceName: ui
servicePort: 80
First we define that all requests on domain application.koudingspawn.de should be affected. Any request on root will be proxied to the ui service on port 80. In this example I won’t show how the service looks like, because this is not important for the ingress definition.
The second ingress definition for the api-server is also very easy:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-api
namespace: application
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: application.koudingspawn.de
http:
paths:
- path: /api
backend:
serviceName: api
servicePort: 8080
There we define, that every request on path /api should be proxied to the api service on port 8080. With these two ingress definitions we have managed to forward requests to the ui by default and only if the path starts with /api requests are proxied to the apiserver.
SSL Certificate
To secure our application via tls we can add a secret to the kubernetes secret resource and reverence this into the ingress definition. This allows the nginx server to serve requests for the application also on port 443. First we need to add the certificates to the cluster:
apiVersion: v1
data:
tls.crt: BASE64(PUBLIC_KEY)
tls.key: BASE64(PRIVATE_KEY)
kind: Secret
metadata:
name: application-koudingspawn-tls
namespace: application
type: kubernetes.io/tls
In the field tls.crt we place the base64 encoded public key and in the field tls.key we place the base64 encoded private key. (e.g. cat private.pem | base64
)
This secret will be placed in our application namespace:
$ kubectl get secret -n application
NAME TYPE DATA AGE
application-koudingspawn-tls kubernetes.io/tls 2 28m
default-token-frgtb kubernetes.io/service-account-token 3 1h
gitlab-com kubernetes.io/dockercfg 1 59m
Now we can define in the ingress definition that our nginx proxy should use tls:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-api
namespace: application
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- hosts:
- application.koudingspawn.de
secretName: application-koudingspawn-tls
rules:
- host: application.koudingspawn.de
http:
paths:
- path: /api
backend:
serviceName: api
servicePort: 8080
So here you can see we added the tls part where we specify the path to the secretName and the hosts that are in the secret certificate. We can do this again for the ui.
Another useful step is to redirect all http traffic to https. Therefore we add the ingress resources an annotation kubernetes.io/ingress.allow-http: "false"
. This tells the nginx proxy to redirect http traffic to https:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-ui
namespace: application
annotations:
kubernetes.io/ingress.class: "nginx"
kubernetes.io/ingress.allow-http: "false"
spec:
tls:
- hosts:
- application.koudingspawn.de
secretName: application-koudingspawn-tls
rules:
- host: application.koudingspawn.de
http:
paths:
- path: /
backend:
serviceName: ui
servicePort: 80
Kube-Lego
The problem of the last part of our tutorial is, that we need a tls certificate. Generally tls certificates are very expensive, therefore and for more security in 2016 the Let’s Encrypt initiative has launched. There you can generate valid Certificates for free and the process of registration is very easy and well documented for nginx and apache. But what about the nginx ingress used in our kubernetes cluster?
The answer is Kube-Lego. Kube-Lego can be deployed into the kubernetes cluster and work together with the nginx ingress to generate Let’s Encrypt certificates. First we need to install the Kube-Lego namespace, configmap and deployment:
apiVersion: v1
metadata:
name: kube-lego
namespace: kube-lego
data:
lego.email: "[email protected]"
lego.url: "https://acme-staging.api.letsencrypt.org/directory"
kind: ConfigMap
In the configmap you need to specify your email address used for Let’s Encrypt registration and the Let’s encrypt API. In this case we use for testing purposes the statging api of Let’s Encrypt that generates self signed certificates that are not valid, but for a short tutorial or test it is enough to see how it work.
apiVersion: v1
kind: Namespace
metadata:
name: kube-lego
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: kube-lego
namespace: kube-lego
spec:
replicas: 1
template:
metadata:
labels:
app: kube-lego
spec:
containers:
- name: kube-lego
image: jetstack/kube-lego:0.1.5
imagePullPolicy: Always
ports:
- containerPort: 8080
env:
- name: LEGO_EMAIL
valueFrom:
configMapKeyRef:
name: kube-lego
key: lego.email
- name: LEGO_URL
valueFrom:
configMapKeyRef:
name: kube-lego
key: lego.url
- name: LEGO_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LEGO_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
timeoutSeconds: 1
After the components are deployed the Kube-Lego deployment watches for the annotation kubernetes.io/tls-acme: "true"
. If it find such an annotation on an ingress it will generate a Let’s Encrypt certificate with the hosts specified in the tls section:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-api
namespace: application
annotations:
kubernetes.io/ingress.class: "nginx"
kubernetes.io/tls-acme: "true"
kubernetes.io/ingress.allow-http: "false"
spec:
tls:
- hosts:
- application.koudingspawn.de
secretName: application-koudingspawn-tls
rules:
- host: application.koudingspawn.de
http:
paths:
- path: /api
backend:
serviceName: api
servicePort: 8080
So in this example it means that Kube-Lego will generate a kubernetes secret called application-koudingspawn-tls
with a Let’s Encrypt certificate valid for application.koudingspawn.de. You don’t need to place the secret or an empty placeholder the Kube-Lego will deploy the secret for you.