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
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=300sConfigure a ClusterIssuer for Let’s Encrypt A
ClusterIssuertells 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 replaceyour-email@example.comwith 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 ControllerApply this manifest:
kubectl apply -f clusterissuer.yamlDeploy an Application with Ingress and Certificate Now, deploy a sample Nginx application and an Ingress resource that requests a certificate from our
letsencrypt-prodClusterIssuer. Ensure you replaceyour-domain.comwith 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: 80Apply these manifests:
kubectl apply -f nginx-app.yamlVerify the certificate status:
kubectl get certificate -n default kubectl describe certificate nginx-tls-secret -n defaultThis 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.