ingress-nginx: Problem with HTTPS, CloudFlare and X-Forwarded-Port header
NGINX Ingress controller version: 0.40.2
Kubernetes version (use kubectl version
):
Client Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.0", GitCommit:"9e991415386e4cf155a24b1da15becaa390438d8", GitTreeState:"clean", BuildDate:"2020-03-26T06:16:15Z", GoVersion:"go1.14", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"16+", GitVersion:"v1.16.13-gke.401", GitCommit:"eb94c181eea5290e9da1238db02cfef263542f5f", GitTreeState:"clean", BuildDate:"2020-09-09T00:57:35Z", GoVersion:"go1.13.9b4", Compiler:"gc", Platform:"linux/amd64"}
Environment: GKE
- Cloud provider or hardware configuration: GKE
- OS (e.g. from /etc/os-release): GKE
- Kernel (e.g.
uname -a
): GKE - Install tools: Kustomize
- Others: CloudFlare Proxy mode
What happened:
Hi, I have this setup
CloudFlare with HTTPS and Proxy mode => GKE nginx-ingress-controller in HTTP => myApp.
When I got to my website in HTTPS mode, myApp receives this request :
GET / HTTP/1.1
Host: myApp.mydomain.com
X-Request-ID: XXXXXXX
X-Real-IP: myIP
X-Forwarded-For: myIP
X-Forwarded-Host: myApp.mydomain.com
X-Forwarded-Port: 80
X-Forwarded-Proto: https
X-Scheme: https
X-Original-Forwarded-For: myIP
So, because of X-Forwarded-Port: 80
, myApp thinks that original request was in HTTPS BUT on port 80 đŚ and then, links generated on the response are not OK.
What you expected to happen:
I would like to receive a X-Forwarded-Port: 443
header.
How to reproduce it: My conf :
body-size: "20m"
# Cloudflare IP ranges which you can find online
proxy-real-ip-cidr: "173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/12,172.64.0.0/13,131.0.72.0/22,2400:cb00::/32,2606:4700::/32,2803:f800::/32,2405:b500::/32,2405:8100::/32,2a06:98c0::/29,2c0f:f248::/32"
use-forwarded-headers: "true"
forwarded-for-header: "CF-Connecting-IP"
Anything else we need to know:
I canât verify the original request (and so, headers added by CloudFlare) which arrives in nginx-ingress-controller, as I donât have tcpdump installed on this container. If you know how to dump the original request , I could dump it.
/kind bug
About this issue
- Original URL
- State: open
- Created 4 years ago
- Reactions: 12
- Comments: 48 (15 by maintainers)
Here is illustration of a full working solution with Helm and
ingress-nginx
chart version 4.0.13 / K8s 1.21.First, add new template,
ingress-nginx/templates/controller-configmap-lua.yaml
:Then add custom values.yaml:
Your upstream apps should now see
X-Forwarded-Proto
-> httpsX-Forwarded-Scheme
-> httpsX-Forwarded-Port
-> 443Note thereâs a slight defect in this setup, in that values.yaml hardcodes the configmap name even though that name is configurable through the template. (It could just be hardcoded there also.)
having the same problem here (and with keycloak too)⌠the solution still this this âcustom pluginâ, really?
This problem is driving me nuts. Any solution yet?
Changing the value of the header
X-Forwarded-Port
without using a custom template can be done with a plugin. https://github.com/kubernetes/ingress-nginx/tree/master/rootfs/etc/nginx/lua/pluginsThe content of such a thing is trivial:
The condition to change the variable can check for any other header (like limiting the change to a particular host) Using a configmap is possible to mount the plugin as a file https://github.com/kubernetes/ingress-nginx/blob/master/charts/ingress-nginx/values.yaml#L396-L404
Is there any plan for this error? X-Forwarded-Port should be configurable from the annotations. I saw that the protocol and the scheme can be set with the annotations, but donât know why the port is missed out. Currently we have to hardcode the forward header port within the template file. It would be not friendly with the mixed http and https traffic.
@aledbf
Slapping the word âtrivialâ on something doesnât make it trivial. Asking people to write a Lua plugin is not trivial nor should it be necessary to set a single proxy header for an upstream app.
Just to add a bit to this, using the bitnami chart, this is what we did:
I just wanted to mention that with the most recent ingress-nginx helm chart this solution needs to be modified to work correctly. In âvalues.yamlâ
plugins: "rewrite_fwd_headers"
needs to be a child ofcontroller.config
. Thanks @brsolomon-deloitte for this workaround!Hi !
I found a way to do a tcpdump in nginx-ingress-controllers.
CloudFlare doesnât send a X-Forwarded-Port Header.
I think this is related to this : https://github.com/kubernetes/ingress-nginx/blob/fb6a03ffb42cfbf682c3c7f400f46fb4802caa1c/rootfs/etc/nginx/template/nginx.tmpl#L1123
This variable is set to the server port.
More critical is that I think this variable is not overwritable in general
server-snippet
nor in annotation in the Ingress.for example, nginx.conf when I added this variable to annotation :
@brsolomon-deloitte thanks this is working fine in the newer 4.0.19 chart. The plugins didnât seem to load unless i explicitly set the plugins in the controllers configmap.
From what i can see by browsing the nginx.conf generated, This issue seems to arise because all the X-Forwarded headers are set after the server/configuration snippet. Would moving these X-Forwarded header definition above those definitions solve them?
Still exists as of most recent chart/controller (chart 4.0.13). It is virtually impossible to set
X-Forwarded-Proto
for upstream apps that need to know the original client made an HTTPS request.Hi @tpoindessous @kolorful @Uysim, can you guys can confirm that the issue still exists? Also with newer versions of ingress-nginx?
@toredash if you use a snippet to set the
X-Forwarded-Port
header it ends up appending instead of replacing.Ideally if the upstream loadbalancer is not sending an
X-Forwarded-Port
header and ingress-nginx is configured to use-forwarded-headers then either it would 1) not send anX-Forwarded-Port
at all or 2) derive theX-Forwarded-Port
from theX-Forwarded-Proto
. Right now it is sending anX-Forwarded-Port
that is the port NGINX itself is listening on, which means the resultingX-Forwarded-*
headers are a mixture of NGINX and the upstream loadbalancer.I stumbled into this issue while troubleshooting the closely related problem. We use custom SSL port 5443 for ingress-controller instead of standard 443, but ingress-nginx always sends
X-Forwarded-Port: 443
to our backend. Sad thing is that even sending this header from the client to nginx doesnât help, it always returns a constant 443 value, regardless of $server_port. I believe the problem is in the following part of Lua code: https://github.com/kubernetes/ingress-nginx/blob/6c729e9cc76ca33ecd1b33c36b931c0aa27aa34f/rootfs/etc/nginx/lua/lua_ingress.lua#L168-L169I tried to comprehend this code but I really donât understand why the value is set to
443
and not toconfig.listen_ports.https
(or left as is, because it is already set to the proper value at line 163).When I tried to play with nginx.conf template on a live server, I figured out these things:
$server_port
5443
$pass_server_port
5443
$pass_port
443
As others already mentioned thereâs no way how to override this value by configuration.
Any help would be appreciated.
@Dohbedoh if there is a way to override or set those headers that would work for me.