Skip to content

Cert-Manager Cheatsheet

Installation

Platform Command
kubectl (Static Manifests) kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.yaml
Helm (Recommended) helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --set installCRDs=true
macOS (cmctl CLI) brew install cmctl
Linux (cmctl CLI) curl -sSL https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cmctl-linux-amd64.tar.gz \| tar xz && sudo mv cmctl /usr/local/bin
Windows (cmctl CLI) curl.exe -L -o cmctl.exe https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cmctl-windows-amd64.exe
Verify Installation kubectl get pods -n cert-manager

Helm Repository Setup

# Add Jetstack Helm repository
helm repo add jetstack https://charts.jetstack.io

# Update repository
helm repo update

# Install with custom values
helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version v1.13.3 \
  --values custom-values.yaml

Basic Commands

Command Description
kubectl get certificates List all certificates in current namespace
kubectl get certificates -A List certificates across all namespaces
kubectl describe certificate <name> Show detailed certificate information
kubectl get certificate <name> -o yaml View certificate in YAML format
kubectl get issuer List all issuers in current namespace
kubectl get clusterissuer List all cluster-wide issuers
kubectl describe issuer <name> Show detailed issuer information
kubectl get certificaterequest List certificate requests
kubectl get order View ACME certificate orders
kubectl get challenge View ACME challenges for domain validation
kubectl logs -n cert-manager deployment/cert-manager View cert-manager controller logs
kubectl logs -n cert-manager deployment/cert-manager-webhook View webhook logs
kubectl logs -n cert-manager deployment/cert-manager-cainjector View CA injector logs
cmctl check api Verify cert-manager API is available
cmctl version Display cert-manager version information
cmctl status certificate <name> Check certificate status and readiness
cmctl inspect secret <secret-name> Inspect TLS secret created by cert-manager
cmctl renew <cert-name> Manually trigger certificate renewal
kubectl get crd \| grep cert-manager List all cert-manager Custom Resource Definitions
kubectl get events --field-selector involvedObject.name=<cert-name> View events related to specific certificate

Advanced Usage

Command Description
cmctl approve <certificaterequest-name> Manually approve a certificate request
cmctl deny <certificaterequest-name> Deny a certificate request
cmctl create certificaterequest test --from-certificate-file=cert.yaml Create certificate request from file
cmctl convert --output-format=pem --input-file=cert.yaml Convert certificate to PEM format
cmctl experimental create acmeaccount --server=<url> --email=<email> Test ACME account registration
kubectl annotate certificate <name> cert-manager.io/issue-temporary-certificate="true" --overwrite Force immediate certificate renewal
kubectl delete certificaterequest <name> Remove failed certificate request
kubectl delete order <name> Delete ACME order
kubectl delete challenge <name> Remove stuck ACME challenge
kubectl get certificate <name> -o jsonpath='{.status.conditions}' Extract certificate status conditions
kubectl get secret <tls-secret> -o jsonpath='{.data.tls\.crt}' \| base64 -d \| openssl x509 -text -noout Decode and view certificate details
kubectl get secret <tls-secret> -o jsonpath='{.data.tls\.crt}' \| base64 -d \| openssl x509 -noout -dates Check certificate expiration dates
helm upgrade cert-manager jetstack/cert-manager --namespace cert-manager --version v1.13.3 Upgrade cert-manager to new version
kubectl rollout restart deployment -n cert-manager Restart all cert-manager components
kubectl scale deployment cert-manager -n cert-manager --replicas=2 Scale cert-manager for high availability
kubectl get certificate --watch Watch certificate status changes in real-time
kubectl patch certificate <name> --type merge -p '{"spec":{"renewBefore":"720h"}}' Modify certificate renewal window
kubectl delete secret <tls-secret> Delete certificate secret (triggers recreation)
cmctl experimental install Install cert-manager using cmctl tool
cmctl experimental uninstall Uninstall cert-manager and clean up resources

Configuration

Self-Signed ClusterIssuer

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}

Let's Encrypt Staging (HTTP-01 Challenge)

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-staging
    solvers:
    - http01:
        ingress:
          class: nginx

Let's Encrypt Production (DNS-01 Challenge)

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - dns01:
        cloudDNS:
          project: my-gcp-project
          serviceAccountSecretRef:
            name: clouddns-dns01-solver
            key: key.json

CA Issuer (Internal PKI)

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: ca-issuer
  namespace: default
spec:
  ca:
    secretName: ca-key-pair

