Istio FAQ - Get client real IP

中文阅读

Problem Description

Service in the namespace with the tag of istio-injection: enabled cannot obtain the real IP of the client through X-Forwarded-For.

Solution

Upgrade Istio

Check and upgrade the Istio version to 1.7 or higher.

Set up externalTrafficPolicy

Set externalTrafficPolicy to Local.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  namespace: istio-system
  name: istiocontrolplane
spec:
  profile: default
  components:
    ingressGateways:
      - name: istio-ingressgateway
        enabled: true
        k8s:
          service:
            externalTrafficPolicy: Local

Wait for the ingressgateway redeployment to complete.

Next, deploy the httpbin service as a verification.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# httpbin.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: httpbin
spec:
  hosts:
    - "httpbin.makeoptim.com"
  gateways:
    - gateway/makeoptim-gateway
  http:
    - route:
        - destination:
            port:
              number: 8000
            host: httpbin
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin
  labels:
    app: httpbin
spec:
  ports:
    - name: http
      port: 8000
  selector:
    app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpbin
      version: v1
  template:
    metadata:
      labels:
        app: httpbin
        version: v1
    spec:
      containers:
        - image: docker.io/citizenstig/httpbin
          imagePullPolicy: IfNotPresent
          name: httpbin
          ports:
            - containerPort: 8000

After deploying httpbin, directly visit and view Headers, you can see that there is an additional X-Envoy-External-Address header, and it points to the real IP of the client.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
❯ curl httpbin.makeoptim.com/get
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Content-Length": "0",
    "Host": "httpbin.makeoptim.com",
    "User-Agent": "curl/7.64.1",
    "X-B3-Parentspanid": "50419cd0b3ae983a",
    "X-B3-Sampled": "0",
    "X-B3-Spanid": "5a0bbd2e611fa59e",
    "X-B3-Traceid": "33c8c481a13746c050419cd0b3ae983a",
    "X-Envoy-Attempt-Count": "1",
    "X-Envoy-External-Address": "38.75.137.213",
    "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/default;Hash=abb1a2a76a04fe7476cd38738e98a228b39dbf6a88936fd249ee23839ec98234;Subject=\"\";URI=spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account",
    "X-Request-Id": "2fe85688-cf60-4f61-b9bb-25e354625124"
  },
  "origin": "38.75.137.213",
  "url": "http://httpbin.makeoptim.com/get"
}

You can get the client’s real IP through X-Envoy-External-Address header. The following is an example of Golang code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package http

import "net/http"

var clientIPHeaders = []string{"X-Envoy-External-Address", "X-Forwarded-For", "X-Real-Ip", "X-Appengine-Remote-Addr"}

// ClientIP get client IP with possible headers.
func ClientIP(request *http.Request) string {
	for _, v := range clientIPHeaders {
		ip := request.Header.Get(v)
		if ip != "" {
			return ip
		}
	}
	return ""
}

Reference

Further reading


CatchZeng
Written by CatchZeng Follow
AI (Machine Learning) and DevOps enthusiast.