Cert Manager and Let's Encrypt

Cert Manager and Let's Encrypt in Thalassa Cloud Kubernetes

Cert Manager is a Kubernetes-native certificate management controller that automates the issuance, renewal, and management of TLS certificates. By installing Cert Manager with Let’s Encrypt in your Thalassa Cloud Kubernetes cluster, you can automatically provision and renew TLS certificates for your applications, ensuring secure HTTPS connections without manual certificate management. This guide walks you through installing Cert Manager, configuring Let’s Encrypt as a certificate issuer, and setting up automatic certificate provisioning for your applications.

Prerequisites

  • Before installing Cert Manager, ensure you have a few things in place. First, you need a running Kubernetes cluster in Thalassa Cloud. Cert Manager works with Kubernetes 1.24 or later, and Thalassa Cloud clusters meet this requirement. If you’re new to Thalassa Cloud Kubernetes, see the Getting Started guide for cluster creation and basic setup.
  • You’ll also need cluster access configured using kubectl. Use tcloud kubernetes connect to configure access, or set up kubeconfig manually. You’ll need cluster administrator permissions to install Cert Manager, as it requires creating cluster-level resources.
  • For Let’s Encrypt certificates, you’ll need a domain name that points to your cluster. Let’s Encrypt validates domain ownership before issuing certificates, so your domain must resolve to an IP address that your cluster can serve traffic from. This typically means configuring DNS to point to a load balancer or ingress controller in your cluster.

Installing Cert Manager

The recommended way to install Cert Manager is using Helm, which provides a straightforward installation process and makes it easy to configure the controller.

First, add the Cert Manager Helm repository:

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

Install Cert Manager using Helm:

helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --set installCRDs=true

The installCRDs=true flag automatically installs the Custom Resource Definitions (CRDs) that Cert Manager needs. These CRDs define the Issuer, ClusterIssuer, and Certificate resources.

Verify that Cert Manager is running:

kubectl get pods -n cert-manager

You should see pods for the Cert Manager controller, webhook, and CA injector. Wait for all pods to be ready:

kubectl wait --for=condition=Ready pod -l app.kubernetes.io/instance=cert-manager -n cert-manager --timeout=300s

Verify that the CRDs are installed:

kubectl get crd | grep cert-manager

You should see CRDs for certificates.cert-manager.io, issuers.cert-manager.io, clusterissuers.cert-manager.io, and related resources.

Configuring Let’s Encrypt Issuer

Once Cert Manager is installed, configure Let’s Encrypt as a certificate issuer. Cert Manager supports two types of issuers: Issuer, which is namespace-scoped, and ClusterIssuer, which works across all namespaces. For most use cases, a ClusterIssuer is convenient because you can use it from any namespace.

Let’s Encrypt provides two environments: staging and production. The staging environment is useful for testing because it has higher rate limits and doesn’t issue trusted certificates. Use staging first to verify your setup works, then switch to production.

Create a staging ClusterIssuer for testing:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: [email protected]
    privateKeySecretRef:
      name: letsencrypt-staging-key
    solvers:
    - http01:
        ingress:
          class: nginx

Replace [email protected] with your email address. Let’s Encrypt uses this email for important notifications about your certificates.

The http01 solver uses the HTTP-01 challenge, which requires Let’s Encrypt to access your domain over HTTP. This works well with ingress controllers. The ingress.class should match your ingress controller class. Common values are nginx, traefik, or alb.

Apply the staging issuer:

kubectl apply -f letsencrypt-staging-issuer.yaml

Verify the issuer is ready:

kubectl get clusterissuer letsencrypt-staging

Once you’ve verified the staging issuer works, create a production ClusterIssuer:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: [email protected]
    privateKeySecretRef:
      name: letsencrypt-prod-key
    solvers:
    - http01:
        ingress:
          class: nginx

Apply the production issuer:

kubectl apply -f letsencrypt-prod-issuer.yaml

Let’s Encrypt Rate Limits

Let’s Encrypt has rate limits to prevent abuse. The production environment allows 50 certificates per registered domain per week. Use the staging environment for testing to avoid hitting rate limits during development.

Ingress Controller Class

The ingress class in the ClusterIssuer must match your ingress controller. If you’re using a different ingress controller, update the ingress.class value accordingly. Common ingress controllers include NGINX, Traefik, and AWS Load Balancer Controller.

Requesting Certificates

