Skip to content

SSL/TLS Module (Cert-Manager)

Complete guide to deploying and managing SSL/TLS certificates with automatic renewal, Let’s Encrypt integration, and certificate lifecycle management.

The Cert-Manager module provides automated certificate management for Kubernetes clusters. It handles the issuance, renewal, and lifecycle management of SSL/TLS certificates from various certificate authorities, with seamless integration to Let’s Encrypt for free certificates.

Cert-Manager Deployment:
├── Cert-Manager Controller
├── Webhook Server
├── CA Injector
├── Cluster Issuers
├── Certificate Resources
├── HTTP-01 Challenge Solver
└── DNS-01 Challenge Solver
  • Automatic Issuance: Request and obtain certificates automatically
  • Auto-Renewal: Proactive certificate renewal before expiration
  • Lifecycle Management: Complete certificate lifecycle handling
  • Multiple CAs: Support for Let’s Encrypt, self-signed, and custom CAs
  • Free Certificates: Zero-cost SSL/TLS certificates
  • HTTP-01 Challenges: Domain validation via HTTP challenges
  • DNS-01 Challenges: Domain validation via DNS challenges
  • Rate Limiting: Built-in rate limit handling
  • Wildcard Certificates: Support for wildcard domain certificates
  • Certificate Storage: Secure certificate storage in Kubernetes secrets
  • Monitoring: Certificate status monitoring and alerting
  • Webhook Integration: Custom validation and approval workflows

The Cert-Manager deployment uses Helmfile for environment management:

