Amazon EKS — TLS and ACM Integration
AWS Certificate Manager (ACM) provides free, auto-renewing TLS certificates. On EKS, you terminate TLS at the load balancer (ALB or NLB) using ACM certificates.
Provision an ACM Certificate
aws acm request-certificate \
--domain-name "*.example.com" \
--subject-alternative-names "example.com" \
--validation-method DNS \
--region us-east-1
Validate the certificate via DNS (add the CNAME record to Route 53):
aws acm describe-certificate --certificate-arn arn:aws:acm:us-east-1:123456789:certificate/abc-123 \
--query "Certificate.DomainValidationOptions[0].ResourceRecord"
TLS on ALB (Ingress)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: secure-ingress
namespace: production
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:us-east-1:123456789:certificate/abc-123"
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
alb.ingress.kubernetes.io/ssl-policy: "ELBSecurityPolicy-TLS13-1-2-2021-06"
alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type":"redirect","RedirectConfig":{"Protocol":"HTTPS","Port":"443","StatusCode":"HTTP_301"}}'
spec:
ingressClassName: alb
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-app
port:
number: 80
HTTP to HTTPS Redirect
Add both HTTP and HTTPS listeners, then redirect HTTP:
annotations:
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80},{"HTTPS":443}]'
alb.ingress.kubernetes.io/ssl-redirect: "443"
alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:us-east-1:123456789:certificate/abc-123"
TLS on NLB (Service)
apiVersion: v1
kind: Service
metadata:
name: secure-api
namespace: production
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "external"
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:us-east-1:123456789:certificate/abc-123"
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: "ELBSecurityPolicy-TLS13-1-2-2021-06"
spec:
type: LoadBalancer
selector:
app: api
ports:
- name: https
port: 443
targetPort: 8080
protocol: TCP
SSL Policies
| Policy | TLS Versions | Use Case |
|---|---|---|
ELBSecurityPolicy-TLS13-1-2-2021-06 |
TLS 1.2 + 1.3 | Modern browsers |
ELBSecurityPolicy-TLS-1-2-2017-01 |
TLS 1.2 only | PCI compliance |
ELBSecurityPolicy-TLS13-1-3-2021-06 |
TLS 1.3 only | Maximum security |
ELBSecurityPolicy-2016-08 |
TLS 1.0+ | Legacy clients (not recommended) |
End-to-End Encryption
For compliance requirements, encrypt traffic all the way to the pod:
Client → HTTPS → ALB → HTTPS → Pod
annotations:
alb.ingress.kubernetes.io/backend-protocol: "HTTPS"
alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:..."
Your pods must serve HTTPS on their target port. Use cert-manager or mounted certificates.
cert-manager as Alternative
For certificates inside the cluster (pod-level TLS):
helm repo add jetstack https://charts.jetstack.io
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager --create-namespace \
--set crds.enabled=true
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:
route53:
region: us-east-1
Recommendation: Use ACM for load balancer TLS (free, auto-renewing). Use cert-manager only when you need pod-level certificates (mTLS, service mesh).
Best Practices
- Use ACM for ALB/NLB TLS — free, automatic renewal, no manual certificate management
- Enforce HTTPS with HTTP→HTTPS redirect
- Use TLS 1.2+ policies — disable older protocols
- Use wildcard certificates for multi-service domains
- End-to-end encryption only when compliance requires it — adds complexity and CPU overhead