Master HTTPS and TLS for production. Configure TLS 1.3, mutual TLS, certificate automation with cert-manager and Let's Encrypt, and HTTP security headers.
HTTPS and TLS Certificate Management
TLS 1.3 Nginx Configuration
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/ssl/certs/example.crt;
ssl_certificate_key /etc/ssl/private/example.key;
# TLS 1.2 and 1.3 only
ssl_protocols TLSv1.2 TLSv1.3;
# Strong cipher suites
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
# Session
ssl_session_cache shared:MozSSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# DH parameters for forward secrecy
ssl_dhparam /etc/nginx/dhparam.pem;
}
# Redirect HTTP to HTTPS
server {
listen 80;
return 301 https://$host$request_uri;
}
cert-manager on Kubernetes
# Install cert-manager
# kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
# ClusterIssuer - Let's Encrypt production
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-account-key
solvers:
- http01:
ingress:
class: nginx
# Ingress with TLS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp-service
port:
number: 80
Mutual TLS (mTLS)
import ssl
import httpx
def create_mtls_client(
cert_path: str,
key_path: str,
ca_cert_path: str,
) -> httpx.Client:
"""Create HTTP client with mutual TLS authentication."""
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.load_verify_locations(ca_cert_path)
ctx.load_cert_chain(cert_path, key_path)
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.check_hostname = True
ctx.minimum_version = ssl.TLSVersion.TLSv1_2
return httpx.Client(verify=ctx)
# Service-to-service mTLS
client = create_mtls_client(
cert_path="/certs/client.crt",
key_path="/certs/client.key",
ca_cert_path="/certs/ca.crt",
)
response = client.get("https://internal-service/api/data")
Istio mTLS (Service Mesh)
# Enable strict mTLS for namespace
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: production
spec:
mtls:
mode: STRICT # All service-to-service traffic must use mTLS
---
# Allow specific service to accept plaintext
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: allow-plaintext
namespace: production
spec:
selector:
matchLabels:
app: legacy-service
mtls:
mode: PERMISSIVE
Certificate Transparency Monitoring
import requests
from datetime import datetime
def monitor_cert_transparency(domain: str) -> list:
"""Check Certificate Transparency logs for issued certs."""
url = f"https://crt.sh/?q={domain}&output=json"
resp = requests.get(url, timeout=10)
certs = resp.json()
suspicious = []
for cert in certs:
issued_at = datetime.fromisoformat(cert["not_before"].replace("Z", "+00:00"))
# Flag recently issued certs
if (datetime.now().astimezone() - issued_at).days < 7:
suspicious.append({
"id": cert["id"],
"name": cert["name_value"],
"issuer": cert["issuer_name"],
"issued": cert["not_before"],
})
return suspicious
# Alert on unexpected certificates
certs = monitor_cert_transparency("example.com")
if certs:
print(f"Alert: {len(certs)} new certificates issued in last 7 days!")
TLS Best Practices
| Setting |
Value |
| Minimum TLS version |
TLS 1.2 |
| Preferred |
TLS 1.3 |
| Certificate type |
ECDSA P-256 |
| Key size (RSA) |
2048+ bits |
| Certificate validity |
90 days (Let's Encrypt) |
| HSTS max-age |
1 year minimum |