This page describes how custom headers work in URL maps used by regional internal Application Load Balancers and cross-region internal Application Load Balancers.
Custom request and response headers let you specify additional headers that the load balancer can add to HTTP(S) requests and responses. Depending on the information that the load balancer detects, these headers can include the following information:
- Latency to the client
- Parameters of the TLS connection 
Before you begin
If necessary, update to the latest version of the Google Cloud CLI:
gcloud components update
How custom headers work
Custom headers work as follows:
- When the load balancer makes a request to the backend, the load balancer adds request headers. - The load balancer adds custom request headers only to the client requests, not to the health check probes. If your backend requires a specific header for authorization that is missing from the health check packet, the health check might fail. 
- The load balancer sets response headers before returning a response to the client. 
To enable custom headers for regional internal Application Load Balancers and cross-region internal Application Load Balancers, you specify a list of header names and header values in the URL map configuration file.
Header names must have the following properties:
- The header name must be a valid HTTP header-field name definition per RFC 7230.
- The header name must not be X-User-IP.
- The header name must not begin with X-Google,X-Goog-,X-GFE, orX-Amz-.
- The following hop-by-hop headers must not be used:
Keep-Alive,Transfer-Encoding,TE,Connection,Trailer, andUpgrade. In accordance with RFC 2616, these headers are not stored by caches or propagated by the target proxies.
- The header name must not be Hostorauthority. BothHostandauthorityare special keywords reserved by Google Cloud. You can't modify these headers for Envoy-based load balancers. Instead, we recommend that you create other custom headers (for example,MyHost) so that you don't interfere with the reserved header names.
- A header name must not appear more than once in the list of headers.
Header names are case-insensitive. When header names are passed to an HTTP/2 backend, the HTTP/2 protocol encodes header names as lowercase.
Header values must have the following properties:
- The header value must be a valid HTTP header field definition per RFC 7230, with obsolete forms disallowed.
- The header value can't be blank. Blank headers are rejected.
- The header value can include one or more variables, enclosed by curly braces, that expand to values that the load balancer provides. For a complete list of variables allowed in the header value, see Variables that can appear in the header value.
In header values, leading whitespace and trailing whitespace are insignificant
and are not passed to the backend. To allow for curly braces in header values,
the load balancer interprets two opening curly braces ({{) as
a single opening brace ({), and two closing curly braces (}}) as a single
closing brace (}).
Add request or response headers
To add request or response headers, use the gcloud CLI to edit the URL map as follows:
Regional
    gcloud compute url-maps edit URL_MAP_NAME \
        --region=REGION
    Following is a sample YAML file that shows you how to use variables in custom headers:
   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
                 requestHeadersToRemove:
                 - 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
    Cross-region
    gcloud compute url-maps edit URL_MAP_NAME \
        --global
    Following is a sample YAML file that shows you how to use variables in custom headers:
   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
    Note the following behaviors:
- If a response header with custom variables resolves to an empty string, it is removed.
- If a request header with custom variables resolves to an empty string, it is retained with an empty string placeholder.
- If a custom request header includes a custom variable, and an incoming client request also includes the same header, the client request header value will be replaced with the new value provided by the load balancer's custom header.
Variables that can appear in the header value
The following variables can appear in custom header values.
| Variable | Description | 
|---|---|
| client_rtt_msec | Estimated round-trip transmission time between the load balancer and the HTTP(S) client, in milliseconds. This is the smoothed round-trip time (SRTT) parameter measured by the load balancer's TCP stack, per RFC 2988. Smoothed RTT is an algorithm that deals with variations and anomalies that may occur in RTT measurements. | 
| client_ip_address | The client's IP address. This is usually the same as the client IP address
        that is the next-to-last address in the X-Forwarded-Forheader, unless the client is using a proxy or theX-Forwarded-Forheader has been tampered with. | 
| client_port | The client's source port. | 
| client_encrypted | trueif the connection between the client and the
        load balancer is encrypted (using HTTPS, HTTP/2, or HTTP/3); otherwise,false. | 
| client_protocol | The HTTP protocol used for communication between the client and the
        load balancer. One of HTTP/1.0,HTTP/1.1,HTTP/2, orHTTP/3. | 
| origin_request_header | Reflects the value of the Originheader in the request
          for Cross-Origin Resource Sharing (CORS) use cases. | 
