# Install cert-manager (Helm)
# helm install cert-manager jetstack/cert-manager # --namespace cert-manager # --create-namespace # --set installCRDs=true
---
# ClusterIssuer for Let's Encrypt (staging)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: devops@example.com
privateKeySecretRef:
name: letsencrypt-staging-key
solvers:
- http01:
ingress:
class: nginx
---
# ClusterIssuer for Let's Encrypt (production)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: devops@example.com
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
# HTTP-01 for standard domains
- http01:
ingress:
class: nginx
# DNS-01 for wildcards (Route53 example)
- dns01:
route53:
region: us-east-1
hostedZoneID: Z1234567890ABC
selector:
dnsZones:
- "example.com"
---
# Certificate resource
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: app-tls
namespace: production
spec:
secretName: app-tls-secret
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
commonName: app.example.com
dnsNames:
- app.example.com
- api.example.com
- "*.app.example.com"
duration: 2160h # 90 days
renewBefore: 720h # 30 days before expiry
---
# Ingress with automatic TLS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-app
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/hsts: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: app-tls-secret
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-app
port:
number: 80
#!/bin/bash
# Certbot for non-Kubernetes environments
# Install certbot
apt-get update && apt-get install -y certbot python3-certbot-nginx
# Obtain certificate (Nginx plugin)
certbot --nginx -d app.example.com -d api.example.com --email devops@example.com --agree-tos --non-interactive
# Obtain certificate (standalone)
certbot certonly --standalone -d app.example.com --email devops@example.com --agree-tos
# Obtain wildcard (DNS challenge)
certbot certonly --manual --preferred-challenges dns -d "*.example.com" --email devops@example.com --agree-tos
# Test renewal
certbot renew --dry-run
# Auto-renewal (cron)
# 0 12 * * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload nginx"
# Check certificate expiry
echo | openssl s_client -servername app.example.com -connect app.example.com:443 2>/dev/null | openssl x509 -noout -dates
# Certificate locations
# /etc/letsencrypt/live/app.example.com/fullchain.pem
# /etc/letsencrypt/live/app.example.com/privkey.pem
TLS certificates encrypt traffic between clients and servers. Let's Encrypt provides free, automated certificates via the ACME protocol. In Kubernetes, cert-manager automates certificate issuance and renewal. A ClusterIssuer configures the ACME server and solver method. HTTP-01 challenges validate domain ownership via HTTP endpoints. DNS-01 challenges use DNS TXT records, required for wildcard certificates. Certificate resources request certificates for specific domains. cert-manager stores certificates as Kubernetes Secrets. Ingress annotations like cert-manager.io/cluster-issuer trigger automatic certificate provisioning. Certificates auto-renew before expiration. For non-Kubernetes environments, certbot handles certificate management with automatic renewal via cron or systemd timers.