Certificate Resource

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-com
  namespace: default
spec:
  secretName: example-com-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - example.com
  - www.example.com
  duration: 2160h      # 90 days
  renewBefore: 360h    # 15 days before expiry

Wildcard Certificate

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-cert
  namespace: default
spec:
  secretName: wildcard-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - "*.example.com"
  - example.com

Vault Issuer

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: vault-issuer
  namespace: default
spec:
  vault:
    server: https://vault.example.com
    path: pki/sign/example-dot-com
    auth:
      kubernetes:
        mountPath: /v1/auth/kubernetes
        role: cert-manager
        secretRef:
          name: vault-token
          key: token

Helm Values Configuration

# custom-values.yaml
installCRDs: true
replicaCount: 2

resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    cpu: 200m
    memory: 256Mi

prometheus:
  enabled: true
  servicemonitor:
    enabled: true

webhook:
  replicaCount: 2

cainjector:
  replicaCount: 2

Common Use Cases

Use Case 1: Secure Ingress with Let's Encrypt

# Create ClusterIssuer
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx
EOF

# Create Ingress with TLS annotation
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  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
EOF

# Verify certificate creation
kubectl get certificate
kubectl describe certificate example-com-tls

Use Case 2: Internal Service mTLS

# Create self-signed CA
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-ca
  namespace: cert-manager
spec:
  isCA: true
  commonName: my-ca
  secretName: my-ca-secret
  privateKey:
    algorithm: ECDSA
    size: 256
  issuerRef:
    name: selfsigned-issuer
    kind: ClusterIssuer
EOF

# Create CA issuer from generated CA
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: my-ca-issuer
spec:
  ca:
    secretName: my-ca-secret
EOF

# Issue service certificates
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: service-a-cert
  namespace: default
spec:
  secretName: service-a-tls
  duration: 8760h
  renewBefore: 720h
  subject:
    organizations:
    - my-org
  commonName: service-a.default.svc.cluster.local
  dnsNames:
  - service-a.default.svc.cluster.local
  issuerRef:
    name: my-ca-issuer
    kind: ClusterIssuer
EOF

Use Case 3: Wildcard Certificate with DNS-01

# Create DNS provider secret (example: Cloudflare)
kubectl create secret generic cloudflare-api-token \
  --from-literal=api-token=YOUR_CLOUDFLARE_API_TOKEN

# Create ClusterIssuer with DNS-01 solver
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-dns
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-dns
    solvers:
    - dns01:
        cloudflare:
          email: admin@example.com
          apiTokenSecretRef:
            name: cloudflare-api-token
            key: api-token
EOF

# Request wildcard certificate
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-example
  namespace: default
spec:
  secretName: wildcard-example-tls
  issuerRef:
    name: letsencrypt-dns
    kind: ClusterIssuer
  dnsNames:
  - "*.example.com"
  - example.com
EOF

# Monitor certificate issuance
kubectl get certificate wildcard-example -w

Use Case 4: Securing Kubernetes Webhooks

# Create certificate for webhook
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: webhook-cert
  namespace: webhook-system
spec:
  secretName: webhook-server-cert
  duration: 8760h
  renewBefore: 720h
  issuerRef:
    name: selfsigned-issuer
    kind: ClusterIssuer
  dnsNames:
  - webhook-service.webhook-system.svc
  - webhook-service.webhook-system.svc.cluster.local
EOF

# Reference in webhook configuration
kubectl apply -f - <<EOF
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: my-webhook
  annotations:
    cert-manager.io/inject-ca-from: webhook-system/webhook-cert
webhooks:
- name: webhook.example.com
  clientConfig:
    service:
      name: webhook-service
      namespace: webhook-system
      path: "/validate"
    caBundle: "" # Injected by cert-manager
EOF

Use Case 5: Certificate Rotation and Renewal

# Create certificate with short duration for testing
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: short-lived-cert
  namespace: default
spec:
  secretName: short-lived-tls
  duration: 24h
  renewBefore: 8h
  issuerRef:
    name: selfsigned-issuer
    kind: ClusterIssuer
  dnsNames:
  - test.example.com
EOF

# Monitor renewal
kubectl get certificate short-lived-cert -w

# Force immediate renewal
kubectl annotate certificate short-lived-cert \
  cert-manager.io/issue-temporary-certificate="true" \
  --overwrite

# Check renewal history
kubectl get certificaterequest -l cert-manager.io/certificate-name=short-lived-cert

