0

3 cách xử lý SSL/TLS traffic tại Loadbalancer hoặc Reverse Proxy

Trong quá trình triển khai hệ thống, đặc biệt là khi làm việc với Load Balancer hay Reverse Proxy như Nginx, việc xử lý traffic TLS/SSL (HTTPS) luôn là một bài toán khiến nhiều anh em đau đầu. Chúng ta nên giải mã (decrypt) ngay tại Proxy để giảm tải cho backend, hay cứ để traffic đi thẳng đến backend cho an toàn tuyệt đối?

Hôm nay, mình sẽ cùng các bạn "mổ xẻ" 3 phương pháp phổ biến nhất: TLS Termination, TLS Passthrough và TLS Re-encrypt. Chúng ta sẽ xem cách chúng hoạt động, cấu hình Nginx thực tế và khi nào thì nên dùng phương pháp nào nhé.

1. TLS Termination (SSL Offloading)

Đây là phương pháp phổ biến nhất mà mình thấy hay được sử dụng trong thực tế. Tại đây, Load Balancer/Proxy sẽ đóng vai trò là điểm kết thúc của kết nối SSL. Nó nhận traffic HTTPS từ client, giải mã, sau đó gửi traffic dưới dạng HTTP (không mã hóa) tới backend qua mạng nội bộ.

Sơ đồ hoạt động

Client (HTTPS) ----> [ Proxy (SSL Cert) ] ----> Backend (HTTP)
      (Mã hóa)           (Giải mã)            (Không mã hóa)

Ví dụ cấu hình TLS Termination (SSL Offloading) cho Nginx:

