Ingress & TLS in kubernetes using self-signed certificates
Provision a cluster
In this tutorial to setup local cluster I will use kind. Follow this instructions to configure ingress controller (nginx in this example).
Create cluster
$ cat <<EOF | kind create cluster --config=- kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane kubeadmConfigPatches: - | kind: InitConfiguration nodeRegistration: kubeletExtraArgs: node-labels: "ingress-ready=true" extraPortMappings: - containerPort: 80 hostPort: 80 protocol: TCP - containerPort: 443 hostPort: 443 protocol: TCP EOF
Deploy nginx Ingress controller
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml $ kubectl wait --namespace ingress-nginx \ --for=condition=ready pod \ --selector=app.kubernetes.io/component=controller \ --timeout=90s ... pod/ingress-nginx-controller-78f889f8b9-2tbjz condition met
Check if it works
# apply ingress test manifests $ kubectl apply -f https://kind.sigs.k8s.io/examples/ingress/usage.yaml # test ingress $ curl localhost/foo foo $ curl localhost/bar bar # cleanup $ kubectl apply -f https://kind.sigs.k8s.io/examples/ingress/usage.yaml
Create basic nginx pod & expose it using Ingress
$ k run nginx --image=nginx pod/nginx created $ k expose pod nginx --port=80 service/nginx exposed $ cat <<EOF | k apply -f- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - host: ingress.local http: paths: - path: / pathType: Prefix backend: service: name: nginx port: number: 80 EOF ingress.networking.k8s.io/nginx created
To make ingress.local
available in local browser, add to the /etc/hosts
line:
127.0.0.1 ingress.local
– in my case cluster is running at 127.0.0.1.
You can check it by running k cluster-info --context kind-<CLUSTER_NAME>
$ k cluster-info --context kind-kind Kubernetes control plane is running at https://127.0.0.1:63119
If succedeed, you should see similar result:
$ curl ingress.local <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
Add TLS encryption with self-signed certificate to enable HTTPs
Until now, pod is exposed using Ingress, but the connection is over HTTP and therefore it is unencrypted. Let’s add some security to the server. First, create certifiates using openssl
, then create kubernetes Secret
of type ssl
. And finally utilize it in Ingress resource.
Create self-signed certificate
$ openssl req \ -x509 -newkey rsa:4096 -sha256 -nodes \ -keyout tls.key -out tls.crt \ -subj "/CN=ingress.local" -days 365 Generating a 4096 bit RSA private key ........++ ...................................................................................................++ writing new private key to 'tls.key' ----- $ ls tls.crt tls.key
Create kubernetes secret with those keys
$ k create secret tls ingress-local-tls \ --cert=tls.crt \ --key=tls.key secret/ingress-local-tls created
Make changes to Ingress
$ cat <<EOF | k apply -f- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: tls: # add those 4 lines - hosts: # - ingress.local # secretName: ingress-local-tls # rules: - host: ingress.local http: paths: - path: / pathType: Prefix backend: service: name: nginx port: number: 80 ingress.networking.k8s.io/nginx configured
Check if everything has been done correctly:
$ curl https://ingress.local curl: (60) SSL certificate problem: self signed certificate More details here: https://curl.haxx.se/docs/sslcerts.html curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. To learn more about this situation and how to fix it, please visit the web page mentioned above.
We can see that curl
recognised our certificate, hence it is self-signed, it treats it like non-legit. We know it is, so just pass --insecure
flag to suppress this warning:
$ curl --insecure https://ingress.local <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
Similar situation will occur when we will try to access web page via browser:

From now, every connection to our ingress.local
site will be encrypted! In the next posts I will describe how to automate certificate management & provisioning using cert-manager
. Eventually I will use Let's encrypt
to create certificates that will be considered by web browsers as legit – then the green padlock will appear.