sigs.k8s.io/gateway-api@v1.0.0/geps/gep-1323.md (about)

     1  # GEP 1323: Response Header Filter
     2  
     3  * Issue: [#1323](https://github.com/kubernetes-sigs/gateway-api/issues/1323)
     4  * Status: Standard
     5  
     6  > **Note**: This GEP is exempt from the [Probationary Period][expprob] rules of
     7  > our GEP overview as it existed before those rules did, and so it has been
     8  > explicitly grandfathered in.
     9  
    10  [expprob]:https://gateway-api.sigs.k8s.io/geps/overview/#probationary-period
    11  
    12  ## TLDR
    13  Similar to how we have `RequestHeaderModifier` in `HTTPRouteFilter`, which lets users modify request headers before the request is forwarded to a backend (or a group of backends), it’d be helpful to have a `ResponseHeaderModifier` field which would let users modify response headers before they are returned to the client.
    14  
    15  ## Goals
    16  * Provide a way to modify HTTP response headers in a `HTTPRoute`.
    17  * Reuse existing types as much as possible to reduce boilerplate code.
    18  
    19  ## Non Goals
    20  * Provide a way to modify other parts of a HTTP response like status code.
    21  * Add fields specifically for standard headers such as `Cookie`.
    22  
    23  ## Introduction
    24  Currently, the `HTTPRouteFilter` API provides a way for request headers to be modified through the `RequestHeaderModifier` field of type `HTTPRequestHeaderModifier`. But, a similar API to modify response headers does not exist. This proposal intends to introduce a new field in `HTTPRouteFilter` named `ResponseHeaderModifier`.
    25  
    26  ## API
    27  We could introduce a new API named `HTTPResponseHeaderModifier` which would look exactly like the existing `HTTPRequestHeaderModifier` API. But since HTTP headers have the same semantics for both requests and responses, it makes more sense to rename `HTTPRequestHeaderModifier` to `HTTPHeaderModifier` and use this for both `RequestHeaderModifier` and `ResponseHeaderModifier`.
    28  
    29  ```golang
    30  // HTTPHeaderModifier defines a filter that modifies the headers of a HTTP
    31  // request or response.
    32  type HTTPHeaderModifier struct {
    33      // Set overwrites the request with the given header (name, value)
    34      // before the action.
    35      // +optional
    36      // +listType=map
    37      // +listMapKey=name
    38      // +kubebuilder:validation:MaxItems=16
    39      Set []HTTPHeader `json:"set,omitempty"`
    40  
    41      // Add adds the given header(s) (name, value) to the request
    42      // before the action. It appends to any existing values associated
    43      // with the header name.
    44  
    45      // +optional
    46      // +listType=map
    47      // +listMapKey=name
    48      // +kubebuilder:validation:MaxItems=16
    49      Add []HTTPHeader `json:"add,omitempty"`
    50  
    51      // Remove the given header(s) from the HTTP request before the action. The
    52      // value of Remove is a list of HTTP header names. Note that the header
    53      // names are case-insensitive (see
    54      // https://datatracker.ietf.org/doc/html/rfc2616#section-4.2).
    55      // +optional
    56      // +kubebuilder:validation:MaxItems=16
    57      Remove []string `json:"remove,omitempty"`
    58  }
    59  ```
    60  
    61  Given the fact that this functionality is offered by only a few projects that currently implement Gateway API when using their own traffic routing CRDs, it’s better to support `ResponseHeaderModifier` as an _Extended_ feature, unlike `RequestHeaderModifier` which is a _Core_ feature. This will also not increase the difficulty of implementing Gateway API for any future ingress or service mesh.
    62  
    63  This feature can be further extended via [Policy Attachment](../reference/policy-attachment.md). The mechanism and use cases of this may be explored in a future GEP.
    64  
    65  ## Usage
    66  Adding support for this unlocks a lot of real world use cases. Let’s review a couple of them:
    67  
    68  * A team has a frontend web app, along with two different versions of their backends exposed as Kubernetes services. If, the frontend needs to know which backend it’s talking to, this can be easily achieved without any modifications to the application code.
    69  
    70  ```yaml
    71  apiVersion: gateway.networking.k8s.io/v1beta1
    72  kind: HTTPRoute
    73  metadata:
    74    name: http-response-header
    75  spec:
    76    hostnames:
    77      - response.header.example
    78    rules:
    79      - backendRefs:
    80        - name: example-svc-beta
    81          weight: 50
    82          port: 80
    83          # set a custom header for all responses being sent from the beta build of the backend server.
    84          filters:
    85             - type: ResponseHeaderModifier
    86               responseHeaderModifier:
    87                add:
    88                  name: build
    89                  value: beta
    90        - name: example-svc-stable
    91          weight: 50
    92          port: 80
    93  ```
    94  
    95  * Cookies can be automatically injected into the response of services. This can enable services to identify users that were redirected to a certain backend.
    96  
    97  ```yaml
    98  apiVersion: gateway.networking.k8s.io/v1beta1
    99  kind: HTTPRoute
   100  metadata:
   101    name: http-response-header
   102  spec:
   103    hostnames:
   104      - response.header.example
   105    rules:
   106      # match against any requests that has the cookie set due to the below rule
   107      - matches:
   108        - headers:
   109          type: Exact
   110          name: Cookie
   111          value: user=insider
   112        backendRefs:
   113        - name: foo-svc
   114          port: 8080
   115  
   116      - filters:
   117        - type: ResponseHeaderModifier
   118          # set cookies for all requests being forwarded to this service
   119          responseHeaderModifier:
   120            set:
   121              name: Set-Cookie
   122              value: user=insider
   123        backendRefs:
   124        - name: example-svc
   125          weight: 1
   126          port: 80
   127  ```
   128  
   129  > Note: Some projects like Envoy support interpolating a few predefined [variables into header values](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#custom-request-response-headers). Similar functionality might be supported by other implementations but its unlikely to be portable and thus has been excluded from the API for the time being.
   130  
   131  ## Prior Art
   132  A few projects that implement Gateway API already have support for similar functionality (in their custom CRDs), like:
   133  * Istio’s `VirtualService`:
   134  
   135  ```yaml
   136  apiVersion: networking.istio.io/v1alpha3
   137  kind: VirtualService
   138  metadata:
   139    name: reviews-route
   140  spec:
   141    hosts:
   142    - reviews.prod.svc.cluster.local
   143    http:
   144    - headers:
   145        request:
   146          set:
   147            test: "true"
   148      route:
   149      - destination:
   150          host: reviews.prod.svc.cluster.local
   151          subset: v2
   152        weight: 25
   153      - destination:
   154          host: reviews.prod.svc.cluster.local
   155          subset: v1
   156        headers:
   157          response:
   158            remove:
   159            - foo
   160        weight: 75
   161  ```
   162  
   163  * Contour’s `HTTPProxy`:
   164  
   165  ```yaml
   166  apiVersion: projectcontour.io/v1
   167  kind: HTTPProxy
   168  metadata:
   169    name: basic
   170  spec:
   171    virtualhost:
   172      fqdn: foo-basic.bar.com
   173    routes:
   174      - conditions:
   175        - prefix: /
   176        services:
   177          - name: s1
   178            port: 80
   179        responseHeadersPolicy:
   180          set:
   181            name: test
   182            value: true
   183  ```
   184  
   185  * Ingress NGINX:
   186  
   187  ```yaml
   188  apiVersion: networking.k8s.io/v1
   189  kind: Ingress
   190  metadata:
   191    name: nginx-headers
   192    annotations:
   193      nginx.ingress.kubernetes.io/configuration-snippet: |
   194        add_header ingress nginx;
   195  spec:
   196    ingressClassName: nginx
   197    rules:
   198    - host: custom.configuration.com
   199      http:
   200        paths:
   201        - path: /
   202          pathType: Prefix
   203          backend:
   204            service:
   205              name: http-svc
   206              port:
   207                number: 80
   208  ```
   209  
   210  ## External Links
   211  * [Contour `HeaderValue`](https://projectcontour.io/docs/v1.22.0/config/api/#projectcontour.io/v1.HeaderValue)
   212  * [Istio `Headers`](https://istio.io/latest/docs/reference/config/networking/virtual-service/#Headers)
   213  * [Ingress NGINX Configuration Snippets](https://kubernetes.github.io/ingress-nginx/examples/customization/configuration-snippets/)
   214  * [NGINX `add_header` directive](https://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header)
   215