TLS certificate is one of the fundamental parts of modern web application security. Managing the lifecycle of TLS certificates for applications running in Kubernetes can be challenging — issuance, creating Kubernetes secrets, configuring ingress, tracking expiry and renewing on time, for every certificate in your environment. It’s tedious and error-prone.
In this post, we’ll see how to automate certificate management using Let’s Encrypt’s free certificates and cert-manager for applications running on Kubernetes.
We’ll use the Sock Shop demo microservices application for this demonstration.
Step 1: Install cert-manager
Cert-manager is an open source Kubernetes add-on that automates TLS certificate management. It manages the lifecycle of certificates issued by CAs — ensuring they’re valid and renewed before expiry. It supports Let’s Encrypt via the ACME protocol.
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.3.1/cert-manager.yaml
Step 2: Install Contour Ingress Controller
We’ll use Contour (a CNCF incubating project) as our ingress controller:
kubectl apply -f https://projectcontour.io/quickstart/contour.yaml
Verify the installation:
kubectl get all -n projectcontour
A successful install shows the contour deployment, envoy daemonset, and services. Note the external IP/hostname of the envoy LoadBalancer service — create a DNS record pointing your domain to it (CNAME for EKS, A record for GKE).
Step 3: Deploy the Demo Application
git clone https://github.com/microservices-demo/microservices-demo.git
cd microservices-demo/deploy/kubernetes
kubectl create namespace sock-shop
kubectl apply -f complete-demo.yaml
Step 4: Create a ClusterIssuer for Let’s Encrypt
We’ll create two issuers — staging for testing, production for real certificates. Let’s Encrypt recommends staging first to avoid rate limits.
# letsencrypt-staging-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: your-email@example.com
privateKeySecretRef:
name: letsencrypt-staging
solvers:
- http01:
ingress:
class: contour
# letsencrypt-prod-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: your-email@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: contour
kubectl apply -f letsencrypt-staging-issuer.yaml
kubectl apply -f letsencrypt-prod-issuer.yaml
Step 5: Create an Ingress with TLS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: front-end-ingress
namespace: sock-shop
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
kubernetes.io/ingress.class: contour
spec:
tls:
- hosts:
- example.com
secretName: sock-shop-tls
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: front-end
port:
number: 80
Once applied, cert-manager detects the annotation, requests a certificate from Let’s Encrypt, handles the HTTP01 challenge, and stores the cert in the sock-shop-tls secret automatically.
Verify
kubectl get certificate -n sock-shop
kubectl describe certificate sock-shop-tls -n sock-shop
When the certificate status shows Ready: True, your application is serving HTTPS with an auto-renewing certificate. No manual intervention needed.
Originally published on Medium — May 20, 2021