How to Install and Configure cert-manager in Kubernetes¶
This guide explains how to install, configure, and use cert-manager to automate certificate management in Kubernetes.
What is cert-manager?¶
cert-manager is a powerful and extensible X.509 certificate controller for Kubernetes. It supports: - Automatic certificate issuance and renewal - Multiple certificate authorities (Let's Encrypt, HashiCorp Vault, etc.) - Multiple certificate types (wildcard, SAN) - Integration with Ingress controllers - Kubernetes-native certificate management
Prerequisites¶
- Kubernetes cluster (v1.20 or higher)
- kubectl installed and configured
- Helm 3.x (for Helm installation method)
- Basic understanding of TLS/SSL certificates
Installation Methods¶
1. Using Helm (Recommended)¶
# Add the Jetstack Helm repository
helm repo add jetstack https://charts.jetstack.io
helm repo update
# Install cert-manager
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set installCRDs=true \
--set prometheus.enabled=true \
--version v1.13.2
2. Using Kubernetes Manifests¶
# Install cert-manager CRDs
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.2/cert-manager.crds.yaml
# Install cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.2/cert-manager.yaml
Verifying the Installation¶
# Check cert-manager pods
kubectl get pods -n cert-manager
Output:
NAME READY STATUS RESTARTS AGE
cert-manager-55b7945f67-xk8q2 1/1 Running 0 2m
cert-manager-cainjector-9b4f96d75-c6lvg 1/1 Running 0 2m
cert-manager-webhook-5d59d996d4-dj8k9 1/1 Running 0 2m
# Check cert-manager services
kubectl get services -n cert-manager
Output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cert-manager ClusterIP 10.96.188.43 <none> 9402/TCP 2m
cert-manager-webhook ClusterIP 10.96.134.21 <none> 443/TCP 2m
# Check cert-manager API resources
kubectl get apiservice v1.cert-manager.io
Output:
NAME SERVICE AVAILABLE AGE
v1.cert-manager.io cert-manager/cert-manager True 2m
Configuring Certificate Issuers¶
1. Let's Encrypt Production Issuer¶
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: your-email@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx
2. Let's Encrypt Staging Issuer (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: your-email@example.com
privateKeySecretRef:
name: letsencrypt-staging
solvers:
- http01:
ingress:
class: nginx
3. Self-Signed Issuer (For Development)¶
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: selfsigned-issuer
spec:
selfSigned: {}
Using Certificates¶
1. Create a Certificate¶
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-com
namespace: default
spec:
secretName: example-com-tls
duration: 2160h # 90 days
renewBefore: 360h # 15 days
subject:
organizations:
- Example Inc.
commonName: example.com
dnsNames:
- example.com
- www.example.com
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
2. Using with Ingress¶
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- example.com
secretName: example-com-tls
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
Advanced Configurations¶
1. DNS01 Challenge Configuration (for Wildcard Certificates)¶
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod-dns
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: your-email@example.com
privateKeySecretRef:
name: letsencrypt-prod-dns
solvers:
- dns01:
cloudflare:
email: your-cloudflare-email
apiTokenSecretRef:
name: cloudflare-api-token-secret
key: api-token
2. Certificate Request Rate Limiting¶
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod-ratelimited
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: your-email@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx
externalAccountBinding:
keyID: your-kid
keySecretRef:
name: eab-secret
key: secret
Monitoring and Troubleshooting¶
1. Enable Prometheus Metrics¶
prometheus:
enabled: true
servicemonitor:
enabled: true
2. Common Debugging Commands¶
# Check certificate status
kubectl describe certificate example-com
Output:
Name: example-com
Namespace: default
Labels: <none>
Annotations: <none>
API Version: cert-manager.io/v1
Kind: Certificate
Metadata:
Creation Timestamp: 2025-09-23T10:15:22Z
Generation: 1
Spec:
Dns Names:
example.com
www.example.com
Issuer Ref:
Kind: ClusterIssuer
Name: letsencrypt-prod
Secret Name: example-com-tls
Status:
Conditions:
Last Transition Time: 2025-09-23T10:16:02Z
Message: Certificate is up to date and has not expired
Reason: Ready
Status: True
Type: Ready
Not After: 2025-12-22T10:15:22Z
Not Before: 2025-09-23T10:15:22Z
Renewal Time: 2025-12-07T10:15:22Z
Revision: 1
# Check certificate request
kubectl describe certificaterequest example-com-2h4j9
Output:
Name: example-com-2h4j9
Namespace: default
Labels: <none>
Annotations: cert-manager.io/certificate-name: example-com
cert-manager.io/certificate-revision: 1
API Version: cert-manager.io/v1
Kind: CertificateRequest
Spec:
Request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ...
Issuer Ref:
Kind: ClusterIssuer
Name: letsencrypt-prod
Status:
Conditions:
Last Transition Time: 2025-09-23T10:15:42Z
Message: Certificate request has been approved
Reason: Issued
Status: True
Type: Ready
# Check issuer status
kubectl describe clusterissuer letsencrypt-prod
Output:
Name: letsencrypt-prod
Namespace:
Labels: <none>
Annotations: <none>
API Version: cert-manager.io/v1
Kind: ClusterIssuer
Spec:
Acme:
Email: your-email@example.com
Preferred Chain:
Private Key Secret Ref:
Name: letsencrypt-prod
Server: https://acme-v02.api.letsencrypt.org/directory
Solvers:
Http01:
Ingress:
Class: nginx
Status:
Acme:
Last Registered Email: your-email@example.com
Uri: https://acme-v02.api.letsencrypt.org/acme/acct/123456789
Conditions:
Last Transition Time: 2025-09-23T10:14:22Z
Message: The ACME account was registered with the ACME server
Reason: ACMEAccountRegistered
Status: True
Type: Ready
# View cert-manager logs
kubectl logs -n cert-manager -l app=cert-manager
Output:
I0923 10:14:20.123456 1 start.go:89] cert-manager version: v1.13.2
I0923 10:14:21.123456 1 controller.go:129] cert-manager/controller-runtime "msg"="Starting EventSource"
I0923 10:14:21.234567 1 controller.go:176] cert-manager/controller-runtime "msg"="Starting Controller"
I0923 10:14:21.345678 1 controller.go:190] cert-manager/controller-runtime "msg"="Starting workers" "controller"="certificates" "worker count"=1
# Check challenges
kubectl get challenges --all-namespaces
Output:
NAMESPACE NAME STATE DOMAIN AGE
default example-com-2h4j9-1234567890 pending example.com 30s
default example-com-2h4j9-0987654321 pending www.example.com 30s
Maintenance¶
1. Upgrading cert-manager¶
# Using Helm
helm repo update
helm upgrade cert-manager jetstack/cert-manager \
--namespace cert-manager \
--reuse-values \
--version v1.13.2
# Using manifests
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.2/cert-manager.yaml
2. Uninstallation¶
# Using Helm
helm uninstall cert-manager -n cert-manager
kubectl delete namespace cert-manager
# Remove CRDs
kubectl delete -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.2/cert-manager.crds.yaml
# Using manifests
kubectl delete -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.2/cert-manager.yaml
Best Practices¶
- Always use staging issuer first
- Implement proper rate limiting
- Set appropriate renewal windows
- Use ClusterIssuers for multi-namespace certificates
- Regularly monitor certificate status
Next Steps¶
- Set up monitoring and alerting for certificate expiry
- Implement automated certificate renewal verification
- Configure backup solutions for certificates
- Set up multiple issuers for redundancy
- Implement certificate transparency logging ```