In this guide we will learn how to configure TLS/SSL in kubernetes using ingress for already existing ssl certificates (either Self-Signed) or purchased ones.
For this to work, you should also have a working ingress set up. We will use Nginx Ingress. You should also have the domain used already configured with the Nginx ingress endpoint record.
Checkout related content:
- Kubernetes Nginx Ingress in aws With Certbot Letsencrypt
- How To Create and use a Self-Signed SSL Certificate for Apache
- How to create a Kubernetes TLS/SSL Secret
Obtaining a TLS Certificate
The basic requirement for ingress TLS is a TLS/SSL certificate. You can obtain these certificates in the following ways.
- Self-Signed Certificates: TLS certificate created and signed by our own Certificate Authority. It is great option for development environments where you can share the root CA with the team so that browsers can trust the certificate.
- Purchase an SSL Certificate: You can buy an SSL Certificate from one of the many well-known certificate authority trusted by browsers & operating systems for production use cases.
- Use Letsencrpt Certificate: Letsencrypt is a non-profit trusted certificate authority that provides free TLS certificates.
Every SSL certificate comes with an expiry date. So you need to rotate the certificate before it expires. For example, Letsecrypt certificates expire every three months.
In this guide we will need a certificate from one of the first two options. If you do not have a certificate already, create a Self-Signed certificate. Use this command:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout citizix-k8s.key -out citizix-k8s.crt
This will prompt you to fill. This command produces two files: citizix-k8s.key
and citizix-k8s.crt
. In production, you’d generate a key file and use it to obtain a certificate from a certificate authority.
This is the output from my machine:
➜ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout citizix-k8s.key -out citizix-k8s.crt Generating a 2048 bit RSA private key ......................................................................+++ .......+++ writing new private key to 'citizix-k8s.key' ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) []:KE State or Province Name (full name) []:Nairobi Locality Name (eg, city) []:Nairobi Organization Name (eg, company) []:Citizix Organizational Unit Name (eg, section) []:Devops Common Name (eg, fully qualified host name) []:citizix-k8s.citizix.com Email Address []:admin@citizix.com
TLS/SSL with Ingress in kubernetes
SSL is** handled by the ingress controller, not the ingress resource**. Meaning, when you add TLS certificates to the ingress resource as a kubernetes secret, the ingress controller access it and makes it part of its configuration.
For example, in the Nginx controller, the SSL certificates are dynamically handled by the following block in nginx.conf
ssl_certificate_by_lua_block {
certificate.call()
}
Deploy a Test Application
In this section, we will create a simple application in kubernetes that we can use to test out certificate. We will create a deployment, service and an ingress.
Make sure you also have access to a kubernetes cluster and are in the right kubernetes cluster. Confirm with this command:
kubectl cluster-info
Then create a namespace where all our resources will reside:
kubectl create ns apps
Now create a deployment in the namespace:
kubectl create deploy -n apps nginx --image nginx:latest
Use this command to confirm that the deployment was created as expected:
➜ k get deploy -n apps
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 1/1 1 1 13s
Confirm that the pods are running:
➜ k get pods -n apps
NAME READY STATUS RESTARTS AGE
nginx-55649fd747-mnrvv 1/1 Running 0 36s
Then expose our deployment as a service:
kubectl expose deployment nginx -n apps --type=ClusterIP --name=nginx --port 80
Confirm:
➜ k get svc -n apps
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP 172.20.250.180 <none> 80/TCP 11s
Create a kubernetes TLS
We can issue the kubectl create command to create a secret from the command line.
When creating a TLS Secret using kubectl
, you can use the tls
subcommand as shown in the following example:
kubectl create secret tls citizix-k8s-tls \
-n apps \
--key=citizix-k8s.key \
--cert=citizix-k8s.crt
Following is the equivalent YAML
file where you have to add the crt and key file contents.
apiVersion: v1
kind: Secret
metadata:
name: citizix-k8s-tls
namespace: apps
type: kubernetes.io/tls
data:
server.crt: |
<crt contents here>
server.key: |
<private key contents here>
The public/private key pair must exist before hand. Verify that the secret was added using this command:
➜ kubectl get secret -n apps citizix-k8s-tls NAME TYPE DATA AGE citizix-k8s-tls kubernetes.io/tls 2 21s
To view the YAML source of the secret:
kubectl get secret -n apps citizix-k8s-tls -o yaml
Create an ingress and add the tls block
We have to create an ingress in the same namespace where the resources have been created.
Save the following YAML as ingress.yaml
. Replace citizix-k8s.citizix.com
with your hostname.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: citizix-k8s-ingress
namespace: apps
spec:
ingressClassName: nginx
tls:
- hosts:
- citizix-k8s.citizix.com
secretName: citizix-k8s-tls
rules:
- host: citizix-k8s.citizix.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: nginx
port:
number: 80
Please note the TLS block with the domain name and the TLS secret created earlier. The host in the TLS block and rules block should match.
Create the ingress resources with this command:
➜ kubectl apply -f ingress.yaml
ingress.networking.k8s.io/citizix-k8s-ingress created
Validating ingress TLS
You can validate the ingress by visiting the site in your browser. If it is a self signed certificate you will receive the “Your connection is not private” warning and if you check the certificate details, you will see the certificate information you added when generating.
If you are using curl:
curl https://citizix-k8s.citizix.com -kv
Check these information, it should have information about the certificate being used.
➜ curl https://citizix-k8s.citizix.com -kv
...
* SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384
* ALPN, server accepted to use h2
* Server certificate:
* subject: C=KE; ST=Nairobi; L=Nairobi; O=Citizix; OU=Devops; CN=citizix-k8s.citizix.com; emailAddress=admin@citizix.com
* start date: Jul 6 11:00:59 2022 GMT
* expire date: Jul 6 11:00:59 2023 GMT
* issuer: C=KE; ST=Nairobi; L=Nairobi; O=Citizix; OU=Devops; CN=citizix-k8s.citizix.com; emailAddress=admin@citizix.com
* SSL certificate verify result: self signed certificate (18), continuing anyway.
...
Ingress SSL Termination
By default, SSL gets terminated in ingress the controller. so all the traffic from the controller to the pod will be without TLS (decrypted traffic).
If you want full SSL, you can add the supported annotation by the ingress controller you are using. For example, In the Nginx ingress controller, to allow SSL traffic till the application, you can use the annotation. For this, your application should have SSL configured.
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
Conclusion
In this guide, we learnt how to configure Ingress TLS certificates with Kubernetes.
To clean up the resources we created, use these commands:
# Delete the deployment
kubectl delete deploy nginx -n apps
# Delete the service
kubectl delete service nginx -n apps
# Delete the ingress
kubectl delete ingress citizix-k8s-ingress -n apps
# Delete the secret
kubectl delete secret citizix-k8s-tls -n apps