-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Issue Template
Title: End-to-End IP transparency using Proxy Protocol
Description:
[It is my intent to work on below, soliciting input, feedback, and assistance]
The general chain of events (in a GKE Kubernetes at least) model is that we have: Client->LoadBalancer->Ingress/Front->Sidecar->service as a sequence. The LoadBalancer does NAT, the Ingress is a proxy server, the istio-sidecar is a proxy server. This leads to 3 levels of address
translation.
Some services need to see the Origin IP to operate efficiently. Methods like X-Forwarded-For, REMOTE_ADDR, exist in HTTP. But, there is no general equivalent for other protocols, and these are unreliable.
General approaches like RFC7974 have been tried (this one fails for ipv6 or when there are more TCP options than average present).
The Kubernetes LoadBalancer exposes a externalTrafficPolicy: Local method to allow keeping the Origin IP. Note, this has a side-affect (see groups and issue ).
HAProxy implemented Proxy Protocol
as a general means around this problem.
In Envoy, we need to act as 3 roles:
- Consumer. In AWS the cloud Load Balancer will natively speak Proxy Protocol, including placing
a TLV extension (PP2_TYPE_AWS/PP2_SUBTYPE_AWS_VPCE_ID) on to indicate the VPC - Originator. Envoy as an Ingress of Front Proxy translates the IP, and should allow transparency
- Sidecar. If we look at mmproxy, we can see a method to be completely transparent, implemented in cloudflare/mmproxy
If all 3 roles are enabled, we can implement services like Geo IP management in our services.
1 Phase (Consumer) is complete (except for the TLV parsing of AWS extensions).
In order to implement the Originator component, information needs to be placed into the socket after connect() and before any other reads/writes. In addition, we need to handle connection-pooling (since absent Envoy, a single connection could never have >1 source IP). Thus an inbound connection being
onward routed can only use a connection-pool connection that advertised the same origin IP.
Potentially a set of Routing matching fields are needed, to operate on the 'Origin' IP vs the 'translated'.
On the 'input side' of Envoy there are a set of filters, but there does not appear to be a single place to hook into all of the outbound (for all protocols since proxy procotol is not specific to http). The closest I can see is:
connection_impl.cc, ~L594
// The local address can only be retrieved for IP connections. Other
// types, such as UDS, don't have a notion of a local address.
if (socket_->remoteAddress()->type() == Address::Type::Ip) {
socket_->setLocalAddress(Address::addressFromFd(fd()), false);
}
}
For the Sidecar (mmproxy), this would involve binding to a non-local IP, and an IP tables rule.
The wire protocol would be otherwise unchanged.
Comments?
a) the general thinking, usefuless of the feature?
b) the components?
c) pointers to where the code would be inserted/type of config needed/concerns/gotchas?