| server_ip_address | The IP address of the load balancer that the client connects to. This
        can be useful when multiple load balancers share common backends. This
        is the same as the last IP address in the X-Forwarded-Forheader. | 
| server_port | The destination port number that the client connects to. | 
| tls_sni_hostname | Server name indication (as defined in RFC 6066), if provided by the client during the TLS or QUIC handshake. The hostname is converted to lowercase and with any trailing dot removed. | 
| tls_version | TLS version negotiated between client and load balancer during the
        SSL handshake. Possible values include: TLSv1,TLSv1.1,TLSv1.2, andTLSv1.3. If
        the client connects using QUIC instead of TLS, the value isQUIC. | 
| tls_cipher_suite | Cipher suite negotiated during the TLS handshake. The value is four
        hex digits defined by the
        IANA
        TLS Cipher Suite Registry,
        for example, 009Cfor TLS_RSA_WITH_AES_128_GCM_SHA256. This
        value is empty for QUIC and for unencrypted client connections. | 
| tls_ja3_fingerprint | JA3 TLS/SSL fingerprint if the client connects using HTTPS, HTTP/2 or HTTP/3. | 
The load balancer expands variables to empty strings when it can't determine their values. For example:
- TLS parameters when TLS is not in use
- The - {origin_request_header}when the request does not include an- Originheader
Geographic values are estimates based on the client's IP address. From time to
time, Google updates the data that provides these values in order to improve
accuracy and to reflect geographic and political changes. Even if the original
X-Forwarded-For header contains valid location information, Google estimates
client locations by using the source IP address information contained in packets
received by the load balancer.
Mutual TLS custom headers
The following additional header variables are available if mutual TLS (mTLS) is configured on the load balancer's TargetHttpsProxy.
| Variable | Description | 
|---|---|
| client_cert_present | trueif the
       client has provided a certificate during the TLS handshake;
       otherwise,false. | 
| client_cert_chain_verified | trueif the
       client certificate chain is verified against a configuredTrustStore; otherwise,false. | 
| client_cert_error | Predefined strings representing the error conditions. For more information about the error strings, see mTLS client validation modes. | 
| client_cert_sha256_fingerprint | Base64-encoded SHA-256 fingerprint of the client certificate. | 
| client_cert_serial_number | The serial number of the client certificate.
      If the serial number is longer than 50 bytes, the string client_cert_serial_number_exceeded_size_limitis added toclient_cert_error, and the
      serial number is set to an empty string. | 
| client_cert_spiffe_id | The SPIFFE ID from the subject alternative name (SAN) field. If the value is not valid or exceeds 2048 bytes, the SPIFFE ID is set to an empty string. If the SPIFFE ID is longer than 2048 bytes, the string
       | 
| client_cert_uri_sans | Comma-separated Base64-encoded list of the SAN extensions of type URI.
      The SAN extensions are extracted from the client certificate.
      The SPIFFE ID is not
      included in the  If the  | 
| client_cert_dnsname_sans | Comma-separated Base64-encoded list of the SAN extensions of type DNSName. The SAN extensions are extracted from the client certificate. If the  | 
| client_cert_valid_not_before | Timestamp (RFC 3339
      date string format) before which the client certificate is not valid.
      For example, 2022-07-01T18:05:09+00:00. | 
| client_cert_valid_not_after | Timestamp (RFC 3339
      date string format) after which the client certificate is not valid.
      For example, 2022-07-01T18:05:09+00:00. | 
| client_cert_issuer_dn | Base64-encoded full Issuer field from the certificate. If the  | 
| client_cert_subject_dn | Base64-encoded full Subject field from the certificate. If the  | 
| client_cert_leaf | The client leaf certificate for an established mTLS connection where the certificate passed validation. Certificate encoding is compliant with RFC 9440: the binary DER certificate is encoded using Base64 (without line breaks, spaces, or other characters outside the Base64 alphabet) and delimited with colons on either side. If  | 
| client_cert_chain | The comma-delimited list of certificates, in standard TLS order, of the client certificate chain for an established mTLS connection where the client certificate passed validation, not including the leaf certificate. Certificate encoding is compliant with RFC 9440. If the combined size of  | 
Limitations
The following limitations apply:
- You can't configure custom headers on backend services used by regional internal Application Load Balancers and cross-region internal Application Load Balancers.