iac/modules/cert-manager/helmfile.yaml
repositories:
- name: jetstack
url: "https://charts.jetstack.io"
releases:
- name: cert-manager
namespace: cert-manager
createNamespace: true
chart: jetstack/cert-manager
version: v1.17.2
- name: issuer
chart: ./ssl-middleware
namespace: default
values:
iac/modules/cert-manager/ssl-middleware/values.yaml
iac/modules/cert-manager/ssl-middleware/templates/cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
annotations:
"helm.sh/hook": "post-install"
"helm.sh/hook-weight": "0"
spec:
acme:
email: { { .Values.email } }
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
ingressClassName: traefik
iac/modules/cert-manager/ssl-middleware/templates/middleware.yaml
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: redirect-https
spec:
redirectScheme:
scheme: https
permanent: true
# Example certificate request
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: myapp-cert
namespace: default
spec:
secretName: myapp-tls
issuerRef:
name: letsencrypt
kind: ClusterIssuer
dnsNames:
- myapp.example.com
- www.myapp.example.com
duration: 2160h # 90 days
renewBefore: 360h # 15 days
# Ingress with automatic certificate
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt"
traefik.ingress.kubernetes.io/router.entrypoints: "websecure"
traefik.ingress.kubernetes.io/router.tls: "true"
spec:
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp-service
port:
number: 80
# Wildcard certificate with DNS-01 challenge
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: wildcard-cert
spec:
secretName: wildcard-tls
issuerRef:
name: letsencrypt-dns
kind: ClusterIssuer
dnsNames:
- "*.example.com"
- example.com
Terminal window
# Check Cert-Manager service status
kubectl get pods -n cert-manager -l app.kubernetes.io/name=cert-manager
# Check service endpoints
kubectl get endpoints -n cert-manager -l app.kubernetes.io/name=cert-manager
# Test Cert-Manager API
kubectl get crd | grep cert-manager
Terminal window
# List all certificates
kubectl get certificates --all-namespaces
# Check certificate status
kubectl describe certificate myapp-cert -n default
# View certificate events
kubectl get events --field-selector involvedObject.name=myapp-cert -n default
# Check certificate secret
kubectl get secret myapp-tls -n default -o yaml
Terminal window
# List cluster issuers
kubectl get clusterissuer
# Check issuer status
kubectl describe clusterissuer letsencrypt
# View issuer events
kubectl get events --field-selector involvedObject.name=letsencrypt
Terminal window
# Check resource usage
kubectl top pods -n cert-manager -l app.kubernetes.io/name=cert-manager
# Monitor certificate renewals
kubectl get events --field-selector reason=Renewed -n default
# Check for failed certificate requests
kubectl get events --field-selector reason=Failed -n default
Terminal window
# View Cert-Manager logs
kubectl logs -n cert-manager -l app.kubernetes.io/name=cert-manager
# Follow logs in real-time
kubectl logs -f -n cert-manager deployment/cert-manager
# Check for errors
kubectl logs -n cert-manager -l app.kubernetes.io/name=cert-manager | grep ERROR
Terminal window
# Navigate to module directory
cd iac/modules/cert-manager
# Install CRDs first
task install
# Deploy using Helmfile
helmfile apply
# Verify deployment
kubectl get pods -n cert-manager
kubectl get pods -n default -l app.kubernetes.io/name=issuer
Terminal window
# Check pod status
kubectl get pods -n cert-manager -l app.kubernetes.io/name=cert-manager
# Verify CRDs installed
kubectl get crd | grep cert-manager
# Check cluster issuer
kubectl get clusterissuer letsencrypt
# Test certificate issuance
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: test-cert
spec:
secretName: test-tls
issuerRef:
name: letsencrypt
kind: ClusterIssuer
dnsNames:
- test.example.com
EOF
Terminal window
# Verify cluster issuer is ready
kubectl describe clusterissuer letsencrypt
# Check for any pending certificates
kubectl get certificates --all-namespaces
# Monitor certificate events
kubectl get events --field-selector involvedObject.kind=Certificate
Terminal window
# List all certificates
kubectl get certificates --all-namespaces
# Check certificate details
kubectl describe certificate myapp-cert -n default
# Force certificate renewal
kubectl patch certificate myapp-cert -n default -p '{"spec":{"renewBefore":"720h"}}'
# Delete certificate
kubectl delete certificate myapp-cert -n default
Terminal window
# List cluster issuers
kubectl get clusterissuer
# Update cluster issuer
kubectl patch clusterissuer letsencrypt -p '{"spec":{"acme":{"email":"[email protected]"}}}'
# Check issuer status
kubectl describe clusterissuer letsencrypt
Terminal window
# List all certificate secrets
kubectl get secrets --all-namespaces | grep tls
# Clean up expired certificates
kubectl get certificates --all-namespaces -o json | \
jq '.items[] | select(.status.conditions[].status == "False") | .metadata.name'
# Delete unused certificate secrets
kubectl delete secret unused-tls -n default
Terminal window
# Update Cert-Manager version
helmfile apply
# Monitor update progress
kubectl rollout status deployment/cert-manager -n cert-manager
# Rollback if needed
kubectl rollout undo deployment/cert-manager -n cert-manager
Terminal window
# Check certificate status
kubectl describe certificate myapp-cert -n default
# View certificate events
kubectl get events --field-selector involvedObject.name=myapp-cert -n default
# Check challenge status
kubectl get challenges --all-namespaces
# Verify ingress configuration
kubectl describe ingress myapp-ingress -n default
Terminal window
# Check challenge pod
kubectl get pods --all-namespaces | grep cm-acme-http-solver
# Check challenge service
kubectl get services --all-namespaces | grep cm-acme-http-solver
# Verify ingress configuration
kubectl get ingress --all-namespaces -o yaml | grep -A 10 -B 10 cm-acme-http-solver
# Test challenge endpoint
curl -I http://myapp.example.com/.well-known/acme-challenge/test
Terminal window
# Check DNS provider configuration
kubectl describe clusterissuer letsencrypt-dns
# Verify DNS records
dig TXT _acme-challenge.example.com
# Check DNS provider credentials
kubectl get secret cloudflare-api-token -n cert-manager -o yaml
Terminal window
# Check Let's Encrypt rate limits
kubectl get events --field-selector reason=RateLimited
# Monitor certificate requests
kubectl get certificates --all-namespaces
# Check for duplicate requests
kubectl get orders --all-namespaces
Terminal window
# Force delete stuck certificates
kubectl delete certificate myapp-cert -n default --grace-period=0 --force
# Restart Cert-Manager
kubectl rollout restart deployment/cert-manager -n cert-manager
# Clear challenge resources
kubectl delete challenges --all --all-namespaces
kubectl delete orders --all --all-namespaces
# Verify recovery
kubectl get certificates --all-namespaces
# Network policy for Cert-Manager
networkPolicy:
enabled: true
allowExternal: true
egressRules:
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
# Service account permissions
serviceAccount:
create: true
annotations: {}
automountServiceAccountToken: true
# RBAC rules
rbac:
create: true
rules:
- apiGroups: ["cert-manager.io"]
resources: ["certificates", "certificaterequests", "issuers"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# Certificate security settings
certificate:
duration: 2160h # 90 days
renewBefore: 360h # 15 days
keyAlgorithm: RSA
keySize: 2048
keyEncoding: PKCS1
# Production-ready configuration
replicaCount: 2
resources:
requests:
memory: 256Mi
cpu: 100m
limits:
memory: 512Mi
cpu: 200m
# High availability
podDisruptionBudget:
enabled: true
minAvailable: 1
# Monitoring
metrics:
enabled: true
serviceMonitor:
enabled: true
# Staging environment with 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
privateKeySecretRef:
name: letsencrypt-staging
solvers:
- http01:
ingress:
ingressClassName: traefik
# Custom certificate authority
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: custom-ca
spec:
ca:
secretName: custom-ca-secret
  • Monitor certificate status
  • Check for failed renewals
  • Review certificate events
  • Verify cluster health
  • Analyze certificate metrics
  • Review certificate inventory
  • Update issuer configurations
  • Check for updates
  • Certificate inventory audit
  • Security review
  • Performance optimization
  • Disaster recovery testing
  • CRDs installed
  • Namespace created
  • RBAC configured
  • Network policies defined
  • Email address configured
  • Cert-Manager pods running
  • Cluster issuer configured
  • Webhook functional
  • Test certificate issued
  • Ingress integration verified
  • Certificate renewals monitored
  • Rate limits respected
  • Security updates applied
  • Performance optimized
  • Disaster recovery tested

The Cert-Manager SSL/TLS module provides automated certificate management with Let’s Encrypt integration and comprehensive lifecycle management.