Skip to content
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. #1851

Closed
wants to merge 1 commit into from

Conversation

Dirbaio
Copy link
Contributor

@Dirbaio Dirbaio commented Dec 25, 2017

This PR adds a configmap option use-forwarded-headers to enable/disable trust of incoming X-Forwarded-* headers.

It is set to true by default, which corresponds to the current ingress behavior, so this change is backwards compatible.

Fixes #1815 #1309 #1668

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Dec 25, 2017
@k8s-reviewable
Copy link

This change is Reviewable

@k8s-ci-robot k8s-ci-robot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label Dec 25, 2017
@coveralls
Copy link

Coverage Status

Coverage increased (+0.01%) to 36.775% when pulling ef9587b on Dirbaio:master into fead908 on kubernetes:master.

@aledbf
Copy link
Member

aledbf commented Dec 25, 2017

ping @maxlaverse

@coveralls
Copy link

Coverage Status

Coverage increased (+0.01%) to 36.775% when pulling 38f0c6c on Dirbaio:master into fead908 on kubernetes:master.

@maxlaverse
Copy link
Contributor

maxlaverse commented Dec 28, 2017

Hi @Dirbaio,
I like the idea of an option to disable the RealIP module completely for those who don't need it.
However, have you tested your PR ? The new map blocks look broken to me.

@Dirbaio
Copy link
Contributor Author

Dirbaio commented Dec 28, 2017

Yes! It's all tested, I'm actually using it in production :)

If by "broken" you mean the "dummy" thing, it's the only workaround I could find to assign one variable to another in the http block.

For example, this sets the variable $pass_access_scheme to the value of $scheme unconditionally.

    map 'dummy' $pass_access_scheme {
         default          $scheme;
    }

I agree it's rather ugly, I'd love input on better ways to do this. Some things I've tried:

  • Changing the template everywhere to use the right variable so we don't have to assign any. The issue is that these variables are used in tons of places and the template gets messy and error-prone very fast. Something like this.
