在網址對應中建立自訂標頭

本頁說明自訂標頭在區域外部應用程式負載平衡器、區域內部應用程式負載平衡器和跨區域內部應用程式負載平衡器使用的網址對應中的作用方式。

您可以使用自訂要求和回應標頭,指定負載平衡器可新增至 HTTP(S) 要求和回應的其他標頭。視負載平衡器偵測到的資訊而定,這些標頭可能包含下列資訊:

  • 用戶端的延遲時間
  • 用戶端 IP 位址的地理位置
  • TLS 連線的參數

事前準備

視需要更新至最新版 Google Cloud CLI:

gcloud components update

自訂標頭的運作方式

自訂標頭的運作方式如下:

  • 負載平衡器向後端提出要求時,會新增要求標頭。

    負載平衡器只會將自訂要求標頭新增至用戶端要求,而不會新增至健康狀態檢查探測。如果後端需要特定的授權標頭,而健康狀態檢查封包中缺少該標頭,則健康狀態檢查可能會失敗。

  • 負載平衡器會在將回應傳回用戶端前設定回應標頭。

如要為區域性外部應用程式負載平衡器、區域內部應用程式負載平衡器和跨區域內部應用程式負載平衡器啟用自訂標頭,請在網址對應設定檔案中指定標頭名稱和標頭值清單。

標頭名稱必須具備下列屬性:

  • 根據 RFC 7230 的規定,標頭名稱必須是有效的 HTTP 標頭欄位名稱定義。
  • 標頭名稱不得為 X-User-IP
  • 標頭名稱的開頭不得為 X-GoogleX-Goog-X-GFEX-Amz-
  • 請勿使用下列逐跳式標頭:Keep-AliveTransfer-EncodingTEConnectionTrailerUpgrade。根據 RFC 2616 規定,這些標頭不會儲存在快取中,也不會由目標 Proxy 傳播。
  • 標頭名稱不得為 HostauthorityHostauthority 都是 Google Cloud保留的特殊關鍵字。您無法修改這些以 Envoy 為基礎的負載平衡器標頭。建議您改為建立其他自訂標頭 (例如 MyHost),以免干擾預留的標頭名稱。
  • 標頭名稱在標頭清單中不可出現超過一次。

標頭名稱不區分大小寫。標頭名稱傳送至 HTTP/2 後端時,HTTP/2 通訊協定會將標頭名稱轉換成小寫編碼。

標頭值必須具備下列屬性:

  • 標頭值必須是有效的 HTTP 標頭欄位定義 (根據 RFC 7230 的規定,您將無法使用已過時的表單)。
  • 標頭值不得空白。空白標頭會遭到拒絕。
  • 標頭值可以包含一個或多個變數 (由大括號括住),以囊括負載平衡器提供的值。如需標題值中允許包含的變數完整清單,請參閱「可以出現在標題值中的變數」。

標頭值中的前置空格及後置空格無關緊要,系統並不會將其傳送至後端。為了能在標頭值中使用大括號,負載平衡器會將雙左大括號 ({{) 解譯成單左括號 ({),並將雙右大括號 (}}) 解譯成單右括號 (})。

新增要求或回應標頭

如要新增要求或回應標頭,請使用 gcloud CLI 編輯網址對應,如下所示:

區域

    gcloud compute url-maps edit URL_MAP_NAME \
        --region=REGION
    

以下是 YAML 檔案範例,說明如何在自訂標頭中使用變數:

   defaultService: regions/REGION/backendServices/BACKEND_SERVICE_1
   name: regional-lb-map
   region: region/REGION
   hostRules:
   - hosts:
     - '*'
     pathMatcher: matcher1
   pathMatchers:
   - defaultService: regions/REGION/backendServices/BACKEND_SERVICE_1
     name: matcher1
     routeRules:
       - matchRules:
           - prefixMatch: /PREFIX
         priority: PRIORITY # 0 is highest
         routeAction:
           weightedBackendServices:
             - backendService: regions/REGION/backendServices/BACKEND_SERVICE_1
               weight: 100
               headerAction:
                 requestHeadersToAdd:
                 - headerName: X-header-1-client-region
                   headerValue: "{client_region}"
                 - headerName: X-header-2-client-ip-port
                   headerValue: "{client_ip_address}, {client_port}"
                   replace: True
                 requesteHeadersToRemove:
                 - header-3-name
                 responseHeadersToAdd:
                 - headerName: X-header-4-server-ip-port
                   headerValue: "{server_ip_address}, {server_port}"
                   replace: True
                 responseHeadersToRemove:
                 - header-5-name
                 - header-6-name
    

跨區域

    gcloud compute url-maps edit URL_MAP_NAME \
        --global
    

以下是 YAML 檔案範例,說明如何在自訂標頭中使用變數:

   defaultService: global/backendServices/BACKEND_SERVICE_1
   name: global-lb-map
   hostRules:
   - hosts:
     - '*'
     pathMatcher: matcher1
   pathMatchers:
   - defaultService: global/backendServices/BACKEND_SERVICE_1
     name: matcher1
     routeRules:
       - matchRules:
           - prefixMatch: /PREFIX
         priority: PRIORITY # 0 is highest
         routeAction:
           weightedBackendServices:
             - backendService: global/backendServices/BACKEND_SERVICE_1
               weight: 100
               headerAction:
                 requestHeadersToAdd:
                 - headerName: X-header-1-client-region
                   headerValue: "{client_region}"
                 - headerName: X-header-2-client-ip-port
                   headerValue: "{client_ip_address}, {client_port}"
                   replace: True
                 requesteHeadersToRemove:
                 - header-3-name
                 responseHeadersToAdd:
                 - headerName: X-header-4-server-ip-port
                   headerValue: "{server_ip_address}, {server_port}"
                   replace: True
                 responseHeadersToRemove:
                 - header-5-name
                 - header-6-name
    

請注意下列行為:

  • 如果含有自訂變數的回應標頭解析為空白字串,系統會移除該標頭。
  • 如果含有自訂變數的要求標頭解析為空白字串,系統會保留該標頭,並使用空白字串預留位置。
  • 如果自訂要求標頭包含自訂變數,且傳入的用戶端要求也包含相同的標頭,則用戶端要求標頭值會替換為負載平衡器自訂標頭提供的新值。

可以出現在標題值中的變數

以下變數可出現在自訂標頭值中。

變數 說明
client_region 與用戶端 IP 位址關聯的國家 (或地區)。這是 Unicode CLDR 地區代碼,例如 USFR。(大部分國家的代碼都可以與 ISO-3166-2 代碼直接對應)。
client_rtt_msec 負載平衡器與 HTTP(S) 用戶端之間的預估往返傳輸時間,以毫秒為單位。這是負載平衡器的 TCP 堆疊根據 RFC 2988 測量出的順暢往返時間 (SRTT) 參數。經過平滑處理的 RTT 是一種演算法,可處理 RTT 測量中可能發生的變化和異常情形。
client_ip_address 用戶端的 IP 位址。這通常與用戶端 IP 位址相同,也就是 X-Forwarded-For 標頭中倒數第二個位址,除非用戶端使用 Proxy 或 X-Forwarded-For 標頭遭到竄改。
client_port 用戶端的來源通訊埠。
client_encrypted true 如果用戶端和負載平衡器之間的連線已加密 (使用 HTTPS、HTTP/2 或 HTTP/3);否則為 false
client_protocol 用於用戶端與負載平衡器之間通訊的 HTTP 通訊協定。只能設為 HTTP/1.0HTTP/1.1HTTP/2HTTP/3 之一。
origin_request_header 反映跨來源資源共享 (CORS) 用途的 Origin 標頭在要求中的值。
server_ip_address 用戶端連線的負載平衡器 IP 位址。當多個負載平衡器共用相同的後端時,這項功能就很實用。這與 X-Forwarded-For 標頭中的最後一個 IP 位址相同。
server_port 用戶端連線的目的地通訊埠編號。
tls_sni_hostname 伺服器名稱指標 (如 RFC 6066 中的定義),如果用戶端在 TLS 或 QUIC 交握期間提供。系統會將主機名稱轉換為小寫,並移除任何的尾隨點。
tls_version 在 SSL 交握期間,用戶端與負載平衡器之間協商的 TLS 版本。可能的值包括:TLSv1TLSv1.1TLSv1.2TLSv1.3。如果用戶端使用 QUIC 而非 TLS 進行連線,值會是 QUIC
tls_cipher_suite 在 TLS 交握期間協商的加密套件。這個值是由 IANA TLS 加密套件登錄檔定義的四個十六進位數字,例如 TLS_RSA_WITH_AES_128_GCM_SHA256 的 009C。對於 QUIC 和未加密的用戶端連線,這個值為空白。
tls_ja3_fingerprint 如果用戶端使用 HTTPS、HTTP/2 或 HTTP/3 連線,則為 JA3 TLS/SSL 指紋

當負載平衡器無法判斷變數的值時,會將其代換為空字串。例如:

  • IP 位址位置不明時的地理位置變數
  • 未使用 TLS 時的 TLS 參數
  • 要求不含 Origin 標頭時的 {origin_request_header}

地理值是根據用戶端 IP 位址判斷的預估值。Google 會不時更新這些值的資料,以提高準確度及反映地理和政治上的變化。即使原始 X-Forwarded-For 標頭包含有效的位置資訊,Google 仍會使用負載平衡器收到的封包中所含的來源 IP 位址資訊,來預估用戶端位置。

相互傳輸層安全性 (TLS) 自訂標頭

如果在負載平衡器的 TargetHttpsProxy 上設定對等 TLS (mTLS),則可使用下列額外的標頭變數。

變數 說明
client_cert_present 如果用戶端在 TLS 握手期間提供憑證,則為 true;否則為 false
client_cert_chain_verified 如果用戶端憑證鏈結是根據已設定的 TrustStore 進行驗證,則為 true;否則為 false
client_cert_error 代表錯誤狀況的預先定義字串。如要進一步瞭解錯誤字串,請參閱 mTLS 用戶端驗證模式
client_cert_sha256_fingerprint 以 Base64 編碼的 SHA-256 指紋,用於驗證用戶端憑證。
client_cert_serial_number 用戶端憑證的序號。 如果序號長度超過 50 個位元組,系統會將字串 client_cert_serial_number_exceeded_size_limit 新增至 client_cert_error,並將序號設為空字串。
client_cert_spiffe_id

主體別名 (SAN) 欄位中的 SPIFFE ID。如果值無效或超過 2048 個位元組,SPIFFE ID 會設為空白字串。

如果 SPIFFE ID 長度超過 2048 個位元組,字串 client_cert_spiffe_id_exceeded_size_limit 會新增至 client_cert_error

client_cert_uri_sans

以逗號分隔的 Base64 編碼清單,其中包含 URI 類型的 SAN 擴充功能。系統會從用戶端憑證中擷取 SAN 擴充欄位。client_cert_uri_sans 欄位中不包含 SPIFFE ID。

如果 client_cert_uri_sans 超過 512 個位元組,字串 client_cert_uri_sans_exceeded_size_limit 會新增至 client_cert_error,以逗號分隔的清單則會設為空字串。

client_cert_dnsname_sans

以逗號分隔的 Base64 編碼清單,其中包含 DNSName 類型的 SAN 擴充功能。系統會從用戶端憑證中擷取 SAN 擴充欄位。

如果 client_cert_dnsname_sans 超過 512 個位元組,字串 client_cert_dnsname_sans_exceeded_size_limit 會新增至 client_cert_error,以逗號分隔的清單則會設為空字串。

client_cert_valid_not_before 用戶端憑證失效之前的時間戳記 (採用 RFC 3339 日期字串格式)。例如:2022-07-01T18:05:09+00:00
client_cert_valid_not_after 用戶端憑證失效的時間戳記 (採用 RFC 3339 日期字串格式)。例如:2022-07-01T18:05:09+00:00
client_cert_issuer_dn

憑證中的完整發證者欄位,採用 Base64 編碼。

如果 client_cert_issuer_dn 長度超過 512 位元組,字串 client_cert_issuer_dn_exceeded_size_limit 會新增至 client_cert_error,而 client_cert_issuer_dn 會設為空字串。

client_cert_subject_dn

憑證中的 Base64 編碼完整主體欄位。

如果 client_cert_subject_dn 長度超過 512 位元組,字串 client_cert_subject_dn_exceeded_size_limit 會新增至 client_cert_error,而 client_cert_subject_dn 會設為空字串。

client_cert_leaf

已建立 mTLS 連線的用戶端葉憑證,且憑證已通過驗證。憑證編碼符合 RFC 9440 標準:二進位 DER 憑證會使用 Base64 編碼 (不含換行符號、空格或 Base64 字母表以外的其他字元),並在兩側以冒號分隔。

如果 client_cert_leaf 未經編碼的大小超過 16 KB,系統會將字串 client_cert_validated_leaf_exceeded_size_limit 新增至 client_cert_error,並將 client_cert_leaf 設為空字串。

client_cert_chain

以逗號分隔的憑證清單,以標準 TLS 順序列出已建立 mTLS 連線的用戶端憑證鏈結 (用戶端憑證已通過驗證),不含葉片憑證。憑證編碼符合 RFC 9440 標準。

如果 client_cert_leafclient_cert_chain 在 Base64 編碼前總大小超過 16 KB,字串 client_cert_validated_chain_exceeded_size_limit 會新增至 client_cert_error,而 client_cert_chain 會設為空字串。

限制

以下限制適用於與地區負載平衡器搭配使用的自訂標頭:

  • 您無法在區域外部應用程式負載平衡器、區域內部應用程式負載平衡器,以及跨區域內部應用程式負載平衡器使用的區域後端服務上設定自訂標頭。
  • 區域性外部應用程式負載平衡器不支援下列自訂標頭變數:
    • cdn_cache_id
    • cdn_cache_status
    • client_region_subdivision
    • client_city
    • client_city_lat_long