With Cert Manager and Let’s Encrypt configured, you can request certificates for your applications. The easiest way is to annotate your Ingress resources, which tells Cert Manager to automatically create certificates.

Create an Ingress resource with certificate annotations:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - myapp.example.com
    secretName: my-app-tls
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-app
            port:
              number: 80

The cert-manager.io/cluster-issuer annotation tells Cert Manager to use the letsencrypt-prod ClusterIssuer to issue a certificate. Cert Manager will automatically create a Certificate resource and manage the certificate lifecycle.

Apply the ingress:

kubectl apply -f ingress.yaml

Cert Manager will automatically create a Certificate resource:

kubectl get certificate

Check the certificate status:

kubectl describe certificate my-app-tls

The certificate goes through several stages: pending, ready, or failed. Once it’s ready, the TLS secret is created and your ingress can use it.

Automatic Certificate Management

When you annotate an Ingress with cert-manager.io/cluster-issuer, Cert Manager automatically creates and manages the Certificate resource. You don’t need to create Certificate resources manually unless you want more control over the certificate configuration.

Creating Certificates Manually

While annotating Ingress resources is convenient, you can also create Certificate resources directly for more control or for use cases where you’re not using Ingress.

Create a Certificate resource:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-app-cert
  namespace: default
spec:
  secretName: my-app-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - myapp.example.com
  - www.myapp.example.com

This creates a certificate for multiple domain names. Cert Manager will automatically request the certificate from Let’s Encrypt and store it in the my-app-tls secret.

Apply the certificate:

kubectl apply -f certificate.yaml

Check the certificate status:

kubectl get certificate
kubectl describe certificate my-app-cert

Once the certificate is ready, you can use the secret in your applications or ingress configurations.

Using Certificates with Applications

Once Cert Manager has issued a certificate, it’s stored in a Kubernetes Secret. You can use this secret in your applications or ingress configurations.

For Ingress resources, the secret is automatically used when you reference it in the tls.secretName field:

spec:
  tls:
  - hosts:
    - myapp.example.com
    secretName: my-app-tls

For applications that need certificates directly, mount the secret as a volume:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
      - name: app
        image: nginx:1.25
        volumeMounts:
        - name: tls
          mountPath: /etc/ssl/certs
          readOnly: true
      volumes:
      - name: tls
        secret:
          secretName: my-app-tls

The secret contains tls.crt (the certificate), tls.key (the private key), and ca.crt (the certificate authority chain).

Certificate Renewal

Cert Manager automatically renews certificates before they expire. Let’s Encrypt certificates are valid for 90 days, and Cert Manager starts the renewal process when a certificate has less than one-third of its validity period remaining (approximately 30 days before expiration).

You don’t need to do anything to enable renewal—Cert Manager handles it automatically. The renewal process is transparent to your applications; Cert Manager updates the secret with the new certificate, and applications using the secret automatically get the renewed certificate.

Monitor certificate status to ensure renewals are working:

kubectl get certificate

Check certificate expiration dates:

kubectl get certificate -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.notAfter}{"\n"}{end}'

Automatic Renewal

Cert Manager automatically renews certificates without manual intervention. The renewal process uses the same issuer and challenge method as the original certificate, so ensure your issuer configuration remains valid.

Troubleshooting

If certificates aren’t being issued, systematic troubleshooting helps identify the problem. Start by checking the certificate status:

kubectl describe certificate <certificate-name>

Check Cert Manager logs for errors:

kubectl logs -n cert-manager -l app.kubernetes.io/instance=cert-manager

Verify the ClusterIssuer is ready:

kubectl describe clusterissuer letsencrypt-prod

Common issues include:

  • DNS not configured: Ensure your domain points to your cluster’s load balancer or ingress controller
  • Ingress class mismatch: The ClusterIssuer’s ingress class must match your ingress controller
  • Rate limits: If you’ve hit Let’s Encrypt rate limits, wait or use the staging environment
  • Challenge failures: Check that Let’s Encrypt can access your domain over HTTP for the HTTP-01 challenge

For more detailed troubleshooting, see the Cert Manager troubleshooting documentation.

Conclusion

Cert Manager with Let’s Encrypt provides automated TLS certificate management for your Kubernetes applications. By installing Cert Manager and configuring Let’s Encrypt issuers, you can automatically provision and renew certificates without manual intervention. For more information about Cert Manager features and advanced configurations, see the official Cert Manager documentation. For details about Let’s Encrypt, see the Let’s Encrypt documentation.