proxy_set_header X-Forwarded-Proto      {{ if $cfg.UseForwardedHeaders }}$pass_access_scheme{{else}}$scheme{{end}};
  • Using nginx set directive. Problem is it's not allowed inside http blocks :(
  • Use go template variables that contain the variable: you can't set a variable inside an if and use it outside later.
  • Move the logic to the Go code (so Go passes a value to the template which is $scheme or $pass_access_scheme. I don't think this is a good idea because it makes it less easy to customize nginx-ingress changing only the template.

Also note that the original template before my changes already had one instance of such hack: the map for $the_real_ip

@Dirbaio
Copy link
Contributor Author

Dirbaio commented Dec 28, 2017

Rebased to latest master

@coveralls
Copy link

Coverage Status

Coverage increased (+0.01%) to 36.775% when pulling 6c2b588 on Dirbaio:master into 519f72e on kubernetes:master.

@maxlaverse
Copy link
Contributor

Thanks for the explanation @Dirbaio

As I said I like the idea. However I have the impression this PR makes the code around the X-Forwarded-* headers less readable than it is currently. It's a complex topic since the Nginx Ingress supports many different configurations. As a user and contributor I'd like to see PRs that make the Nginx Ingress behaviors more clear and understandable.

My opinion is that we should spend time on your last comment in #1815 (comment), see what can technically be done and agree on a clear implementation for the X-Forwarded-For headers.

@Dirbaio
Copy link
Contributor Author

Dirbaio commented Dec 28, 2017

This PR implements mostly the behavior in that comment.

  • WAN mode -> use-forwarded-headers=false, use-proxy-protocol=false
  • forwarded header mode -> use-forwarded-headers=true, use-proxy-protocol=false
  • proxy-protocol mode -> use-forwarded-headers=false, use-proxy-protocol=true

Maybe it would be cleaner to replace these two bools with a single option choosing the mode. Something like this?

  • WAN mode -> proxy-mode=direct
  • forwarded header mode -> proxy-mode=forwarded-headers
  • proxy-protocol mode -> proxy-mode=proxy-protocol

Not sure on the naming though. proxy-mode, client-info-mode, client-info-source ... Also, this would remove the possibility of using proxy protocol AND forwarded headers at the same time, but I can't think of any case where you'd want that.

And of course, document it.

What do you think?

@maxlaverse
Copy link
Contributor

I don't have a strong opinion about the naming.
I like the second option a bit more as it makes the notion of "proxy-mode" real, which I believe is easier to understand and document.

I think a mixed setup with forwarded headers and proxy protocol is broken anyway and can't be fixed (see #1489 (comment))

Now that I spent some time reading your proposition, I think those dummy maps are acceptable (if we can't find a cleaner way). At least it makes the proxy configuration easier to understand for users. We should make sure we have the rights comments in the template to make it easier for contributors to understand how the Nginx Controller works with the different "proxy-mode"s.

Let's discuss #1815 (comment) and if we reach an agreement, add documentation here ?

@aledbf
Copy link
Member

aledbf commented Dec 28, 2017

@Dirbaio we need to try to not add new options. I mean

Maybe it would be cleaner to replace these two bools with a single option choosing the mode. >Something like this?
WAN mode -> proxy-mode=direct
forwarded header mode -> proxy-mode=forwarded-headers
proxy-protocol mode -> proxy-mode=proxy-protocol

Mode Description
proxy-protocol is the option use-proxy-protocol
forwarded header default option when use-proxy-protocol is false
WAN is "similar" to compute-full-forwarded-for
headers from connection the changes introduced by this PR

If we add a new option called "proxy-mode" (just an example) we could brake a running ingress controller (overriding a configured option)

@aledbf
Copy link
Member

aledbf commented Dec 28, 2017

I think those dummy maps are acceptable (if we can't find a cleaner way).

There's no other way to do this.

@@ -205,6 +202,26 @@ http {
default $http_x_forwarded_host;
'' $this_host;
}
{{ else }}
map 'dummy' $pass_access_scheme {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment at the start of the else section explaining why this is required

@maxlaverse
Copy link
Contributor

I agree that in general we should always try limiting the addition of new options.
In that case, "proxy-mode" would replace two existing options after a deprecation period. And it would be set in the config-map dedicated to the Ingress.

Don't you think it's really easier to explain how the Nginx Ingress works with those "proxy-modes" @aledbf ? And having the documentation talking about proxy modes that match the configuration flags is straightforward to understand, which should lead to less issues on the topic :)

If we have a proper section in the documentation about those modes including the existing proxy-real-ip-cidr paragraph, that would already be a good improvement.

@aledbf
Copy link
Member

aledbf commented Dec 28, 2017

In that case, "proxy-mode" would replace two existing options after a deprecation period. And it would be set in the config-map dedicated to the Ingress.

Good idea

@aledbf
Copy link
Member

aledbf commented Dec 28, 2017

Don't you think it's really easier to explain how the Nginx Ingress works with those "proxy-modes" @aledbf ? And having the documentation talking about proxy modes that match the configuration flags is straightforward to understand, which should lead to less issues on the topic :)

You think the explanation in #1815 (comment) is the right format?

@maxlaverse
Copy link
Contributor

maxlaverse commented Dec 28, 2017

I think we could start from it yes

The source of the headers is described for every case.
And I like this "designed for" sentence that also contains some real products. It believe it will help users that are not familiar with the topic.

The existing proxy-real-ip-cidr section should be integrated with a clear explanation what it implies regarding the headers and the proxy-modes. Basically proxy-real-ip-cidr should not be set (eq default 0.0.0.0/0) for the modes to work as described. We don't have to remove that option, but we should probably not encourage users to change it imo. If people still want to set it, why not, but it's a mixed mode and implies to know how the RealIP Nginx module behaves.

@fejta-bot
Copy link

Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale.
Stale issues rot after an additional 30d of inactivity and eventually close.

If this issue is safe to close now please do so with /close.

Send feedback to sig-testing, kubernetes/test-infra and/or fejta.
/lifecycle stale

@k8s-ci-robot k8s-ci-robot added the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. label Mar 28, 2018
@fejta-bot
Copy link

Stale issues rot after 30d of inactivity.
Mark the issue as fresh with /remove-lifecycle rotten.
Rotten issues close after an additional 30d of inactivity.

If this issue is safe to close now please do so with /close.

Send feedback to sig-testing, kubernetes/test-infra and/or fejta.
/lifecycle rotten
/remove-lifecycle stale

@k8s-ci-robot k8s-ci-robot added lifecycle/rotten Denotes an issue or PR that has aged beyond stale and will be auto-closed. and removed lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. labels Apr 27, 2018
@aledbf aledbf closed this May 10, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lifecycle/rotten Denotes an issue or PR that has aged beyond stale and will be auto-closed. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants