In Apigee X, the X-Forwarded-For header will contain 3 values by default. This will include following:
[Client IP, Load Balancer IP, Istio Gateway IP]
If the client tries to spoof the client IP address by sending a X-Forwarded-For header, those values will get added to the front of the above list. For an example:
[Spoof IP1, Spoof IP2, Client IP, Load Balancer IP, Istio Gateway IP]
Therefore, if you need to find the actual client IP which sent the API request to the Load Balancer, that can be read using a JavaScript policy similar to following:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Javascript continueOnError="false" enabled="true" timeLimit="200" name="Find-Client-Ip">
<DisplayName>Find-Client-Ip</DisplayName>
<Properties/>
<ResourceURL>jsc://Find-Client-Ip.js</ResourceURL>
</Javascript>
Find-Client-Ip.js:
var xffArray = context.getVariable("request.header.x-forwarded-for.values");
var xffArrayLength = context.getVariable("request.header.X-Forwarded-For.values.count");
var clientIp = context.getVariable("request.header.x-forwarded-for." + (xffArrayLength - 2));
context.setVariable("response.content", clientIp);
Proxy Endpoint:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
<PreFlow name="PreFlow">
<Request/>
<Response>
<Step>
<Name>Find-Client-Ip</Name>
</Step>
</Response>
</PreFlow>
<Flows/>
<PostFlow name="PostFlow">
<Request/>
<Response/>
</PostFlow>
<HTTPProxyConnection>
<BasePath>/find-my-ip</BasePath>
</HTTPProxyConnection>
<RouteRule name="noroute"/>
</ProxyEndpoint>
An example API request to verify above implementation:
curl -i -k --resolve ${hostname}:443:${load_balancer_ip} -H 'X-Forwarded-For: 10.0.0.1, 10.0.0.2' https://${hostname}/find-my-ip
An example output by masking sensitive information:
HTTP/2 200
user-agent: curl/7.61.1
accept: */*
x-cloud-trace-context: ---masked---
x-forwarded-for: 10.0.0.1, 10.0.0.2, ---true-client-ip---, ---load-balancer-ip---,10.128.0.3
x-forwarded-proto: https
x-request-id: ---masked---
x-b3-traceid: ---masked---
x-b3-spanid: ---masked---
x-b3-sampled: 0
content-length: 12
date: Fri, 30 Jul 2021 04:12:01 GMT
server: apigee
via: 1.1 google, 1.1 google
alt-svc: clear
---true-client-ip---
@imesh it seems like we might just be able to use the proxy.client.ip flow variable.
Just wondering if there are any issues with that?
I did some checking with our setup:
Client --> External HTTP Load Balancer --[via Network Bridge VMs]--> Apigee X
And this is what I get when I echo out the flow variables. As you can see, it seems that proxy.client.ip correctly identified the end client
{
"client.ip": "192.168.108.29",
"proxy.client.ip": "100.100.100.100",
"request.header.True-Client-IP": "",
"request.header.True-Client-IP.values": "[]",
"request.header.X-Forwarded-For.values": "200.200.200.200, 100.100.100.100, 34.120.113.103, 192.168.108.29]"
}