# Verify new certificate
cmctl inspect secret short-lived-tls

Best Practices

  • Use ClusterIssuers for shared certificates: ClusterIssuers can be referenced from any namespace, reducing configuration duplication across your cluster

  • Start with Let's Encrypt staging: Always test with staging environment first to avoid hitting production rate limits (50 certificates per domain per week)

  • Set appropriate renewal windows: Configure renewBefore to at least ⅓ of certificate duration to allow multiple retry attempts before expiration

  • Monitor certificate expiration: Enable Prometheus metrics and set up alerts for certificates expiring within 7-14 days using certmanager_certificate_expiration_timestamp_seconds

  • Use DNS-01 for wildcards and internal services: DNS-01 challenge is required for wildcard certificates and works better for services not exposed to internet

  • Implement proper RBAC: Restrict access to Issuers and certificate secrets using Kubernetes RBAC to prevent unauthorized certificate creation

  • Version control your configurations: Store Certificate and Issuer manifests in Git to track changes and enable GitOps workflows

  • Use separate issuers per environment: Create different issuers for dev/staging/prod to isolate credentials and prevent cross-environment certificate issues

  • Enable CA injection for webhooks: Use cert-manager.io/inject-ca-from annotation to automatically inject CA bundles into webhook configurations

  • Plan for disaster recovery: Backup CA private keys and ACME account credentials stored in Kubernetes secrets to external secure storage

Troubleshooting

Issue Solution
Certificate stuck in "Pending" Check certificate request: kubectl describe certificaterequest <name>. Look for ACME challenge failures or issuer configuration errors
ACME HTTP-01 challenge failing Verify ingress is accessible: curl http://<domain>/.well-known/acme-challenge/test. Check ingress class matches solver configuration
DNS-01 challenge timeout Confirm DNS provider credentials: kubectl get secret <dns-secret> -o yaml. Verify DNS propagation: dig TXT _acme-challenge.<domain>
"Too many certificates" rate limit Switch to Let's Encrypt staging server or wait 7 days. Check rate limits: https://letsencrypt.org/docs/rate-limits/
Certificate not renewing automatically Check renewBefore setting and cert-manager logs: kubectl logs -n cert-manager deployment/cert-manager. Verify controller is running
Webhook connection failures Verify webhook service is running: kubectl get svc -n cert-manager. Check webhook certificate validity: cmctl check api
CA injection not working Ensure cainjector is running: kubectl get pods -n cert-manager. Verify annotation syntax: cert-manager.io/inject-ca-from: namespace/certificate
Certificate shows "Ready=False" Get detailed status: cmctl status certificate <name>. Check events: kubectl get events --field-selector involvedObject.name=<cert-name>
Order stuck in "Pending" Delete order to retry: kubectl delete order <order-name>. Certificate controller will create new order automatically
Secret not created after certificate ready Check secret name matches secretName in Certificate spec. Verify namespace: kubectl get secret <name> -n <namespace>
Wildcard certificate validation fails Ensure DNS-01 solver is configured (HTTP-01 doesn't support wildcards). Verify DNS provider permissions for TXT record creation
Certificate shows wrong issuer Delete certificate request: kubectl delete certificaterequest <name>. Update Certificate spec with correct issuerRef
High memory usage Reduce certificate count or increase resources: kubectl set resources deployment cert-manager -n cert-manager --limits=memory=512Mi
Duplicate certificates created Check for multiple Certificate resources with same secretName. Remove duplicates to prevent conflicts
ACME account registration fails Verify email format in issuer spec. Check ACME server URL is correct. Review cert-manager logs for detailed error messages

Debug Command Sequence

# Complete troubleshooting workflow
kubectl describe certificate <cert-name>
kubectl get certificaterequest -l cert-manager.io/certificate-name=<cert-name>
kubectl describe certificaterequest <request-name>
kubectl get order
kubectl describe order <order-name>
kubectl get challenge
kubectl describe challenge <challenge-name>
kubectl logs -n cert-manager deployment/cert-manager --tail=100

Common Log Patterns

# Search for specific certificate errors
kubectl logs -n cert-manager deployment/cert-manager | grep "certificate=<cert-name>"

# Find ACME challenge errors
kubectl logs -n cert-manager deployment/cert-manager | grep "challenge"

# Check for rate limit errors
kubectl logs -n cert-manager deployment/cert-manager | grep "rate limit"

# Monitor certificate renewal attempts
kubectl logs -n cert-manager deployment/cert-manager -f | grep "renewal"