From 9cb21132a461461c2a60d4293042edc6b8a54f77 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 16 Mar 2022 01:10:56 -0400 Subject: [PATCH 1/3] docs: Sync README.md with default proxy.conf settings --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 239a905..1b1b529 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ You can also use wildcards at the beginning and the end of host name, like `*.ba You can have multiple containers proxied by the same `VIRTUAL_HOST` by adding a `VIRTUAL_PATH` environment variable containing the absolute path to where the container should be mounted. For example with `VIRTUAL_HOST=foo.example.com` and `VIRTUAL_PATH=/api/v2/service`, then requests to http://foo.example.com/api/v2/service will be routed to the container. If you wish to have a container serve the root while other containers serve other paths, give the root container a `VIRTUAL_PATH` of `/`. Unmatched paths will be served by the container at `/` or will return the default nginx error page if no container has been assigned `/`. It is also possible to specify multiple paths with regex locations like `VIRTUAL_PATH=~^/(app1|alternative1)/`. For further details see the nginx documentation on location blocks. This is not compatible with `VIRTUAL_DEST`. -The full request URI will be forwarded to the serving container in the `X-Forwarded-Path` header. +The full request URI will be forwarded to the serving container in the `X-Original-URI` header. **NOTE**: Your application needs to be able to generate links starting with `VIRTUAL_PATH`. This can be achieved by it being natively on this path or having an option to prepend this path. The application does not need to expect this path in the request. @@ -381,7 +381,7 @@ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; -proxy_set_header X-Forwarded-Path $request_uri; +proxy_set_header X-Original-URI $request_uri; # Mitigate httpoxy attack (see README for details) proxy_set_header Proxy ""; From 5f15f045564da8d91332a4e9e3cdccce2be171d5 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 26 Mar 2022 21:10:16 -0400 Subject: [PATCH 2/3] docs: Document the request headers sent to the backend server --- README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1b1b529..564f72e 100644 --- a/README.md +++ b/README.md @@ -361,6 +361,19 @@ docker run -d -p 80:80 -p 443:443 \ You'll need apache2-utils on the machine where you plan to create the htpasswd file. Follow these [instructions](http://httpd.apache.org/docs/2.2/programs/htpasswd.html) +### Headers + +By default, `nginx-proxy` forwards all incoming request headers from the client to the backend server unmodified, with the following exceptions: + + * `Connection`: Set to `upgrade` if the client sets the `Upgrade` header, otherwise set to `close`. (Keep-alive between `nginx-proxy` and the backend server is not supported.) + * `Proxy`: Always removed if present. This prevents attackers from using the so-called [httpoxy attack](http://httpoxy.org). There is no legitimate reason for a client to send this header, and there are many vulnerable languages / platforms (`CVE-2016-5385`, `CVE-2016-5386`, `CVE-2016-5387`, `CVE-2016-5388`, `CVE-2016-1000109`, `CVE-2016-1000110`, `CERT-VU#797896`). + * `X-Real-IP`: Set to the client's IP address. + * `X-Forwarded-For`: The client's IP address is appended to the value provided by the client. (If the client did not provide this header, it is set to the client's IP address.) + * `X-Forwarded-Proto`: If the client did not provide this header, this is set to `http` for plain HTTP connections and `https` for TLS connections. Otherwise, the header is forwarded to the backend server unmodified. + * `X-Forwarded-Ssl`: Set to `on` if the `X-Forwarded-Proto` header sent to the backend server is `https`, otherwise set to `off`. + * `X-Forwarded-Port`: If the client did not provide this header, this is set to the port of the server that accepted the client's request. Otherwise, the header is forwarded to the backend server unmodified. + * `X-Original-URI`: Set to the original request URI. + ### Custom Nginx Configuration If you need to configure Nginx beyond what is possible using environment variables, you can provide custom configuration files on either a proxy-wide or per-`VIRTUAL_HOST` basis. @@ -389,8 +402,6 @@ proxy_set_header Proxy ""; ***NOTE***: If you provide this file it will replace the defaults; you may want to check the .tmpl file to make sure you have all of the needed options. -***NOTE***: The default configuration blocks the `Proxy` HTTP request header from being sent to downstream servers. This prevents attackers from using the so-called [httpoxy attack](http://httpoxy.org). There is no legitimate reason for a client to send this header, and there are many vulnerable languages / platforms (`CVE-2016-5385`, `CVE-2016-5386`, `CVE-2016-5387`, `CVE-2016-5388`, `CVE-2016-1000109`, `CVE-2016-1000110`, `CERT-VU#797896`). - #### Proxy-wide To add settings on a proxy-wide basis, add your configuration file under `/etc/nginx/conf.d` using a name ending in `.conf`. From 8aa00fcea2588eb39565b030c706068a21f9ee33 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 16 Mar 2022 00:59:03 -0400 Subject: [PATCH 3/3] feat: Option to not trust `X-Forwarded-*` headers from clients If header values from a malicious client are passed to the backend server unchecked and unchanged, the client may be able to subvert security checks done by the backend server. --- README.md | 13 +++- app/docker-entrypoint.sh | 7 ++ nginx.tmpl | 5 +- .../certs/web.nginx-proxy.tld.crt | 70 +++++++++++++++++++ .../certs/web.nginx-proxy.tld.key | 27 +++++++ .../test_default.py | 20 ++++++ .../test_default.yml | 16 +++++ .../test_disabled.py | 20 ++++++ .../test_disabled.yml | 18 +++++ .../test_enabled.py | 20 ++++++ .../test_enabled.yml | 18 +++++ 11 files changed, 230 insertions(+), 4 deletions(-) create mode 100644 test/test_trust-downstream-proxy/certs/web.nginx-proxy.tld.crt create mode 100644 test/test_trust-downstream-proxy/certs/web.nginx-proxy.tld.key create mode 100644 test/test_trust-downstream-proxy/test_default.py create mode 100644 test/test_trust-downstream-proxy/test_default.yml create mode 100644 test/test_trust-downstream-proxy/test_disabled.py create mode 100644 test/test_trust-downstream-proxy/test_disabled.yml create mode 100644 test/test_trust-downstream-proxy/test_enabled.py create mode 100644 test/test_trust-downstream-proxy/test_enabled.yml diff --git a/README.md b/README.md index 564f72e..367be6b 100644 --- a/README.md +++ b/README.md @@ -369,11 +369,20 @@ By default, `nginx-proxy` forwards all incoming request headers from the client * `Proxy`: Always removed if present. This prevents attackers from using the so-called [httpoxy attack](http://httpoxy.org). There is no legitimate reason for a client to send this header, and there are many vulnerable languages / platforms (`CVE-2016-5385`, `CVE-2016-5386`, `CVE-2016-5387`, `CVE-2016-5388`, `CVE-2016-1000109`, `CVE-2016-1000110`, `CERT-VU#797896`). * `X-Real-IP`: Set to the client's IP address. * `X-Forwarded-For`: The client's IP address is appended to the value provided by the client. (If the client did not provide this header, it is set to the client's IP address.) - * `X-Forwarded-Proto`: If the client did not provide this header, this is set to `http` for plain HTTP connections and `https` for TLS connections. Otherwise, the header is forwarded to the backend server unmodified. + * `X-Forwarded-Proto`: If the client did not provide this header or if the `TRUST_DOWNSTREAM_PROXY` environment variable is set to `false` (see below), this is set to `http` for plain HTTP connections and `https` for TLS connections. Otherwise, the header is forwarded to the backend server unmodified. * `X-Forwarded-Ssl`: Set to `on` if the `X-Forwarded-Proto` header sent to the backend server is `https`, otherwise set to `off`. - * `X-Forwarded-Port`: If the client did not provide this header, this is set to the port of the server that accepted the client's request. Otherwise, the header is forwarded to the backend server unmodified. + * `X-Forwarded-Port`: If the client did not provide this header or if the `TRUST_DOWNSTREAM_PROXY` environment variable is set to `false` (see below), this is set to the port of the server that accepted the client's request. Otherwise, the header is forwarded to the backend server unmodified. * `X-Original-URI`: Set to the original request URI. +#### Trusting Downstream Proxy Headers + +For legacy compatibility reasons, `nginx-proxy` forwards any client-supplied `X-Forwarded-Proto` (which affects the value of `X-Forwarded-Ssl`) and `X-Forwarded-Port` headers unchecked and unmodified. To prevent malicious clients from spoofing the protocol or port that is perceived by your backend server, you are encouraged to set the `TRUST_DOWNSTREAM_PROXY` value to `false` if: + + * you do not operate a second reverse proxy downstream of `nginx-proxy`, or + * you do operate a second reverse proxy downstream of `nginx-proxy` but that proxy forwards those headers unchecked from untrusted clients. + +The default for `TRUST_DOWNSTREAM_PROXY` may change to `false` in a future version of `nginx-proxy`. If you require it to be enabled, you are encouraged to explicitly set it to `true` to avoid compatibility problems when upgrading. + ### Custom Nginx Configuration If you need to configure Nginx beyond what is possible using environment variables, you can provide custom configuration files on either a proxy-wide or per-`VIRTUAL_HOST` basis. diff --git a/app/docker-entrypoint.sh b/app/docker-entrypoint.sh index 8f4ed7a..0477dd2 100755 --- a/app/docker-entrypoint.sh +++ b/app/docker-entrypoint.sh @@ -109,6 +109,13 @@ if [[ $* == 'forego start -r' ]]; then _resolvers _setup_dhparam + + if [ -z "${TRUST_DOWNSTREAM_PROXY}" ]; then + cat >&2 <<-EOT + Warning: TRUST_DOWNSTREAM_PROXY is not set; defaulting to "true". For security, you should explicitly set TRUST_DOWNSTREAM_PROXY to "false" if there is not a trusted reverse proxy in front of this proxy. + Warning: The default value of TRUST_DOWNSTREAM_PROXY might change to "false" in a future version of nginx-proxy. If you require TRUST_DOWNSTREAM_PROXY to be enabled, explicitly set it to "true". + EOT + fi fi exec "$@" diff --git a/nginx.tmpl b/nginx.tmpl index e8a555d..295af0c 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -6,6 +6,7 @@ {{ $debug_all := $.Env.DEBUG }} {{ $sha1_upstream_name := parseBool (coalesce $.Env.SHA1_UPSTREAM_NAME "false") }} {{ $default_root_response := coalesce $.Env.DEFAULT_ROOT "404" }} +{{ $trust_downstream_proxy := parseBool (coalesce $.Env.TRUST_DOWNSTREAM_PROXY "true") }} {{ define "ssl_policy" }} {{ if eq .ssl_policy "Mozilla-Modern" }} @@ -150,14 +151,14 @@ upstream {{ .Upstream }} { # If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the # scheme used to connect to this server map $http_x_forwarded_proto $proxy_x_forwarded_proto { - default $http_x_forwarded_proto; + default {{ if $trust_downstream_proxy }}$http_x_forwarded_proto{{ else }}$scheme{{ end }}; '' $scheme; } # If we receive X-Forwarded-Port, pass it through; otherwise, pass along the # server port the client connected to map $http_x_forwarded_port $proxy_x_forwarded_port { - default $http_x_forwarded_port; + default {{ if $trust_downstream_proxy }}$http_x_forwarded_port{{ else }}$server_port{{ end }}; '' $server_port; } diff --git a/test/test_trust-downstream-proxy/certs/web.nginx-proxy.tld.crt b/test/test_trust-downstream-proxy/certs/web.nginx-proxy.tld.crt new file mode 100644 index 0000000..aed9349 --- /dev/null +++ b/test/test_trust-downstream-proxy/certs/web.nginx-proxy.tld.crt @@ -0,0 +1,70 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4096 (0x1000) + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld + Validity + Not Before: Jan 13 03:06:39 2017 GMT + Not After : May 31 03:06:39 2044 GMT + Subject: CN=web.nginx-proxy.tld + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:95:56:c7:0d:48:a5:2b:3c:65:49:3f:26:e1:38: + 2b:61:30:56:e4:92:d7:63:e0:eb:ad:ac:f9:33:9b: + b2:31:f1:39:13:0b:e5:43:7b:c5:bd:8a:85:c8:d9: + 3d:d8:ac:71:ba:16:e7:81:96:b2:ab:ae:c6:c0:bd: + be:a7:d1:96:8f:b2:9b:df:ba:f9:4d:a1:3b:7e:21: + 4a:cd:b6:45:f9:6d:79:50:bf:24:8f:c1:6b:c1:09: + 19:5b:62:cb:96:e8:04:14:20:e8:d4:16:62:6a:f2: + 37:c1:96:e2:9d:53:05:0b:52:1d:e7:68:92:db:8b: + 36:68:cd:8d:5b:02:ff:12:f0:ac:5d:0c:c4:e0:7a: + 55:a2:49:60:9f:ff:47:1f:52:73:55:4d:d4:f2:d1: + 62:a2:f4:50:9d:c9:f6:f1:43:b3:dc:57:e1:31:76: + b4:e0:a4:69:7e:f2:6d:34:ae:b9:8d:74:26:7b:d9: + f6:07:00:ef:4b:36:61:b3:ef:7a:a1:36:3a:b6:d0: + 9e:f8:b8:a9:0d:4c:30:a2:ed:eb:ab:6b:eb:2e:e2: + 0b:28:be:f7:04:b1:e9:e0:84:d6:5d:31:77:7c:dc: + d2:1f:d4:1d:71:6f:6f:6c:6d:1b:bf:31:e2:5b:c3: + 52:d0:14:fc:8b:fb:45:ea:41:ec:ca:c7:3b:67:12: + c4:df + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:web.nginx-proxy.tld + Signature Algorithm: sha256WithRSAEncryption + 4e:48:7d:81:66:ba:2f:50:3d:24:42:61:3f:1f:de:cf:ec:1b: + 1b:bd:0a:67:b6:62:c8:79:9d:31:a0:fd:a9:61:ce:ff:69:bf: + 0e:f4:f7:e6:15:2b:b0:f0:e4:f2:f4:d2:8f:74:02:b1:1e:4a: + a8:6f:26:0a:77:32:29:cf:dc:b5:61:82:3e:58:47:61:92:f0: + 0c:20:25:f8:41:4d:34:09:44:bc:39:9e:aa:82:06:83:13:8b: + 1e:2c:3d:cf:cd:1a:f7:77:39:38:e0:a3:a7:f3:09:da:02:8d: + 73:75:38:b4:dd:24:a7:f9:03:db:98:c6:88:54:87:dc:e0:65: + 4c:95:c5:39:9c:00:30:dc:f0:d3:2c:19:ca:f1:f4:6c:c6:d9: + b5:c4:4a:c7:bc:a1:2e:88:7b:b5:33:d0:ff:fb:48:5e:3e:29: + fa:58:e5:03:de:d8:17:de:ed:96:fc:7e:1f:fe:98:f6:be:99: + 38:87:51:c0:d3:b7:9a:0f:26:92:e5:53:1b:d6:25:4c:ac:48: + f3:29:fc:74:64:9d:07:6a:25:57:24:aa:a7:70:fa:8f:6c:a7: + 2b:b7:9d:81:46:10:32:93:b9:45:6d:0f:16:18:b2:21:1f:f3: + 30:24:62:3f:e1:6c:07:1d:71:28:cb:4c:bb:f5:39:05:f9:b2: + 5b:a0:05:1b +-----BEGIN CERTIFICATE----- +MIIC+zCCAeOgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp +bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs +ZDAeFw0xNzAxMTMwMzA2MzlaFw00NDA1MzEwMzA2MzlaMB4xHDAaBgNVBAMME3dl +Yi5uZ2lueC1wcm94eS50bGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCVVscNSKUrPGVJPybhOCthMFbkktdj4OutrPkzm7Ix8TkTC+VDe8W9ioXI2T3Y +rHG6FueBlrKrrsbAvb6n0ZaPspvfuvlNoTt+IUrNtkX5bXlQvySPwWvBCRlbYsuW +6AQUIOjUFmJq8jfBluKdUwULUh3naJLbizZozY1bAv8S8KxdDMTgelWiSWCf/0cf +UnNVTdTy0WKi9FCdyfbxQ7PcV+ExdrTgpGl+8m00rrmNdCZ72fYHAO9LNmGz73qh +Njq20J74uKkNTDCi7eura+su4gsovvcEsenghNZdMXd83NIf1B1xb29sbRu/MeJb +w1LQFPyL+0XqQezKxztnEsTfAgMBAAGjIjAgMB4GA1UdEQQXMBWCE3dlYi5uZ2lu +eC1wcm94eS50bGQwDQYJKoZIhvcNAQELBQADggEBAE5IfYFmui9QPSRCYT8f3s/s +Gxu9Cme2Ysh5nTGg/alhzv9pvw709+YVK7Dw5PL00o90ArEeSqhvJgp3MinP3LVh +gj5YR2GS8AwgJfhBTTQJRLw5nqqCBoMTix4sPc/NGvd3OTjgo6fzCdoCjXN1OLTd +JKf5A9uYxohUh9zgZUyVxTmcADDc8NMsGcrx9GzG2bXESse8oS6Ie7Uz0P/7SF4+ +KfpY5QPe2Bfe7Zb8fh/+mPa+mTiHUcDTt5oPJpLlUxvWJUysSPMp/HRknQdqJVck +qqdw+o9spyu3nYFGEDKTuUVtDxYYsiEf8zAkYj/hbAcdcSjLTLv1OQX5slugBRs= +-----END CERTIFICATE----- diff --git a/test/test_trust-downstream-proxy/certs/web.nginx-proxy.tld.key b/test/test_trust-downstream-proxy/certs/web.nginx-proxy.tld.key new file mode 100644 index 0000000..8365ecf --- /dev/null +++ b/test/test_trust-downstream-proxy/certs/web.nginx-proxy.tld.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAlVbHDUilKzxlST8m4TgrYTBW5JLXY+Drraz5M5uyMfE5Ewvl +Q3vFvYqFyNk92KxxuhbngZayq67GwL2+p9GWj7Kb37r5TaE7fiFKzbZF+W15UL8k +j8FrwQkZW2LLlugEFCDo1BZiavI3wZbinVMFC1Id52iS24s2aM2NWwL/EvCsXQzE +4HpVoklgn/9HH1JzVU3U8tFiovRQncn28UOz3FfhMXa04KRpfvJtNK65jXQme9n2 +BwDvSzZhs+96oTY6ttCe+LipDUwwou3rq2vrLuILKL73BLHp4ITWXTF3fNzSH9Qd +cW9vbG0bvzHiW8NS0BT8i/tF6kHsysc7ZxLE3wIDAQABAoIBAEmK7IecKMq7+V0y +3mC3GpXICmKR9cRX9XgX4LkLiZuSoXrBtuuevmhzGSMp6I0VjwQHV4a3wdFORs6Q +Ip3eVvj5Ck4Jc9BJAFVC6+WWR6tnwACFwOmSZRAw/O3GH2B3bdrDwiT/yQPFuLN7 +LKoxQiCrFdLp6rh3PBosb9pMBXU7k/HUazIdgmSKg6/JIoo/4Gwyid04TF/4MI2l +RscxtP5/ANtS8VgwBEqhgdafRJ4KnLEpgvswgIQvUKmduVhZQlzd0LMY8FbhKVqz +Utg8gsXaTyH6df/nmgUIInxLMz/MKPnMkv99fS6Sp/hvYlGpLZFWBJ6unMq3lKEr +LMbHfIECgYEAxB+5QWdVqG2r9loJlf8eeuNeMPml4P8Jmi5RKyJC7Cww6DMlMxOS +78ZJfl4b3ZrWuyvhjOfX/aTq7kQaF1BI9o3KJBH8k6EtO4gI8KeNmDONyQk9zsrn +ru8Zwr7hVbAo8fCXxCnmPzhDLsYg6f3BVOsQWoX2SFYKZ1GvkPfIReECgYEAwu6G +qtgFb57Vim10ecfWGM6vrPxvyfqP+zlH/p4nR+aQ+2sFbt27D0B1byWBRZe4KQyw +Vq6XiQ09Fk6MJr8E8iAr9GXPPHcqlYI6bbNc6YOP3jVSKut0tQdTUOHll4kYIY+h +RS3VA3+BA//ADpWpywu+7RZRbaIECA+U2a224r8CgYB5PCMIixgoRaNHZeEHF+1/ +iY1wOOKRcxY8eOU0BLnZxHd3EiasrCzoi2pi80nGczDKAxYqRCcAZDHVl8OJJdf0 +kTGjmnrHx5pucmkUWn7s1vGOlGfgrQ0K1kLWX6hrj7m/1Tn7yOrLqbvd7hvqiTI5 +jBVP3/+eN5G2zIf61TC4AQKBgCX2Q92jojNhsF58AHHy+/vqzIWYx8CC/mVDe4TX +kfjLqzJ7XhyAK/zFZdlWaX1/FYtRAEpxR+uV226rr1mgW7s3jrfS1/ADmRRyvyQ8 +CP0k9PCmW7EmF51lptEanRbMyRlIGnUZfuFmhF6eAO4WMXHsgKs1bHg4VCapuihG +T1aLAoGACRGn1UxFuBGqtsh2zhhsBZE7GvXKJSk/eP7QJeEXUNpNjCpgm8kIZM5K +GorpL7PSB8mwVlDl18TpMm3P7nz6YkJYte+HdjO7pg59H39Uvtg3tZnIrFxNxVNb +YF62/yHfk2AyTgjQZQUSmDS84jq1zUK4oS90lxr+u8qwELTniMs= +-----END RSA PRIVATE KEY----- diff --git a/test/test_trust-downstream-proxy/test_default.py b/test/test_trust-downstream-proxy/test_default.py new file mode 100644 index 0000000..456d07a --- /dev/null +++ b/test/test_trust-downstream-proxy/test_default.py @@ -0,0 +1,20 @@ +import pytest +import re + + +@pytest.mark.parametrize('url,header,input,want', [ + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'http'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'f00'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'https'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'f00'), + + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '80'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '1234'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '443'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '1234'), +]) +def test_downstream_proxy_header(docker_compose, nginxproxy, url, header, input, want): + kwargs = {} if input is None else {'headers': {header: input}} + r = nginxproxy.get(url, **kwargs) + assert r.status_code == 200 + assert re.search(fr'(?m)^(?i:{re.escape(header)}): {re.escape(want)}$', r.text) diff --git a/test/test_trust-downstream-proxy/test_default.yml b/test/test_trust-downstream-proxy/test_default.yml new file mode 100644 index 0000000..c420d80 --- /dev/null +++ b/test/test_trust-downstream-proxy/test_default.yml @@ -0,0 +1,16 @@ +web: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: web.nginx-proxy.tld + HTTPS_METHOD: noredirect + + +sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro + - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro diff --git a/test/test_trust-downstream-proxy/test_disabled.py b/test/test_trust-downstream-proxy/test_disabled.py new file mode 100644 index 0000000..bc9684f --- /dev/null +++ b/test/test_trust-downstream-proxy/test_disabled.py @@ -0,0 +1,20 @@ +import pytest +import re + + +@pytest.mark.parametrize('url,header,input,want', [ + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'http'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'http'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'https'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'https'), + + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '80'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '80'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '443'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '443'), +]) +def test_downstream_proxy_header(docker_compose, nginxproxy, url, header, input, want): + kwargs = {} if input is None else {'headers': {header: input}} + r = nginxproxy.get(url, **kwargs) + assert r.status_code == 200 + assert re.search(fr'(?m)^(?i:{re.escape(header)}): {re.escape(want)}$', r.text) diff --git a/test/test_trust-downstream-proxy/test_disabled.yml b/test/test_trust-downstream-proxy/test_disabled.yml new file mode 100644 index 0000000..860e5f9 --- /dev/null +++ b/test/test_trust-downstream-proxy/test_disabled.yml @@ -0,0 +1,18 @@ +web: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: web.nginx-proxy.tld + HTTPS_METHOD: noredirect + + +sut: + image: nginxproxy/nginx-proxy:test + environment: + TRUST_DOWNSTREAM_PROXY: "false" + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro + - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro diff --git a/test/test_trust-downstream-proxy/test_enabled.py b/test/test_trust-downstream-proxy/test_enabled.py new file mode 100644 index 0000000..456d07a --- /dev/null +++ b/test/test_trust-downstream-proxy/test_enabled.py @@ -0,0 +1,20 @@ +import pytest +import re + + +@pytest.mark.parametrize('url,header,input,want', [ + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'http'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'f00'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'https'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'f00'), + + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '80'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '1234'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '443'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '1234'), +]) +def test_downstream_proxy_header(docker_compose, nginxproxy, url, header, input, want): + kwargs = {} if input is None else {'headers': {header: input}} + r = nginxproxy.get(url, **kwargs) + assert r.status_code == 200 + assert re.search(fr'(?m)^(?i:{re.escape(header)}): {re.escape(want)}$', r.text) diff --git a/test/test_trust-downstream-proxy/test_enabled.yml b/test/test_trust-downstream-proxy/test_enabled.yml new file mode 100644 index 0000000..7b2a8de --- /dev/null +++ b/test/test_trust-downstream-proxy/test_enabled.yml @@ -0,0 +1,18 @@ +web: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: web.nginx-proxy.tld + HTTPS_METHOD: noredirect + + +sut: + image: nginxproxy/nginx-proxy:test + environment: + TRUST_DOWNSTREAM_PROXY: "true" + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro + - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro