Use a letsencrypt certificate on Kubernetes with cert-manager and Traefik

traefik k3s ingress letsencrypt cert-manager

4 min read | by Jordi Prats

To be able to automatically request letsencrypt certificates for the TLS-eanble Ingress objects in a kubernetes cluster with the traefik ingress controller we can use the cert-manager controller.

First we'll be installing it using helm. To do se we don't need to add any values, unless we want it to configuew the ClusterIssuer for us. First we are going to load the repository and update it:s

$ helm repo add jetstack https://charts.jetstack.io $ helm repo update 

Once ready we can install it as follows:

helm install cert-manager jetstack/cert-manager --namespace cert-manager 

We'll need to give it a few seconds to spin up all the containers:

$ kubectl get pods -n cert-manager NAME READY STATUS RESTARTS AGE cert-manager-6ffb79dfdb-mqkvm 1/1 Running 0 13s cert-manager-cainjector-5fcd49c96-2zfmw 1/1 Running 0 13s cert-manager-webhook-796ff7697b-9w67w 1/1 Running 0 13s 

Once ready we can now create the ClusterIssuer objects, which defines how to connect to the external provider via the ingress controller. For this example we are going to use K3S's default ingress controller: traefik, requesting certificates to letsencrypt:

apiVersion: cert-manager.io/v1alpha2 kind: ClusterIssuer metadata:  name: letsencrypt spec:  acme:  server: https://acme-v02.api.letsencrypt.org/directory  email: email@pet2cattle.com  privateKeySecretRef:  name: letsencrypt-ca  solvers:  - http01:  ingress:  ingressTemplate:  metadata:  annotations:  "kubernetes.io/ingress.class": "traefik" 

privateKeySecretRef is where the data is stored, it will be created for us.

We can use kubectl describe to check whether or now the ClusterIssuer is able to issue new certificates

$ kubectl describe clusterissuer letsencrypt Name: letsencrypt Namespace: Labels: <none> Annotations: <none> API Version: cert-manager.io/v1 Kind: ClusterIssuer Metadata:  (...) Status:  Acme:  Last Registered Email: jprats@systemadmin.es  Uri: https://acme-v02.api.letsencrypt.org/acme/acct/1112900837  Conditions:  Last Transition Time: 2023-05-16T17:30:44Z  Message: The ACME account was registered with the ACME server  Observed Generation: 1  Reason: ACMEAccountRegistered  Status: True  Type: Ready Events: <none> 

Once we have the ClusterIssuer we'll need to make sure we have the application exposed using an Ingress with the tls options:

apiVersion: networking.k8s.io/v1 kind: Ingress metadata:  name: awscost spec:  ingressClassName: traefik  rules:  - host: awscost.pet2cattle.com  http:  paths:  - backend:  service:  name: awscost  port:  name: http  path: /  pathType: Prefix  tls:  - hosts:  - awscost.pet2cattle.com  secretName: awscost-pet2cattle-https-cert 

The secret referenced in secretName is where the certificate is going to be stored, we don't need to populate it with anything.

The requirements, depending on the issuer, we'll be different. For letsencrypt we'll need to make this reachable for them to validate it so we'll need to make sure DNS is updated as well.

With the application reachable we can now proceed to create the Certificate with the commonName and SAN (dnsNames) we need:

apiVersion: cert-manager.io/v1 kind: Certificate metadata:  name: awscost-pet2cattle-https-cert spec:  commonName: awscost.pet2cattle.com  dnsNames:  - awscost.pet2cattle.com  issuerRef:  kind: ClusterIssuer  name: letsencrypt  secretName: awscost-pet2cattle-https-cert 

Once created, the cert-manager controller will need to request the certificate and with for the CA to create it. It's going to take a few minutes. We can check it's status directly with kubectl get looking as the READY column:

$ kubectl get certificate NAME READY SECRET AGE awscost-pet2cattle-https-cert False awscost-pet2cattle-https-cert 6s (...) $ kubectl get certificate NAME READY SECRET AGE awscost-pet2cattle-https-cert True awscost-pet2cattle-https-cert 5m42s 

In the status section we can see some details of the certificate itself:

$ kubectl get certificate awscost-pet2cattle-https-cert -n awscost -o yaml apiVersion: cert-manager.io/v1 kind: Certificate metadata:  (...) spec:  commonName: awscost.pet2cattle.com  dnsNames:  - awscost.pet2cattle.com  issuerRef:  kind: ClusterIssuer  name: letsencrypt  secretName: awscost-pet2cattle-https-cert status:  conditions:  - lastTransitionTime: "2023-05-17T18:12:20Z"  message: Certificate is up to date and has not expired  observedGeneration: 2  reason: Ready  status: "True"  type: Ready  notAfter: "2023-08-15T17:12:18Z"  notBefore: "2023-05-17T17:12:19Z"  renewalTime: "2023-07-16T17:12:18Z"  revision: 1 

Posted on 23/05/2023