'Add Custom Header to HTTP request in Load Balancer

I have an containerized application/service deployed in openshift container platform with istio service mesh. In istio virtual service yaml, i wanted to validate if the http request is having a header(for ex: version) and with value v1. i have added below config in virtual service yaml which validates header. But i am looking for available options to inject this header in HTTP request using loadbalancer/ingress/openshif route etc. As my istio-ingressgateway service is deployed with ClusterIp. i have used openshift route to send the external traffic to ingressgateway. please share the possible ways to add headers to http request

  http:
    - match:
        - headers: # Match header
            version: # header that we decided for dark release
              exact: v1 # exact match


 


Solution 1:[1]

You can use envoy filter to do that.

Below envoy filter add request header called customer-id with alice value to all request going though istio ingress gateway. I also commented code for response headers if someone would like to use it.

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: lua-filter
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  configPatches:
  - applyTo: HTTP_FILTER
    match:
      context: GATEWAY
      listener:
        filterChain:
          filter:
            name: "envoy.http_connection_manager"
            subFilter:
              name: "envoy.router"
    patch:
      operation: INSERT_BEFORE
      value:
       name: envoy.lua
       typed_config:
         "@type": "type.googleapis.com/envoy.config.filter.http.lua.v2.Lua"
         inlineCode: |
            function envoy_on_request(request_handle)
                request_handle:headers():add("customer-id", "alice")
            end
           # function envoy_on_response(response_handle)
           #     response_handle:headers():add("customer-id", "alice")
           # end

There are yamls I've used to test that, it might be useful for testing above filter.

  • If you use above filter with alice header then all requests goes to nginx-v1
  • If you use above filter with bob header then all requests goes to nginx-v2
  • If you delete this filter then it's 50/50 between nginx-v1 and nginx-v2

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-v1
spec:
  selector:
    matchLabels:
      run: nginx1
  replicas: 1
  template:
    metadata:
      labels:
        run: nginx1
        app: frontend
    spec:
      containers:
      - name: nginx1
        image: nginx
        ports:
        - containerPort: 80
        lifecycle:
          postStart:
            exec:
              command: ["/bin/sh", "-c", "echo Hello nginx1 > /usr/share/nginx/html/index.html"]

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-v2
spec:
  selector:
    matchLabels:
      run: nginx2
  replicas: 1
  template:
    metadata:
      labels:
        run: nginx2
        app: frontend
    spec:
      containers:
      - name: nginx2
        image: nginx
        ports:
        - containerPort: 80
        lifecycle:
          postStart:
            exec:
              command: ["/bin/sh", "-c", "echo Hello nginx2 > /usr/share/nginx/html/index.html"]



---

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: frontend
spec:
  ports:
  - name: http-front
    port: 80
    protocol: TCP
  selector:
    app: frontend

---

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: gatewayx
spec:
  selector:
    istio: ingressgateway # use istio default controller
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"

---

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: nginxvirt
spec:
  hosts:
  - '*'
  gateways:
  - gatewayx
  http:
  - name: "route-1"
    match:
    - headers:
        customer-id:
          exact: alice
    route:
    - destination:
        host: nginx
        subset: v1
  - name: "route-2"
    match:
    - headers:
        customer-id:
          exact: bob
    route:
    - destination:
        host: nginx
        subset: v2
  - route:
    - destination:
        host: nginx

---

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: nginxdest
spec:
  host: nginx
  subsets:
  - name: v1
    labels:
      run: nginx1
  - name: v2
    labels:
      run: nginx2

Solution 2:[2]

It should be possible to use virtualService like

spec:  
  hosts:  
  - "example.com"  
  gateways:  
  - your-gateway  
  http:  
  -   
    name: remove-headers  
    headers:  
      request:  
        remove:  
        - yourHeader  

But I can't make it works. Please share if you can :)

Solution 3:[3]

Pretty late to answer this but hope it helps someone.

We can use istio virtual service for adding custom headers to request as well as response.

I am using bookinfo-gateway provided by Istio as an example here:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
  - "*"
  gateways:
  - bookinfo-gateway
  http:
  - match:
    - uri:
        exact: /productpage
    route:
    - destination:
        host: productpage
        port:
          number: 9080
      headers:
        request:
          set:
            X-Frame-Options: deny # if request header has X-Frame-Options, it will be overwritten
        response:
          add:
            hello: world # add "hello" with value world in response header
          remove:
            - "foo" # remove foo from response header

I have tested this locally using Minikube v1.25.2, and Istio v1.13, it is working as per expectations.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jakub
Solution 2 terrasson marc
Solution 3 bhushan pathak