How to pass the part of request uri as custom header in Kubernetes ingress controller

12/20/2019

I've the below configuration in ingress.yaml which forwards the requests with uris like /default/demoservice/health or /custom/demoservice/health to backend demoservice. I would want to retrieve the first part of uri (i.e default or custom in the example above)from the uri and pass as custom header to upstream.

I've deployed the ingress configmap with custom header

X-MyVariable-Path: ${request_uri} 

but this sends the full request uri. How can I split?

- path: "/(.*?)/(demoservice.*)
quot;
backend: serviceName: demoservice servicePort: 80
-- Shiva
kubernetes
kubernetes-ingress

2 Answers

12/20/2019

I found two ways to achieve this.

One is by using regular expression in your configmap to parse the first part of request_uri.

To do the above, you need to add nginx.ingress.kubernetes.io/use-regex: "true" annotation to your ingress, before you do so. As this is set to false by default.

Another approach is defining that particular header in the annotation itself and add something like $1 below is the example.

ingress.kubernetes.io/configuration-snippet: |
      more_set_headers "X-MyVariable-Path: "$1;

Not entirely sure, that would work for you. But I got this logic from Rewrite example here.

And add the path as /customheader(/|$)(.*) something like this will create a capture group.

Hope it works and helpful.

-- BinaryMonster
Source: StackOverflow

12/20/2019

I have found a solution, tested it and it works.
All you need is to add following annotations to your ingress object :

nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/configuration-snippet: |  
proxy_set_header X-MyVariable-Path $1;  

Where $1 is referencing whatever is captured in first group of regexp expression in path: field.

I've reproduced your scenario using the following yaml:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_set_header  X-MyVariable-Path  $1;
    nginx.ingress.kubernetes.io/use-regex: "true"
  name: foo-bar-ingress
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: echo
          servicePort: 80
        path: /(.*?)/(demoservice.*)$
---
apiVersion: v1
kind: Service
metadata:
  labels:
    run: echo
  name: echo
spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    run: echo
---
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: echo
  name: echo
spec:
  containers:
  - image: mendhak/http-https-echo
    imagePullPolicy: Always
    name: echo

You can test using curl:

curl -k https://<your_ip>/default/demoservice/healthz

Output:

 {
  "path": "/default/demoservice/healthz",
  "headers": {
    "host": "192.168.39.129",
    "x-request-id": "dfcc67a80f5b02e6fe6c647c8bf8cdf0",
    "x-real-ip": "192.168.39.1",
    "x-forwarded-for": "192.168.39.1",
    "x-forwarded-host": "192.168.39.129",
    "x-forwarded-port": "443",
    "x-forwarded-proto": "https",
    "x-scheme": "https",
    "x-myvariable-path": "default", # your variable here
    "user-agent": "curl/7.52.1",
    "accept": "*/*"
  },
  "method": "GET",
  "body": "",
  "fresh": false,
  "hostname": "192.168.39.129",
  "ip": "::ffff:172.17.0.4",
  "ips": [],
  "protocol": "http",
  "query": {},
  "subdomains": [],
  "xhr": false,
  "os": {
    "hostname": "echo"
  }
}

I hope it helps =)

-- KoopaKiller
Source: StackOverflow