Appending and Removing Request/Response Headers

Gloo Edge can add and remove headers to/from requests and responses. We refer to this feature as “Header Manipulation”.

Header Manipulation is configured via the headerManipulation struct.

This struct can be added to Route Options , Virtual Host Options , and Weighted Destination Options .

The headerManipulation struct contains four optional fields requestHeadersToAdd, requestHeadersToRemove, responseHeadersToAdd, and responseHeadersToRemove. The key and value for the header can be specified directly in the manifest, or in the case of requestHeadersToAdd it can be a reference to a secret of the type gloo.solo.io/header or Opaque.

headerManipulation:

  # add headers to request
  requestHeadersToAdd:
  - header:
      key: HEADER_NAME
      value: HEADER_VALUE
    # if the header HEADER_NAME is already present,
    # append the value.
    append: true
  - header:
      key: HEADER_NAME
      value: HEADER_VALUE
    # if the header HEADER_NAME is already present,
    # overwrite the value.
    append: false
  - headerSecretRef:
      name: SECRET_NAME
      namespace: SECRET_NAMESPACE
    # The type of the secret must be gloo.solo.io/header or Opaque
    # Each key/value pair in the secret will be added

  # remove headers from request
  requestHeadersToRemove:
  - "HEADER_NAME"
  - "HEADER_NAME"

  # add headers to response
  responseHeadersToAdd:
  - header:
      key: HEADER_NAME
      value: HEADER_VALUE
    # if the header HEADER_NAME is already present,
    # append the value.
    append: true
  - header:
      key: HEADER_NAME
      value: HEADER_VALUE
    # if the header HEADER_NAME is already present,
    # overwrite the value.
    append: false

  # remove headers from response
  responseHeadersToRemove:
  - "HEADER_NAME"
  - "HEADER_NAME"
  

Depending on where the headerManipulation struct is added, the header manipulation will be applied on that level.

Envoy supports adding dynamic values to request and response headers. The percent symbol (%) is used to delimit variable names. See a list of the dynamic variables supported by Envoy in the envoy docs.

If you would like to use the headerSecretRef with requestHeadersToAdd, you can create the correct Secret type by using glooctl. For example, the following command will create a secret named my-headers:

glooctl create secret header my-headers --headers x-header-1=one,x-header-2=two

The secret will be created in the same namespace as the Gloo Edge installation by default. Inspecting the secret will show that the type is set to gloo.solo.io/header. Each key/value pair in the secret will be added as a header to the request.

Example: Manipulating Headers on a Route

apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
  creationTimestamp: null
  name: 'default'
  namespace: 'gloo-system'
spec:
  virtualHost:
    domains:
    - '*'
    routes:
    - matchers:
       - prefix: '/petstore'
      routeAction:
        single:
          upstream:
            name: 'default-petstore-8080'
            namespace: 'gloo-system'
      options:
        prefixRewrite: '/api/pets'
        headerManipulation:
          # add headers to all responses 
          # returned by this route
          responseHeadersToAdd:
          - header:
              key: HEADER_NAME
              value: HEADER_VALUE
          - headerSecretRef
              name: my-headers
              namespace: gloo-system
status: {}

Example: Manipulating Headers on a VirtualHost

apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
  creationTimestamp: null
  name: 'default'
  namespace: 'gloo-system'
spec:
  virtualHost:
    domains:
    - '*'
    routes:
    - matchers:
       - prefix: '/petstore'
      routeAction:
        single:
          upstream:
            name: 'default-petstore-8080'
            namespace: 'gloo-system'
      options:
        prefixRewrite: '/api/pets'
    options:
      headerManipulation:
        # remove headers from all requests 
        # handled by this virtual host
        requestHeadersToRemove:
        - "x-my-header"
        - "x-your-header"
status: {}

Example: Manipulating Headers on a Weighted Destination

apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
  creationTimestamp: null
  name: 'default'
  namespace: 'gloo-system'
spec:
  virtualHost:
    domains:
    - '*'
    routes:
    - matchers:
       - prefix: /myservice
      routeAction:
        multi:
          destinations:
          - weight: 9
            destination:
              upstream:
                name: default-myservice-v1-8080
                namespace: gloo-system
          - weight: 1
            destination:
              upstream:
                name: default-myservice-v2-8080
                namespace: gloo-system
            options:
              headerManipulation:
                # add headers to all requests
                # that are load balanced to `default-myservice-v2-8080`
                # on this route 
                requestHeadersToAdd:
                - header:
                    key: HEADER_NAME
                    value: HEADER_VALUE
status: {}

Inheritance of request headers

Headers can be inherited by children objects, such as shown in the following example with delegated routes. For more information about inheritance, see Inheritance rules. For more information about delegation, see Delegating with route tables.

  1. In your Virtual Service, set up a delegated route.
    apiVersion: gateway.solo.io/v1
    kind: VirtualService
    metadata:
      name: 'example'
      namespace: 'gloo-system'
    spec:
      virtualHost:
        domains:
        - 'example.com'
        routes:
        - matchers:
           - prefix: '/a' # delegate ownership of routes for `example.com/a`
          delegateAction:
            ref:
              name: 'a-routes'
              namespace: 'a'
        - matchers:
           - prefix: '/b' # delegate ownership of routes for `example.com/b`
          delegateAction:
            ref:
              name: 'b-routes'
              namespace: 'b'
    
  2. Add headers that you want all child objects to inherit in the VirtualHost parent object in the same VirtualService as the previous step. In the following example, the x-gateway-start-time header is added to requests, and the x-route-table: alphabet header is added to responses.
    ...
    virtualHost:
      options:
        headerManipulation:
          requestHeadersToAdd:
            - header:
                key: x-gateway-start-time
                value: '%START_TIME%'
          responseHeadersToAdd:
            - header:
                key: x-route-table
                value: alphabet
    
  3. In the RouteTable child object, define other headers. In the following example, the x-route-table header is added to requests, and the x-route-table: a header is added to responses.
    apiVersion: gateway.solo.io/v1
    kind: RouteTable
    metadata:
      name: 'a-routes'
      namespace: 'a'
    spec:
      routes:
        - matchers:
            # the path matchers in this RouteTable must begin with the prefix `/a/`
           - prefix: '/a/1'
          routeAction:
            single:
              upstream:
                name: 'foo-upstream'
      options:
        headerManipulation:
          requestHeadersToAdd:
            - header:
                key: x-route-table
                value: a
          responseHeadersToAdd:
            - header:
                key: x-route-table
                value: a
    
  4. Now, requests that match the route /a/1 get the following headers:
    • The x-gateway-start-time request header is inherited from the parent VirtualHost option.
    • The x-route-table request header is set in the child Route option.
    • The x-route-table response header in the child overwrites the parent object’s value of alphabet instead to a, because child objects take precedence in case of conflict.