Skip to content

SSL Policies & TLS Termination — Kiểm Soát TLS Version và Cipher Suites

Tại sao SSL policy quan trọng trong production

TLS misconfiguration là một trong những lỗ hổng bảo mật phổ biến nhất. Hệ thống chấp nhận TLS 1.0 hay cipher suites yếu (RC4, 3DES) dễ bị tấn công POODLE, BEAST, hay SWEET32. Ngược lại, policy quá strict có thể break compatibility với old clients (mobile apps cũ, legacy browsers).

SSL Policy trong GCP LB cho phép enforce TLS version tối thiểu và cipher suite profile một cách tập trung — thay vì cấu hình trên từng backend riêng lẻ.

TLS Termination — Xảy ra ở đâu

GFE-based LB (Global External Application LB)

TLS được terminate tại Google Front End (GFE) — các proxy servers ở PoP của Google trên toàn thế giới. Điều này có nghĩa:

  • TLS session được establish giữa client và GFE, không phải client và backend
  • Certificate được served từ GFE
  • Kết nối từ GFE đến backend (Pod) thường là plain HTTP (hoặc HTTPS nếu explicit)
  • SSL Policy áp dụng cho phần client → GFE

Envoy-based LB (Regional/Internal Application LB)

TLS được terminate tại Envoy proxy instances trong proxy-only subnet của VPC bạn. SSL Policy áp dụng cho phần client → Envoy.

Backend encryption

Nếu cần end-to-end encryption (client → LB → backend là HTTPS), phải cấu hình Backend Service với HTTPS backend protocol. Backend (Pod) phải serve TLS. GKE không tự manage backend certificates.

SSL Policy — Cấu trúc

SSL Policy trong GCP gồm ba thành phần:

1. Minimum Protocol Version: TLS version tối thiểu chấp nhận.

  • TLS_1_0 — Accept TLS 1.0, 1.1, 1.2, 1.3 (không recommended)
  • TLS_1_1 — Accept TLS 1.1+
  • TLS_1_2 — Accept TLS 1.2+ (production standard)
  • TLS_1_3 — Chỉ TLS 1.3 (rất strict, có thể break nhiều clients)

2. Profile: Tập hợp cipher suites được phép.

3. Custom features (chỉ với CUSTOM profile): List cụ thể cipher suites.

Bốn Profiles

COMPATIBLE

Tương thích cao nhất. Cho phép tất cả cipher suites, TLS 1.0+. Phù hợp cho legacy clients nhưng kém bảo mật nhất.

Cipher suites bao gồm: RSA key exchange, ECDHE, các ciphers cũ như CHACHA20.

MODERN

Cho phép TLS 1.0+ nhưng loại bỏ nhiều cipher yếu. Cân bằng giữa compatibility và security.

Loại bỏ: RSA key exchange (không có forward secrecy), NULL ciphers, RC4. Giữ lại: ECDHE với AES-GCM, CHACHA20-POLY1305.

RESTRICTED

TLS 1.2+ và chỉ ECDHE cipher suites với AEAD. Phù hợp cho compliance requirements (PCI-DSS, FedRAMP).

Loại bỏ thêm: SHA-1 based cipher suites. Có thể break old clients không support ECDHE hay TLS 1.2.

CUSTOM

Bạn chỉ định exact list cipher suites:

bash
gcloud compute ssl-policies create custom-policy \
  --profile=CUSTOM \
  --min-tls-version=TLS_1_2 \
  --custom-features=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,\
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,\
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,\
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

CUSTOM cho phép fine-grained control nhưng phức tạp hơn. Cần test kỹ sau khi thay đổi.

Gắn SSL Policy vào Target Proxy

SSL Policy được gắn vào Target HTTPS Proxy (hoặc Target SSL Proxy), không phải Backend Service:

bash
# Tạo SSL policy
gcloud compute ssl-policies create production-ssl-policy \
  --profile=RESTRICTED \
  --min-tls-version=TLS_1_2

# Gắn vào target proxy
gcloud compute target-https-proxies update my-target-https-proxy \
  --ssl-policy=production-ssl-policy \
  --global

Với GKE Ingress, gắn qua FrontendConfig:

yaml
apiVersion: networking.gke.io/v1beta1
kind: FrontendConfig
metadata:
  name: frontend-config
spec:
  sslPolicy: "production-ssl-policy"

Với GKE Gateway:

yaml
apiVersion: networking.gke.io/v1
kind: GCPGatewayPolicy
metadata:
  name: gateway-ssl-policy
spec:
  targetRef:
    kind: Gateway
    name: external-gateway
  default:
    sslPolicy: "production-ssl-policy"

Certificate Management

Google-managed certificates

Google tự provision và renew certificates từ Let's Encrypt:

yaml
# Với GKE Ingress (legacy approach)
metadata:
  annotations:
    networking.gke.io/managed-certificates: "my-managed-cert"
---
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
  name: my-managed-cert
spec:
  domains:
    - app.example.com

Google-managed certs tự renew 30 ngày trước khi expire. Không cần manual intervention.

Cho production với nhiều certificates, Certificate Manager cung cấp quản lý tập trung:

bash
# Tạo Google-managed cert qua Certificate Manager
gcloud certificate-manager certificates create my-cert \
  --domains="app.example.com,api.example.com"

# Tạo Certificate Map
gcloud certificate-manager maps create my-cert-map

# Thêm cert vào map
gcloud certificate-manager maps entries create my-entry \
  --map=my-cert-map \
  --certificates=my-cert \
  --hostname="app.example.com"

Với Gateway API, reference Certificate Map qua annotation:

yaml
metadata:
  annotations:
    networking.gke.io/certmap: "my-cert-map"

Self-managed certificates (Kubernetes Secrets)

bash
kubectl create secret tls my-tls-secret \
  --cert=tls.crt \
  --key=tls.key

Self-managed không tự renew. Cần external tool (cert-manager với Let's Encrypt) để automation.

Testing SSL Policy

Sau khi áp SSL policy, verify bằng openssl:

bash
# Test TLS version và cipher
openssl s_client -connect app.example.com:443 -tls1_1
# Expected: ALERT handshake failure (nếu TLS_1_2 minimum)

openssl s_client -connect app.example.com:443 -tls1_2
# Expected: Successful handshake

# Xem cipher suite được chọn
openssl s_client -connect app.example.com:443 | grep "Cipher is"

Hoặc dùng SSL Labs (ssllabs.com/ssltest) cho comprehensive scan.

Failure modes

Old client bị block sau khi apply RESTRICTED profile

Triệu chứng: Một số clients (mobile apps cũ, IoT devices) bắt đầu fail kết nối sau khi update SSL policy.

Nguyên nhân: Old clients không support TLS 1.2 hay ECDHE cipher suites.

Fix:

  1. Identify clients bị ảnh hưởng (monitor SSL handshake failure logs)
  2. Upgrade clients nếu có thể
  3. Nếu không thể upgrade, cân nhắc dùng MODERN thay vì RESTRICTED

Certificate not provisioned (Google-managed)

Triệu chứng: HTTPS connections fail sau khi tạo ManagedCertificate. Certificate status là PROVISIONING.

Nguyên nhân: Google cần verify domain ownership qua DNS/HTTP challenge. IP phải được publish và DNS phải point đến IP trước khi provision.

Fix: Đảm bảo DNS record trỏ đến static IP của LB. Provision có thể mất 10-60 phút.

References