Cấu hình mTLS và Lua Script trong Istio EnvoyFilter: Quy trình và Thứ Tự Thực Thi

KiloKilo
7 min read

Giới thiệu

Trong hệ thống microservices, việc cấu hình kết nối bảo mật với mTLS và theo dõi các request/response thông qua Lua scripting là một yêu cầu phổ biến, đặc biệt khi sử dụng Istio. Envoy, proxy của Istio, cung cấp sự linh hoạt này thông qua việc sử dụng EnvoyFilter.

Bài viết này sẽ hướng dẫn bạn cách kết hợp hai tính năng chính trong một EnvoyFilter:

  1. Thiết lập kết nối mTLS với một dịch vụ bên ngoài Kubernetes thông qua applyTo: CLUSTER.

  2. Sử dụng Lua script để in ra body của response từ dịch vụ đó với applyTo: HTTP_FILTER.

Quy trình hoạt động của EnvoyFilter

Khi triển khai EnvoyFilter, các phần cấu hình với applyTo: CLUSTERapplyTo: HTTP_FILTER được xử lý vào những thời điểm khác nhau trong quá trình kết nối và truyền tải dữ liệu. Quy trình tổng quan diễn ra như sau:

  1. Thiết lập kết nối (applyTo: CLUSTER):

    • Envoy xác định cluster (đại diện cho backend service) và thực hiện kết nối TCP, bao gồm cả mTLS nếu được cấu hình.
  2. Xử lý HTTP request/response (applyTo: HTTP_FILTER):

    • Sau khi kết nối đã được thiết lập, Envoy bắt đầu xử lý các HTTP request và response bằng cách áp dụng các HTTP filter (bao gồm Lua script).

Thứ tự applyTo: CLUSTERapplyTo: HTTP_FILTER

Nhiều người mới bắt đầu thường thắc mắc rằng liệu thứ tự các phần cấu hình applyTo trong file EnvoyFilter có ảnh hưởng đến thứ tự thực thi của chúng không. Câu trả lời là không. Envoy xử lý các bước theo quy trình logic của nó, không phải theo thứ tự bạn sắp xếp trong file.

  • applyTo: CLUSTER sẽ luôn được xử lý trước vì nó liên quan đến việc thiết lập kết nối TCP và bảo mật (mTLS). Điều này phải diễn ra trước khi Envoy có thể truyền tải dữ liệu.

  • applyTo: HTTP_FILTER sẽ được thực thi sau khi kết nối đã được thiết lập và Envoy bắt đầu xử lý request/response ở tầng HTTP.

Cấu hình mTLS và Lua Script trong EnvoyFilter

Dưới đây là một ví dụ cụ thể về cách kết hợp cả mTLS và Lua script trong một EnvoyFilter. Trong ví dụ này, chúng ta sẽ thiết lập mTLS với một API bên ngoài, sau đó sử dụng Lua script để in ra toàn bộ body của response.

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: external-api-mtls-lua
spec:
  workloadSelector:
    labels:
      app: my-app  # Lựa chọn workload mà bạn muốn áp dụng filter
  configPatches:
  # Cấu hình mTLS (applyTo: CLUSTER)
  - applyTo: CLUSTER
    match:
      cluster:
        service: external-api.example.com  # Tên miền hoặc host của ServiceEntry
        portNumber: 443
    patch:
      operation: MERGE
      value:
        transport_socket:
          name: envoy.transport_sockets.tls
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
            common_tls_context:
              tls_certificates:
                certificate_chain:
                  filename: /etc/certs/client.crt  # Đường dẫn tới chứng chỉ client
                private_key:
                  filename: /etc/certs/client.key  # Đường dẫn tới private key
              validation_context:
                trusted_ca:
                  filename: /etc/certs/ca.crt  # Đường dẫn tới CA
                match_subject_alt_names:
                - exact: external-api.example.com  # Kiểm tra SAN (Subject Alternative Name)

  # Cấu hình Lua HTTP filter (applyTo: HTTP_FILTER)
  - applyTo: HTTP_FILTER
    match:
      context: SIDECAR_OUTBOUND  # Áp dụng cho các request outbound đi từ sidecar
      listener:
        portNumber: 443          # Port của API bên ngoài
        filterChain:
          filter:
            name: envoy.filters.network.http_connection_manager
    patch:
      operation: INSERT_BEFORE
      value:
        name: envoy.filters.http.lua
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
          inlineCode: |
            function envoy_on_response(response_handle)
              -- Lấy toàn bộ body của response
              local body = response_handle:body():getBytes(0, response_handle:body():length())
              -- In ra toàn bộ body của response
              response_handle:logInfo("Lua Script - Body content: " .. body)
            end

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

  1. mTLS với applyTo: CLUSTER:

    • Phần này thiết lập kết nối mTLS với API bên ngoài (external-api.example.com).

    • Sử dụng các chứng chỉ được mount vào pod để thực hiện xác thực mTLS.

    • Chúng ta sử dụng operation: MERGE để thêm các cấu hình mTLS vào cluster hiện có mà không cần thay thế toàn bộ cấu hình cluster. Điều này giúp giữ lại các cấu hình mặc định khác của Envoy (như load balancing, timeout).

  2. Lua Script với applyTo: HTTP_FILTER:

    • Lua filter được thêm vào pipeline xử lý HTTP request/response bằng operation: INSERT_BEFORE, chèn Lua script vào trước các filter đã có.

    • Lua script in ra toàn bộ body của response từ API sau khi nhận được phản hồi từ backend service.

