You need automated TLS certificates. Three dominant approaches exist:
- cert-manager — Kubernetes-native controller that works with any CA (Let’s Encrypt, Vault, private CA, cloud CA)
- AWS ACM (and equivalents: Azure App Service Managed Certs, GCP Managed Certificates) — cloud provider handles everything, zero configuration
- CDN/Edge managed (Cloudflare Universal SSL, CloudFront default cert) — the edge provider manages certificates for you
Each has different trade-offs in control, flexibility, portability, and operational overhead. Here’s how to choose.
The Three Models
cert-manager (Kubernetes-Native)
You control: CA selection, key algorithm, validity period, renewal timing, deployment target Provider controls: Nothing (you manage everything) Works with: Any Kubernetes cluster, any CA, any issuer
# You declare what you want
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: api-tls
spec:
secretName: api-tls-secret
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- api.example.com
privateKey:
algorithm: ECDSA
size: 256
# cert-manager handles: key generation, CSR, ACME challenge,
# certificate storage, renewal at 2/3 lifetime
AWS ACM (Cloud-Managed)
You control: Domain names, which services use the certificate Provider controls: Key generation, storage, renewal, deployment to AWS services Works with: ALB, CloudFront, API Gateway, Elastic Beanstalk (AWS services only)
# You request a certificate
aws acm request-certificate \
--domain-name api.example.com \
--validation-method DNS
# AWS handles: key generation (you never see the private key),
# validation, issuance, renewal (auto, 60 days before expiry),
# deployment to attached services
CDN/Edge Managed (Cloudflare, etc.)
You control: Almost nothing (domain points to CDN) Provider controls: Everything — certificate issuance, deployment, renewal Works with: Traffic flowing through the CDN/edge
# You point DNS to Cloudflare
# Cloudflare automatically:
# - Issues a certificate for your domain
# - Deploys it at their edge (200+ locations)
# - Renews before expiry
# - Handles all TLS termination
# Zero configuration. Zero management.
Detailed Comparison
| Feature | cert-manager | AWS ACM | Cloudflare/CDN |
|---|---|---|---|
| Setup complexity | Medium (install + configure issuers) | Low (request + validate) | None (automatic) |
| Ongoing management | Monitor cert-manager health | None | None |
| CA flexibility | Any CA (LE, Vault, PCA, self-signed) | AWS-issued only (or import) | Provider’s CA only |
| Key control | You generate and store the key | AWS generates, you never see it | Provider generates, you never see it |
| Key export | ✅ (it’s in a K8s Secret) | ❌ (non-exportable) | ❌ |
| Private CA support | ✅ (Vault, PCA, self-signed issuers) | ⚠️ (import only, no auto-renew) | ❌ |
| Wildcard support | ✅ (DNS-01 challenge) | ✅ | ✅ |
| Multi-cloud | ✅ (any K8s cluster) | ❌ (AWS only) | ⚠️ (only for CDN-fronted traffic) |
| Non-web use (mTLS, gRPC) | ✅ | ❌ (web services only) | ❌ |
| Cost | Free (open source) | Free (for AWS services) | Free (included with CDN) |
| Renewal | Automatic (2/3 lifetime) | Automatic (60 days before) | Automatic |
| Failure visibility | K8s events + metrics | CloudWatch (limited) | None (opaque) |
| Vendor lock-in | None | High (cert tied to AWS) | High (cert tied to CDN) |
Decision Framework
Where does your TLS terminate?
AWS Load Balancer (ALB/NLB/CloudFront):
└── AWS ACM (zero effort, auto-renew, free, native integration)
Cloudflare/CDN edge:
└── CDN managed certificate (automatic, zero config)
Kubernetes Ingress Controller:
└── cert-manager (native K8s integration, any CA)
Non-AWS cloud (GCP, Azure):
├── GCP: Google-managed certificates (for GCP LB)
├── Azure: App Service managed certs (for App Service)
└── General: cert-manager in GKE/AKS (most flexible)
On-premises / bare metal:
└── cert-manager (if K8s) or ACME client (certbot/acme.sh)
Internal services (mTLS):
└── cert-manager with private CA issuer (Vault, self-signed, PCA)
Multi-cloud / portable:
└── cert-manager (works identically across any K8s cluster)
When to Use Each
Use AWS ACM When:
- Your TLS terminates at an AWS service (ALB, CloudFront, API Gateway)
- You want zero operational overhead for public certificates
- You don’t need the private key (ACM certificates are non-exportable)
- You’re AWS-only (no multi-cloud requirement)
# Attach ACM cert to ALB — that's it. Auto-renews forever.
aws elbv2 modify-listener \
--listener-arn arn:aws:elasticloadbalancing:... \
--certificates CertificateArn=arn:aws:acm:us-east-1:123:certificate/abc
Limitation: If you need the certificate on a non-AWS system (Nginx on EC2, on-premises server), ACM can’t help — the private key is non-exportable. Use cert-manager or certbot instead.
Use cert-manager When:
- You run Kubernetes (any provider: EKS, GKE, AKS, on-prem)
- You need certificates for Ingress, Gateway API, or internal services
- You want to use multiple CAs (Let’s Encrypt for public, Vault for internal)
- You need mTLS certificates (not just server TLS)
- You want portability across clouds
- You need control over key algorithm, validity, and renewal timing
# Works identically on EKS, GKE, AKS, or bare-metal K8s
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
solvers:
- http01:
ingress:
class: nginx
Use CDN-Managed When:
- All your traffic flows through the CDN (Cloudflare, Fastly, CloudFront)
- You want absolute zero certificate management
- You don’t need certificates for non-CDN services
- You’re OK with the CDN provider controlling your TLS
Warning: CDN-managed certificates only protect the edge-to-client connection. You still need certificates for origin-to-CDN (configure “Full (Strict)” mode in Cloudflare, not “Flexible” which sends plaintext to origin).
The Hybrid Pattern (Most Common)
Most production environments use multiple approaches:
Public traffic → CDN (Cloudflare managed cert) → Origin (ACM on ALB or cert-manager on Ingress)
Internal APIs → cert-manager with Vault issuer (private CA, short-lived, mTLS)
AWS-native services → ACM (Lambda, API Gateway, CloudFront)
Non-K8s servers → certbot/acme.sh (ACME directly)
This isn’t over-engineering — it’s using the right tool for each layer.
Monitoring Across All Three
Regardless of which approach you use, monitor certificate expiry:
# Prometheus blackbox_exporter — monitors what's actually served
# Works for ALL approaches (ACM, cert-manager, CDN, anything)
- job_name: 'tls-certificates'
metrics_path: /probe
params:
module: [tcp_connect]
static_configs:
- targets:
- api.example.com:443 # ACM on ALB
- app.example.com:443 # cert-manager on Ingress
- www.example.com:443 # Cloudflare managed
- internal.example.com:443 # Vault-issued
# Alert if ANY certificate expires within 14 days
- alert: CertExpiringSoon
expr: (probe_ssl_earliest_cert_expiry - time()) / 86400 < 14
Even with “fully managed” certificates (ACM, Cloudflare), monitoring catches edge cases: misconfigured services, certificates that fell out of auto-renewal, or services accidentally using a different (expiring) certificate.
FAQ
Q: Can I use cert-manager with AWS ACM?
A: Not directly (ACM doesn’t expose an API for cert-manager to use). But you can use cert-manager with AWS Private CA (via the aws-privateca-issuer plugin) for internal certificates. For public certificates on AWS services, use ACM directly.
Q: What if I need the same certificate on both AWS ALB and a Kubernetes Ingress? A: You can’t export ACM certificates. Options: 1) Use cert-manager for both (store cert in K8s Secret, also deploy to ALB via automation). 2) Use separate certificates (one from ACM for ALB, one from cert-manager for Ingress — same domain, different certs, both valid).
Q: Is cert-manager production-ready? A: Yes. cert-manager is a CNCF graduated project, used in production by thousands of organizations. It manages millions of certificates globally. It’s the de facto standard for Kubernetes certificate management.
Q: What about Caddy (built-in ACME)? A: Caddy has ACME built into the web server itself — no external tool needed. Point Caddy at a domain, it automatically gets and renews certificates. Great for simple deployments. For Kubernetes or complex environments, cert-manager is more appropriate.
Q: Which is most reliable for auto-renewal? A: AWS ACM (managed by AWS, extremely reliable). cert-manager (reliable if properly configured and monitored — but YOU must ensure cert-manager pods are healthy). CDN-managed (reliable but opaque — you can’t see if renewal is failing until it fails).