Most modern web applications use a Secure Sockets Layer (SSL) for establishing an encrypted link between a server and a client. What is more, in particular cases SSL can be enforced. This mechanism is known as HTTP Strict Transport Security (HSTS). A very good example of such enforcement is the entire .dev top-level domain. It is incorporated on the HSTS preload list, requiring HTTPS on all .dev domains without individual HSTS enlistment. As a matter of fact, my domain belongs to .dev top-level domain as well.
In order to enable HTTPS (SSL/TLS) for websites, we have to obtain a digital certificate. For that purpose, we can use Let's Encrypt.
Let's Encrypt
Let’s Encrypt is a free, automated, and open certificate authority (CA), run for the public’s benefit. It is a service provided by the Internet Security Research Group (ISRG).
The key principles behind Let’s Encrypt are:
Free: Anyone who owns a domain name can use Let’s Encrypt to obtain a trusted certificate at zero cost.
Automatic: Software running on a web server can interact with Let’s Encrypt to painlessly obtain a certificate, securely configure it for use, and automatically take care of renewal.
Secure: Let’s Encrypt will serve as a platform for advancing TLS security best practices, both on the CA side and by helping site operators properly secure their servers.
Transparent: All certificates issued or revoked will be publicly recorded and available for anyone to inspect.
Open: The automatic issuance and renewal protocol is published as an open standard that others can adopt.
Cooperative: Much like the underlying Internet protocols themselves, Let’s Encrypt is a joint effort to benefit the community, beyond the control of any one organization.
Let’s Encrypt
For automated Let's Encrypt certificate obtaining and renewal we can use Cert Manager.
Installing Cert Manager
cert-manager is a powerful and extensible X.509 certificate controller for Kubernetes and OpenShift workloads. It will obtain certificates from a variety of Issuers, both popular public Issuers as well as private ones, ensure the certificates are valid and up-to-date, and will attempt to renew certificates at a configured time before expiry.
Key features:
Automated issuance and renewal of certificates to secure Ingress with TLS.
Fully integrated Issuers from recognized public and private Certificate Authorities.
Secure pod-to-pod communication with mTLS using private PKI Issuers.
Supports certificate use cases for web-facing and internal workloads.
Open source add-ons for enhanced cloud-native service mesh security.
Backed by major cloud service providers and distributions.
The most convenient way of installing cert-manager into the Kubernetes cluster is to use Helm Chart. First, we have to add a new repository.
❯ helm repo add jetstack https://charts.jetstack.io
"jetstack" has been added to your repositories
Once the repository has been added we are ready to install cert-manager.
❯ helm upgrade --install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.7.3 \
--set installCRDs=true
When the installation finishes, 3 new Pods will be created.
❯ kubectl get pods
NAME READY STATUS RESTARTS AGE
cert-manager-5f9d99bd9-z92p8 1/1 Running 0 51d
cert-manager-cainjector-f6b49bddd-b48w9 1/1 Running 0 51d
cert-manager-webhook-58b5f99b69-wst8t 1/1 Running 0 51d
At this point, we are almost ready to request a certificate. But before going further make sure that you have a working Ingress controller.
NGINX as Ingress controller
Requesting a certificate
To request a certificate, we need to add Certificate Authority (CA), and we will use Let's Encrypt for that.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
namespace: cert-manager
spec:
acme:
email: blog@slys.dev
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-prod-secret
solvers:
- http01:
ingress:
class: nginx
After a while Cluster Issuer will become ready.
❯ kubectl get clusterissuers.cert-manager.io
NAME READY AGE
letsencrypt-prod True 87d
Setting up SSL is as simple as adding a few annotations to an Ingress resource and TLS section.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/permanent-redirect: https://blog.slys.dev
name: ghost-slys-dev
namespace: ghost
spec:
ingressClassName: nginx
rules:
- host: slys.dev
http:
paths:
- backend:
service:
name: ghost
port:
name: https
path: /
pathType: ImplementationSpecific
tls:
- hosts:
- slys.dev
secretName: slys.dev-tls
So we added cluster-issuer that references to letsencrypt-prod. We also added a tls-acme annotation and a tls section. After a while, the cert-manager should obtain from CA a certificate for us.
❯ kubectl get certificates.cert-manager.io
NAME READY SECRET AGE
slys.dev-tls True slys.dev-tls 87d
Here we can find the issued certificate as well as the name of the secret that holds the certificate. Now we can enjoy using an encrypted link between a server and a client.
Conclusion
Setting up TLS/SSL encryption using Cert Manager and Let's Encrypt is a really pleasant and easy task. It requires creating Issuer and adding a few annotations to an Ingress resource, but the rest happens automagically. 😂