Tại sao MERGEINSERT_BEFORE?

  • MERGE: Khi bạn cần bổ sung hoặc thay đổi một phần cấu hình đã có, nhưng vẫn muốn giữ lại các thiết lập khác (như load balancing hoặc các thông số mặc định khác của Envoy), MERGE sẽ giúp bạn chỉ thêm hoặc chỉnh sửa một phần mà không thay đổi toàn bộ cấu hình.

  • INSERT_BEFORE: Được sử dụng khi bạn muốn chèn một filter mới (ở đây là Lua filter) vào trước một filter khác trong chuỗi xử lý HTTP. Thứ tự của các filter quan trọng vì nó quyết định cách mà request và response sẽ được xử lý.

Thứ tự thực thi của EnvoyFilter

Như đã đề cập, thứ tự tổ chức code trong EnvoyFilter không ảnh hưởng đến thứ tự thực thi. Envoy xử lý dựa trên quy trình kết nối và truyền tải dữ liệu:

  • Trước tiên, Envoy sẽ thiết lập kết nối TCP với backend service (bao gồm mTLS nếu có) theo cấu hình applyTo: CLUSTER.

  • Sau khi kết nối được thiết lập, các HTTP filters sẽ xử lý các request/response ở tầng ứng dụng, bao gồm Lua script từ applyTo: HTTP_FILTER.

Dưới đây là mô hình luồng đi của gói tin khi nó đi qua các FILTER trong Envoy khi sử dụng applyTo: CLUSTERapplyTo: HTTP_FILTER

+-------------------------------+
|   Client (Application)         |
+-------------------------------+
                |
                v
+-----------------------------------------------+
| Envoy Sidecar Proxy                            |
|                                               |
| +-------------------------------------------+ |
| |    **Outbound Filter Chain**              | |
| |                                           | |
| | 1. **HTTP_FILTER**                        | |
| |    - Lua Script (Logging HTTP Body)       | |
| +-------------------------------------------+ |
|                                               |
|     (HTTP Request flows down to Cluster)      |
|                                               |
| +-------------------------------------------+ |
| |    **Cluster (Backend Selection)**        | |
| |                                           | |
| | 2. **CLUSTER**                            | |
| |    - mTLS Connection Setup                | |
| |    - Route to external backend service    | |
| +-------------------------------------------+ |
|                                               |
+-----------------------------------------------+
                |
                v
+-------------------------------+
|   Backend Service (External)   |
|   - Receives HTTP request      |
|   - Sends HTTP response        |
+-------------------------------+
                ^
                |
+-----------------------------------------------+
| Envoy Sidecar Proxy                            |
|                                               |
| +-------------------------------------------+ |
| |    **Inbound Filter Chain**               | |
| |                                           | |
| | 1. **HTTP_FILTER**                        | |
| |    - Lua Script (Logging HTTP Response)   | |
| +-------------------------------------------+ |
|                                               |
|     (HTTP Response flows up from Cluster)     |
|                                               |
| +-------------------------------------------+ |
| |    **Cluster (Backend Selection)**        | |
| |                                           | |
| | 2. **CLUSTER**                            | |
| |    - TLS Termination (Decryption of Data) | |
| +-------------------------------------------+ |
|                                               |
+-----------------------------------------------+
                |
                v
+-------------------------------+
|   Client (Application)         |
+-------------------------------+

Giải thích mô hình:

  1. Gói tin từ Client (Application):

    • Gói tin HTTP được tạo từ ứng dụng và được gửi đi qua Envoy Sidecar Proxy.
  2. Gói tin đi qua HTTP_FILTER (Outbound):

    • Trước khi rời khỏi Envoy, gói tin HTTP sẽ đi qua các HTTP filter đã được cấu hình. Ở đây, Lua script sẽ không in log gì vì đó là request outbound (ta chỉ in log response).
  3. Gói tin đi qua CLUSTER:

    • Sau khi qua HTTP_FILTER, gói tin sẽ đến tầng CLUSTER. Ở đây, Envoy sẽ xác định backend cluster (ở đây là dịch vụ bên ngoài) và thiết lập kết nối mTLS.

    • Kết nối mTLS được thiết lập, và gói tin HTTP được truyền đi tới dịch vụ bên ngoài thông qua kết nối đã mã hóa.

  4. Backend Service nhận gói tin:

    • Dịch vụ backend (API bên ngoài) nhận được gói tin, xử lý request và trả về response.
  5. Gói tin quay lại qua CLUSTER (Inbound):

    • Khi response từ backend được trả về, gói tin đi qua tầng CLUSTER của Envoy. Kết nối mTLS được giải mã để xử lý response ở tầng HTTP.
  6. Gói tin quay lại qua HTTP_FILTER (Inbound):

    • Sau khi được giải mã tại tầng CLUSTER, gói tin HTTP response sẽ đi qua HTTP_FILTER. Ở đây, Lua script sẽ được kích hoạt để in ra toàn bộ nội dung của response body.
  7. Gói tin trở lại Client (Application):

    • Sau khi xử lý qua các filter, gói tin HTTP response sẽ được trả về ứng dụng (client).
0
Subscribe to my newsletter

Read articles from Kilo directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Kilo
Kilo