http {
    upstream my_app {
        server 10.0.0.10:80; # Backend chạy HTTP
    }

    server {
        listen 443 ssl;
        server_name example.com;

        # 1. Cấu hình Certificate
        ssl_certificate /etc/nginx/certs/fullchain.pem;
        ssl_certificate_key /etc/nginx/certs/privkey.pem;

        location / {
            # 2. Forward tới backend bằng HTTP
            proxy_pass http://my_app;
            
            # 3. Truyền thông tin protocol gốc cho backend
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

Giải thích cấu hình:

  • listen 443 ssl: Nginx lắng nghe cổng 443 và sẵn sàng thực hiện bắt tay (handshake) SSL với client.
  • ssl_certificate: Đường dẫn đến chứng chỉ SSL. Mọi quá trình mã hóa/giải mã diễn ra tại đây.
  • proxy_pass http://my_app: Lưu ý là http. Traffic sau khi giải mã sẽ được đẩy đi dưới dạng plain text.
  • X-Forwarded-Proto $scheme: Cực kỳ quan trọng để backend biết client gốc dùng https, tránh việc backend tự ý redirect vòng lặp về lại http.

Đánh giá

Ưu điểm:

  • Giảm tải CPU cho backend (không tốn tài nguyên giải mã)
  • Quản lý chứng chỉ tập trung tại 1 nơi
  • Proxy có thể đọc/ghi đè Header (Cookie, Caching, WAF).

Nhược điểm:

  • Traffic trong mạng nội bộ không được mã hóa. Nếu kẻ tấn công xâm nhập được LAN, họ có thể "sniff" dữ liệu.

Use Case thực tế:

  • Hầu hết các ứng dụng Web thông thường nằm trong mạng nội bộ an toàn (VPC).
  • Những ứng dụng ưu tiên hiệu năng cũng thường sử dụng phương pháp này.

2. TLS Passthrough

Phương pháp này coi Proxy như một "đường ống" thuần túy. Nginx sẽ không can thiệp, không giải mã dữ liệu mà chỉ chuyển tiếp nguyên văn các gói tin đã mã hóa từ client xuống thẳng backend. Theo mô hình OSI, bạn hiểu đơn giản package khi được gửi đến thì chỉ bóc tách đến layer 4 (TCP) rồi được xử lý tiếp chứ không cần bóc đến Layer 7 (HTTP).

Sơ đồ hoạt động

Client (HTTPS) ----> [ Proxy (L4) ] ----> Backend (SSL Cert)
      (Mã hóa)        (Chuyển tiếp)          (Giải mã tại đây)

Để dùng Passthrough, chúng ta phải dùng module stream (Layer 4) thay vì module http (Layer 7). Sau đây là cấu hình nginx mẫu:

stream {
    upstream backend_ssl {
        server 10.0.0.10:443; # Backend tự cầm Cert và chạy HTTPS
    }

    server {
        listen 443;
        proxy_pass backend_ssl;
        # Không cấu hình ssl_certificate ở đây vì Nginx không giải mã
    }
}

Giải thích cấu hình:

  • stream { ... }: Chạy ở tầng TCP (Layer 4). Nginx chỉ nhìn thấy IP và Port, không nhìn thấy URL hay Header.
  • proxy_pass backend_ssl: Các gói tin TCP được forward nguyên trạng.

Lưu ý: Bạn không thể dùng các tính năng như proxy_set_header hay server_name (dựa trên tên miền) trong block này vì Nginx không đọc được nội dung gói tin.

Đánh giá

Ưu điểm:

  • Bảo mật tối đa (End-to-End Encryption),
  • Proxy không biết gì về dữ liệu khách hàng.

Nhược điểm:

  • Backend sẽ phải tốn tài nguyên CPU để xử lý giải mã thay vì ở proxy.
  • Proxy không thể thực hiện các tính năng Layer 7 (như Routing theo URL, chèn Header)
  • Không thể lấy, xử lý được log liên quan đến Layer 7 (HTTP)

Use Case:

  • Các ứng dụng yêu cầu chứng chỉ client (mTLS) hoặc các dịch vụ tài chính, ngân hàng cực kỳ nhạy cảm.
  • Các database có certificate riêng. Mình rất hay áp dụng cách này cho các Database nằm trên Cloud mà sử dụng domain để kết nối.

3. TLS Re-encryption

Đây là "best of both worlds". Proxy nhận traffic HTTPS (mã hóa lần 1), giải mã để xử lý (WAF, Header, Routing), sau đó lại mã hóa lần 2 bằng một chứng chỉ khác trước khi gửi tới backend.

Sơ đồ hoạt động

Client (HTTPS) ----> [ Proxy (Decrypt & Encrypt) ] ----> Backend (HTTPS)
  (Mã hóa lần 1)       (Giải mã và Mã hóa lần 2)       (Giải mã lần cuối)

Cấu hình Nginx

http {
    upstream secure_backend {
        server 10.0.0.10:443; # Backend cũng chạy HTTPS
    }

    server {
        listen 443 ssl;
        ssl_certificate /etc/nginx/certs/public.pem;
        ssl_certificate_key /etc/nginx/certs/public.key;

        location / {
            # 1. Forward tới backend bằng HTTPS
            proxy_pass https://secure_backend;

            # 2. Cấu hình kiểm tra chứng chỉ của backend
            proxy_ssl_verify on;
            proxy_ssl_trusted_certificate /etc/nginx/certs/backend_ca.crt;
            proxy_ssl_server_name on; # Hỗ trợ SNI cho backend
        }
    }
}

Giải thích cấu hình:

  • listen 443 ssl: Giải mã kết nối từ Client.
  • proxy_pass https://...: Điểm khác biệt là https. Nginx đóng vai trò là một "client" tạo kết nối mã hóa mới tới backend.
  • proxy_ssl_verify on: Đảm bảo Nginx kiểm tra tính hợp lệ của chứng chỉ phía backend, tránh tấn công Man-in-the-middle ngay trong mạng nội bộ.
  • proxy_ssl_trusted_certificate /etc/nginx/certs/backend_ca.crt: Yêu cầu proxy tin tưởng certificate của backend. Certficate này có thể là public hoặc internal certificates.
  • proxy_ssl_server_name on: Gửi SNI (Server Name Indication) để backend biết đang phục vụ cho domain nào.

Đánh giá

Ưu điểm:

  • Bảo mật toàn diện trên mọi chặng đường packge đi qua
  • Giữ được khả năng can thiệp Layer 7 của Proxy.

Nhược điểm:

  • Tốn tài nguyên CPU nhất (mã hóa/giải mã 2 lần)
  • Thời gian xử lý request (latency) sẽ cao hơn đáng kể
  • Cấu hình và quản lý certificate ở cả 2 đầu rất phức tạp.

Use Case:

  • Các hệ thống tuân thủ tiêu chuẩn PCI-DSS, HIPAA hoặc các hệ thống Zero-trust.
  • Hệ thống yêu cầu khả năng mã hóa end-to-end mà vẫn có thể extract được dữ liệu ở các layer giữa.

Chốt lại

Tiêu chí TLS Termination TLS Passthrough TLS Re-encryption
Vị trí giải mã Tại Proxy Tại Backend Cả Proxy và Backend
Mức độ bảo mật Trung bình (Package trong nội bộ không được mã hóa) Rất cao (End-to-End) Cao
Hiệu năng (CPU) Tốn tài nguyên xử lý tại proxy Tốn tài nguyên xử lý tại Backend Tốn tài nguyên xử lý tại cả Proxy và Backend
Khả năng can thiệp Layer 7 Không
Quản lý Cert Tập trung tại Proxy Phân tán tại Backend Phức tạp (quản lý cả 2)
Độ khó cấu hình Bình thường Dễ Phức tạp

Kết luận

Lựa chọn phương pháp nào phụ thuộc hoàn toàn vào yêu cầu bảo mật và kiến trúc hạ tầng của bạn. Nếu bạn ưu tiên sự đơn giản và tốc độ, Termination là số 1. Nếu cần bảo mật tuyệt đối, hãy cân nhắc Passthrough. Còn nếu cần cả sự linh hoạt lẫn bảo mật trong mạng LAN, hãy chọn Re-encryption.

Hy vọng bài viết này giúp anh em có cái nhìn rõ nét hơn về cách xử lý traffic TLS. Nếu có thắc mắc gì, đừng ngần ngại để lại comment bên dưới nhé! Chúc anh em xây dựng hệ thống mượt mà!

Nếu như bạn đang gặp khó khăn trong vấn đề chuyên môn, cần người hỗ trợ về mặt hệ thống, DevOps tools hay cần định hướng trong công việc thì mình tự tin có thể hỗ trợ được bạn. Liên hệ với mình để trao đổi thêm nhé https://hoangviet.io.vn/, mình rất vui khi được trao đổi và cộng tác với bạn.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí