-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
nginx: Option to not use neither incoming X-Forwarded headers nor Proxy Protocol. #1815
Comments
even if you get the IP address of one of the nodes? (not using the externalTrafficPolicy field) |
I'd say yes. It's up to you as the cluster manager to configure it correctly, or you get incorrect behavior. You're already getting incorrect behavior in this environment right now by trusting XFF, so adding this option wouldn't make it "more incorrect". The docs here could be expanded to clarify it. |
Hi @Dirbaio How can users spoof their IPs if you don't set the If |
Yes, correct.
No. Not setting
and I can indeed spoof my IP. Making requests from outside the cluster to a test service that echos the received headers back:
|
Setting
|
Good to know! However, I'm not sure what to do about those additional headers One workaround to this issue is to move the logic checking those headers on the server side, activate compute-full-forwarded-for and ignore those headers if remote_addr doesn't match a trusted source. |
IMO the nginx-ingress config needs a bit of refactor to increase flexibility, make it less error-prone and fix the inconsistencies in the XF* headers. Here's a bit of brainstorming: We'd like the user to be able to configure nginx-ingress to handle these 3 "operation modes", depending on where it's serving requests from.
Mode 1 - direct from WANDesigned for: single hosts, Amazon NLB, GCE NLB, other L4 packet-based LBs doing direct return Doesn't trust incoming
Mode 2 - from a LB speaking X-Forwarded-For headersDesigned for: Amazon ALB, GCE L7 LB, other L7 LBs. Fully trusts incoming
Mode 3. from a LB speaking Proxy Protocol.Designed for: Amazon ELB in TCP/SSL modes (?), GCE TCP LB, GCE SSL LB, haproxy with Proxy Protocol, other TCP proxy LBs. Only trusts Proxy Protocol. Doesn't trust incoming
My proposal for changes
proxy-real-ip-cidrCurrently the behavior of Using headers: If the IP is whitelisted, it trusts XFF (mode 2), otherwise it falls back to real IP (mode 1). That's only for XFF. It still blindly trusts other XF headers no matter the IP... Using proxy protocol: If the IP is whitelisted, it uses the source IP in the ProxyProtocol header. If not, it will still expect a ProxyProtocol header, but ignore the info in it, which is weird. I really can't think of a case where you would actually want a "mixed" mode like this. Your traffic either comes from another LB or directly. Also, if nginx-ingress is behind an LB it shouldn'be exposed to WAN to begin with. Maybe |
My opinion on your proposition @Dirbaio Mode 1 - direct from WANAre Mode 2 - from a LB speaking X-Forwarded-For headersSince I wrote the Mode 3 - from a LB speaking Proxy ProtocolWe can't trust
Sounds good proxy-real-ip-cidrRealIP doesn't work with headers other than Deprecating/dropping |
I added it because the current template does that. It was added in 0755231 without much explanation. @aledbf what was the rationale behind it? is it something we should keep?
I think it's a safer choice to keep it off by default. I'm afraid some backend may break with multiple IPs in the header. Having it off works for any backend, and will show the end-user real IP, which is all you need most of the time. If the user cares about the middle proxy IPs he can always enable it after making sure his backend handles it correctly.
I meant the real http
Yes, it is needed. Imagine a backend receives The value would come from whether nginx is accepting that request with SSL or not. This works fine as long as there are only TCP proxies. This would break with Google SSL Proxy load balancer, for example.
+10000 |
In Azure the load balancer is L4 and so clients arrive with their real IP address. Therefore the X-Forwarder-X headers should not be trusted/used. From reading this issue I gather that the only way to achieve this is to set |
Yes, you're correct. What's the status on this @aledbf @maxlaverse ? If we get consensus on how it should work, I can go ahead and update my PR to move this forward. |
@Dirbaio Thanks for posting the workaround. I was just bit by this, and I am also in favor of a more explicit configmap setting to override this behavior. I'm happy to help with this wherever I can. |
IMO. What about having 4 cases then? Mode 1: Direct from Wan Mode 2: Proxy from Wan Mode 3: from a LB speaking X-Forwarded-For headers Mode 4: from a LB speaking Proxy Protocol For configuration, I would recommend having a single key configuration for setting the mode in which you would like it to act. Having multiple key value pairs that control the mode could confuse things. |
+1. We're after Mode 1. |
For the record, in case anyone wants to fix this: There was a patch for this security issue, but it went ignored: #1851 |
FWIW, running in mode 1 (behind GCE network LB), specifying:
and using a custom
seems to do the trick for me (prevent spoofing via X-Forwarded-*). See https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/custom-template.md and https://github.com/kubernetes/ingress-nginx/blob/master/rootfs/etc/nginx/template/nginx.tmpl |
Follow up to #1309 #1668
nginx-ingress with GCE network load balancer allows spoofing source IP via X-Forwarded-For header, without any way to disable it.
Steps to reproduce:
X-Forwarded-For
header.This setup creates a GCE "Network Load Balancer", which basically hashes TCP packets based on src/dest IP/ports and sends them to a random node unmodified, including the source IP addr. (it's NOT an "active" TCP proxy nor a L7 load balancer)
Note the
externalTrafficPolicy: Local
in the Service. This makes it so the source IP of the incoming TCP connections is preserved: it doesn't go through any NAT in kube-proxy. More info: https://kubernetes.io/docs/tutorials/services/source-ip/#source-ip-for-services-with-typeloadbalancerUsing Proxy Protocol is NOT a solution here: GCE NLB cannot do ProxyProtocol because it doesn't modify packets. The GCE TCP LB can, but I'd rather stick with NLB because it's much simpler (supported by k8s out of the box,
externalTrafficPolicy: Local
saves an extra network hop, and not having an active TCP proxy in the middle another one probably too.)Looking through the template confirms that nginx-ingress must either use incoming X-Forwarded-For OR Proxy Protocol.
Ideally there should be an option to use neither (just use the source IP in the actual raw TCP connection).
The text was updated successfully, but these errors were encountered: