devops November 27, 2025

How To Secure K3s Services with Let's Encrypt using Cert-Manager

Developers struggle with manual SSL certificate management; implementing Let’s Encrypt with Cert-Manager on K3s automates secure communication for services, ensuring robust encryption with minimal effort.

Why This Solution Works

Cert-Manager automatically provisions, renews, and manages SSL/TLS certificates from Let’s Encrypt, integrating directly with Kubernetes ingresses. Key insight: This eliminates the manual overhead and risk of expired certificates, providing always-on HTTPS for applications deployed on K3s.

Step-by-Step Implementation

  1. Install Cert-Manager Begin by installing Cert-Manager into your K3s cluster. Cert-Manager is responsible for automating certificate lifecycle management.

    kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
    kubectl wait --for=condition=ready pod -l app.kubernetes.io/instance=cert-manager -n cert-manager --timeout=300s
    
  2. Configure a ClusterIssuer for Let’s Encrypt A ClusterIssuer tells Cert-Manager how to obtain certificates from Let’s Encrypt using the ACME protocol. We’ll use the HTTP01 challenge, which is common with K3s’s default Traefik Ingress. Remember to replace your-email@example.com with your actual email.

    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: letsencrypt-prod
    spec:
      acme:
        email: your-email@example.com # <--- REPLACE WITH YOUR EMAIL
        server: https://acme-v02.api.letsencrypt.org/directory
        privateKeySecretRef:
          name: letsencrypt-prod-private-key
        solvers:
        - http01:
            ingress:
              class: traefik # K3s default Ingress Controller
    

    Apply this manifest:

    kubectl apply -f clusterissuer.yaml
    
  3. Deploy an Application with Ingress and Certificate Now, deploy a sample Nginx application and an Ingress resource that requests a certificate from our letsencrypt-prod ClusterIssuer. Ensure you replace your-domain.com with your actual domain name.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      labels:
        app: nginx
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:latest
            ports:
            - containerPort: 80
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-service
    spec:
      selector:
        app: nginx
      ports:
        - protocol: TCP
          port: 80
          targetPort: 80
      type: ClusterIP
    ---
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: nginx-ingress
      annotations:
        cert-manager.io/cluster-issuer: letsencrypt-prod
        ingress.kubernetes.io/ssl-redirect: "true" # Optional: force HTTPS
    spec:
      ingressClassName: traefik # K3s default Ingress Controller
      tls:
        - hosts:
          - your-domain.com # <--- REPLACE WITH YOUR DOMAIN
          secretName: nginx-tls-secret # Cert-Manager will store the cert here
      rules:
        - host: your-domain.com # <--- REPLACE WITH YOUR DOMAIN
          http:
            paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: nginx-service
                  port:
                    number: 80
    

    Apply these manifests:

    kubectl apply -f nginx-app.yaml
    

    Verify the certificate status:

    kubectl get certificate -n default
    kubectl describe certificate nginx-tls-secret -n default
    

    This setup typically provisions a valid SSL certificate within 1-5 minutes and ensures automated renewal every 60-90 days, eliminating manual certificate management efforts by 100%.

When to Use This (Not Use This)

Use this for: Any K3s environment hosting publicly accessible services, microservices requiring secure communication, or when rapid deployment of SSL/TLS is critical without manual overhead. Avoid for: Internal-only services that do not require external access, or environments where a commercial wildcard certificate is already centrally managed by other means.