TLS
Transport Layer Security (TLS) in Kubernetes Ingress provides encrypted communication between clients and your Services. Ingress Controllers handle TLS termination—they receive encrypted HTTPS traffic, decrypt it, and forward it as HTTP to backend Services. This allows you to secure external traffic while keeping internal communication simple.
What is TLS Termination?
TLS termination means the Ingress Controller handles SSL/TLS encryption/decryption. The flow works like this:
- Client sends HTTPS request (encrypted)
- Ingress Controller receives and decrypts the request
- Ingress Controller forwards HTTP request (unencrypted) to backend Service
- Backend Service processes the request
TLS Configuration in Ingress
Configure TLS in Ingress resources using the tls section:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com
- www.example.com
secretName: example-tls
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
Key components:
hosts- Hostnames that should use TLSsecretName- Kubernetes Secret containing certificate and key
Creating TLS Secrets
TLS certificates are stored in Kubernetes Secrets:
Using kubectl
kubectl create secret tls example-tls \
--cert=path/to/cert.crt \
--key=path/to/key.key
Using YAML
apiVersion: v1
kind: Secret
metadata:
name: example-tls
namespace: default
type: kubernetes.io/tls
data:
tls.crt: <base64-encoded-certificate>
tls.key: <base64-encoded-key>
Note: The secret type must be kubernetes.io/tls, and the keys must be named tls.crt and tls.key.
TLS Secret Structure
A TLS secret contains:
apiVersion: v1
kind: Secret
metadata:
name: example-tls
type: kubernetes.io/tls
data:
tls.crt: LS0tLS1CRUdJTi... # Base64-encoded certificate
tls.key: LS0tLS1CRUdJTi... # Base64-encoded private key
Fields:
tls.crt- Certificate (PEM encoded, base64)tls.key- Private key (PEM encoded, base64)
Multiple TLS Hosts
You can configure multiple TLS hosts in one Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-tls-ingress
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: api-tls
- hosts:
- www.example.com
secretName: www-tls
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- host: www.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
Each host can use a different certificate.
Wildcard Certificates
Use wildcard certificates for multiple subdomains:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wildcard-ingress
spec:
ingressClassName: nginx
tls:
- hosts:
- "*.example.com"
- example.com
secretName: wildcard-tls
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- host: www.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
Note: Wildcard certificates cover subdomains but not the root domain unless explicitly included.
Automatic Certificate Management
Use cert-manager for automatic certificate provisioning and renewal:
Installing cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
Using cert-manager with Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: auto-tls-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com
secretName: example-tls # cert-manager creates this
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
cert-manager will:
- Create the TLS secret automatically
- Obtain certificate from Let’s Encrypt
- Renew certificate before expiration
HTTP to HTTPS Redirect
Most Ingress Controllers support automatic HTTP to HTTPS redirect:
NGINX Ingress Controller
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: redirect-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com
secretName: example-tls
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
Annotations:
ssl-redirect: "true"- Redirects HTTP to HTTPS (if TLS is configured)force-ssl-redirect: "true"- Always redirects, even without TLS config
TLS Versions and Ciphers
Configure TLS versions and cipher suites via controller annotations:
NGINX Ingress Controller
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: secure-tls-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-protocols: "TLSv1.2 TLSv1.3"
nginx.ingress.kubernetes.io/ssl-ciphers: "ECDHE-RSA-AES128-GCM-SHA256,ECDHE-RSA-AES256-GCM-SHA384"
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com
secretName: example-tls
rules:
# ...
Best practices:
- Use TLS 1.2 or higher
- Disable weak ciphers
- Prefer ECDHE ciphers for forward secrecy
Certificate Chain
For proper TLS validation, include the full certificate chain:
# Combine certificate and chain
cat server.crt intermediate.crt root.crt > fullchain.crt
# Create secret with full chain
kubectl create secret tls example-tls \
--cert=fullchain.crt \
--key=server.key
The certificate file should contain:
- Server certificate
- Intermediate certificate(s)
- Root certificate (optional, usually not needed)
Best Practices
- Use cert-manager - Automate certificate provisioning and renewal
- Use Let’s Encrypt - Free, automated certificates for public domains
- Enable HTTPS redirect - Always redirect HTTP to HTTPS
- Use strong TLS versions - TLS 1.2 or higher
- Rotate certificates - Regularly rotate certificates
- Monitor expiration - Set up alerts for certificate expiration
- Use wildcards wisely - Wildcard certs simplify multi-subdomain setups
- Store secrets securely - Use Kubernetes Secrets with proper RBAC
- Test TLS configuration - Verify certificates work correctly
- Document certificate sources - Keep track of where certificates come from
Troubleshooting
TLS Not Working
- Check secret exists:
kubectl get secret <secret-name> - Verify secret type: Should be
kubernetes.io/tls - Check secret data:
kubectl get secret <secret-name> -o yaml - Verify certificate format: Should be PEM encoded
- Test certificate:
openssl x509 -in cert.crt -text -noout
Certificate Errors
- Check expiration:
kubectl get secret <secret-name> -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -dates - Verify hostname match: Certificate must match Ingress hostname
- Check certificate chain: Ensure full chain is included
- Verify private key: Ensure key matches certificate
- Test with openssl:
openssl s_client -connect <host>:443 -servername <host>
cert-manager Issues
- Check cert-manager pods:
kubectl get pods -n cert-manager - Review certificate status:
kubectl describe certificate <cert-name> - Check ClusterIssuer:
kubectl get clusterissuer - Review events:
kubectl get events -n cert-manager - Check logs:
kubectl logs -n cert-manager <cert-manager-pod>
HTTPS Redirect Not Working
- Check annotations: Verify redirect annotations are set
- Verify controller support: Ensure controller supports redirect
- Test HTTP access:
curl -I http://example.com - Check controller logs: Review for redirect configuration
- Verify TLS config: Ensure TLS is properly configured
See Also
- Ingress Overview - Introduction to Ingress
- Ingress Resources - Configuring Ingress resources
- Ingress Controllers - Controller selection and configuration
- Secrets - Managing Kubernetes Secrets