-
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
Add use-forwarded-headers configmap option. #2616
Conversation
Codecov Report
@@ Coverage Diff @@
## master #2616 +/- ##
==========================================
- Coverage 47.57% 47.56% -0.01%
==========================================
Files 77 77
Lines 5532 5533 +1
==========================================
Hits 2632 2632
- Misses 2560 2562 +2
+ Partials 340 339 -1
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good but requires at least a unit test.
This is indeed a breaking change, and not the behaviour most people will expect (why would my web proxy decide for me whether a header is secure or not?). If this gets approved we should first leave this to |
It has to decide something if the user doesn't. IMO it's better to go with the most conservative option, which is assuming XFF headers aren't secure and not trusting them. If doing breaking changes is not OK then I guess logging a warning is the best we can do, though.. I'll add unit tests and docs soon. |
I'm perfectly with you @Dirbaio, just trying to think about a safe path so that users can be warned in a timely manner before we do change the default (not everybody reads release notes carefully 😉). |
I haven't added the warning when the option is unset though because I'm unsure where to add it :) Help would be appreciated (or we can just not add it?) |
CI failed due to something unrelated (I think). How do I retest? also ping @antoineco PTAL |
I restarted it. |
@@ -596,6 +597,12 @@ _References:_ | |||
|
|||
Sets the addresses on which the server will accept requests instead of *. It should be noted that these addresses must exist in the runtime environment or the controller will crash loop. | |||
|
|||
## use-forwarded-headers | |||
|
|||
If true, nginx passes the incoming `X-Forwarded-*` headers to upstreams. Use this option when nginx is behind another L7 proxy / load balancer that is setting these headers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(nitpick) NGINX is commonly written in capital letters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -222,7 +226,9 @@ http { | |||
'' close; | |||
} | |||
|
|||
map {{ buildForwardedFor $cfg.ForwardedForHeader }} $the_real_ip { | |||
# The following is a sneaky way to do "set $the_real_ip $remote_addr" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather use a Go template comment to avoid writing this message to the config file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this could be useful to someone cat
ing the rendered config from a running container, to help understand what's going on.
The rendered template already contains other similar comments, and this one is rendered just once so it's not like it'd cause much bloat.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, no strong opinion on that one.
Expect(err).NotTo(HaveOccurred()) | ||
defer conn.Close() | ||
|
||
conn.Write([]byte("GET / HTTP/1.1\r\nHost: forwarded-headers\r\nX-Forwarded-Port: 1234\r\nX-Forwarded-Proto: myproto\r\nX-Forwarded-For: 1.2.3.4\r\nX-Forwarded-Host: myhost\r\n\r\n")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the gorequest
package may make this easier to read.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Overall LGTM, however I have a feeling I'm not experienced enough with the NGINX |
@aledbf I need your opinion on 2 things:
|
@antoineco the code you linked is for cmdline flags, but this is a configmap flag, which is pulled dynamically from the Kubernetes API. |
Yeah stupid me, ignore that comment. The next best place would be inside the |
ping @aledbf . Does the PR look OK? Should I add the future change warning? |
@Dirbaio I will take a look at this PR after we release 0.16. Apologies for the delay |
Seems this got ignored again like it happened with #1851 Not great for a security issue :/ |
/assign aledbf Like I said, the PR looks good to me but I'm unable to tell whether these maps are idiomatic. Also pinging @ElvinEfendi |
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: aledbf, Dirbaio The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
@Dirbaio again, apologies for the delay with the review and merge of this PR |
@Dirbaio thanks! |
/hold |
@@ -1047,7 +1069,7 @@ stream { | |||
|
|||
{{ $proxySetHeader }} X-Request-ID $req_id; | |||
{{ $proxySetHeader }} X-Real-IP $the_real_ip; | |||
{{ if $all.Cfg.ComputeFullForwardedFor }} | |||
{{ if and $all.Cfg.UseForwardedHeaders $all.Cfg.ComputeFullForwardedFor }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need another else if
here, something like
else if $all.Cfg.ComputeFullForwardedFor
{ $proxySetHeader }} X-Forwarded-For $proxy_add_x_forwarded_for;
since this is still not using forwarded headers, rather just passing it to upstream
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$full_x_forwarded_for
is the same as $proxy_add_x_forwarded_for
but done "by hand" in a map above.
Maybe this is so it appends the proxy protocol addr instead of $remote_addr
if using proxy protocol, and nginx's $proxy_add_x_forwarded_for
doesn't?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah that makes sense @Dirbaio
Why do you require $all.Cfg.UseForwardedHeaders
to be true
here though?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ComputeFullForwardedFor
has no effect when UseForwardedHeaders = false
.
There are 3 cases to consider:
UseForwardedHeaders = false
: incoming X-Forwarded-For value is discarded and replaced with the source IP nginx-ingress sees.UseForwardedHeaders = true, ComputeFullForwardedFor = false
: incoming X-Forwarded-For value is passed through if present, otherwise it's filled with the source IP nginx-ingress sees.UseForwardedHeaders = true, ComputeFullForwardedFor = true
: incoming X-Forwarded-For value is passed through, appended with the source IP nginx-ingress sees.
For case 3 we use $full_x_forwarded_for
, which has been computed earlier in the template.
For cases 1, 2 we use $the_real_ip
, which earlier in the template has been set to be the appropriate source IP depending on UseForwardedHeaders
Thanks for the PR @Dirbaio! I wonder if we can get rid of
Why would a reverse proxy do this? This seems like a hacky way of satisfying some lazy upstream so that they can get the correct client IP. |
We noticed by chance that the default behavior of ingress-nginx is to trust the X-Forwarded-For header, which caused a security vulnerability for our setup. Is there an issue tracking the change of the default to false for this? I think that it would be much preferable to follow a "secure by default" approach. How many users of ingress-nginx are affected without knowing? |
@schweikert unfortunately that's the case. I think default value for #3333 aims to do so. |
This PR adds a configmap option
use-forwarded-headers
to enable/disable trust of incomingX-Forwarded-*
headers.Setting it to
true
corresponds to the current ingress behavior.It is set to
false
by default. this is a breaking change, but IMO it's the right thing to do if we follow the "secure by default" principle:true
, it might lead to vulnerable installations: If it's set to true in a scenario when it shouldn't (direct port forwarding, L3 load balancers) the config is vulnerable to source IP spoofing. However, since everything appears to work correctly, the user probably won't notice, and will end up vulnerable in production.false
, it'll just cause incorrect behavior if it's wrong. The user is likely to notice he's getting incorrect source IPs and will set it totrue
. At no point the user is vulnerable to spoofing.Fixes #1815 #1309 #1668
Rebase/update of #1851