How to setup free ssl certificate in k8s using lets encrypt?
Learn how to install cert-manager using helm and use cert-manager to issue ssl certificates via Let’s Encrypt and configure SSL in traefik ingress.
In this article, we will learn to install cert-manager using helm and use cert-manager to issue ssl certificates via Let’s Encrypt and configure SSL in traefik ingress.
cert-manager
cert-manager is a certificate management solution for kubernetes. It helps in automating certificate management tasks like issuing new certificates and renew certificates.
It creates ClusterIssuer
and Certificate
custom resource definitions in k8s which we can use to automate the certificate management process in a declarative manner.
It supports certificate issuers including,
- Let’s Encrypt (ACME)
- HashiCorp Vault
- Venafi
- private PKI
Certificate resolvers
Before issuing a certificate, The ACME CA server need to verify that a you own the domain to prevent a user fraudulently impersonate another’s domain. So the client needs to complete "challenges".
It provides two kinds of challenge mechanism.
- HTTP01
- DNS01
HTTP01 challenge
HTTP01 challenge completes domain ownership by uploading a computed key to the domain and verifies by accessing the computed key through HTTP.
For example, If you ask the cert-manager to issue a certificate for mywebsite.com, the issuer uploads some content at mywebsite.com/a-key.txt
If your domain is already accessible through http and you don't have access to DNS servers, you can use this method.
DNS01 challenge
DNS01 challenge completes domain ownership by adding a computed key to the DNS TXT record and verifies using DNS lookup.
Install cert-manager using helm
$ helm repo add jetstack https://charts.jetstack.io
$ helm repo update
$ helm install \
cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.7.1 \
--set installCRDs=true
Verify cert-manager installation
Check cert-manager, cert-manager-cainjector, and cert-manager-webhook pods in the cert-manager namespace are in Running state.
$ kubectl get pods --namespace cert-manager
Create test-resources.yaml
cat <<EOF > test-resources.yaml
apiVersion: v1
kind: Namespace
metadata:
name: cert-manager-test
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: test-selfsigned
namespace: cert-manager-test
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: selfsigned-cert
namespace: cert-manager-test
spec:
dnsNames:
- example.com
secretName: selfsigned-cert-tls
issuerRef:
name: test-selfsigned
EOF
Apply the manifest to cluster
kubectl apply -f test-resources.yaml
Wait for few seconds and run below command to check if it say "Certificate issued successfully", then we are good to go.
kubectl describe certificate -n cert-manager-test
Create Lets Encrypt Staging Issuer
It is recommended to us staging issuer to verify the certificate issuer is setup correctly and to avoid rate limiting by lets encrypt. In this example, We are using http01 challenge method in to verify domain ownership.
create staging-issuer.yaml and set your ingress class.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
namespace: myapp
spec:
acme:
# The ACME Staging server URL
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: myemail@myapp.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-staging
# Enable the HTTP-01 challenge provider
solvers:
# An empty 'selector' means that this solver matches all domains
- selector: {}
http01:
ingress:
class: traefik/nginx/myingressclass
Create Certificate resource
create cert.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: my-app-com
namespace: myapp
spec:
secretName: myapp-com-tls
issuerRef:
name: letsencrypt-staging
kind: ClusterIssuer
commonName: myapp.com
dnsNames:
- www.myapp.com
Apply the manifest to the cluster
$ kubectl apply -f staging-issuer.yaml
$ kubectl apply -f cert.yaml
Verify certificate creation
Run this command below, and you should see "The certificate has been successfully issued" event. This process will create tls cerificate as a k8s secret with the name "myapp-com-tls". We can reference this secret name in ingress manifests to setup ingress.
$ kubectl describe certificate my-app-com
If not, copy resource id next to certicaterequest event and run the command below for example, if the message is "Created new CertificateRequest resource "selfsigned-cert-2gd9x", run
$ kubectl describe certificaterequest selfsigned-cert-2gd9x
You should see the reason for error.
Lets Encrypt Production Issuer
Copy the staging-issuer.yaml and. replace the server url to below
server: https://acme-v02.api.letsencrypt.org/directory
Configure traefik Ingress
Configure the ingress with the tls secret name mentioned in the cert.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: my-ingress
spec:
entryPoints:
- web
- websecure
routes:
- match: Host(`myapp.com`)
kind: Rule
services:
- name: my-app-svc
port: 3000
tls:
secretName: myapp-com-tls
This will enable ssl for the myapp.com domain.
Thanks for reading. 😀
If you like this article, subscribe to the newsletter and Connect with me on twitter to get updates on my future articles. ✅
Did you find this article valuable?
Support Suresh Kumar by becoming a sponsor. Any amount is appreciated!