-
Notifications
You must be signed in to change notification settings - Fork 1
IBX-11181: Filtered client-supplied X-Forwarded-* headers in Varnish VCL #13
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
Open
vidarl
wants to merge
2
commits into
5.0
Choose a base branch
from
IBX-11181-Trusted_Proxies_is_not_set_on_Ibexa_Cloud
base: 5.0
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| # Image for running the varnishtest suite in tests/varnish/. | ||
| # | ||
| # Mirrors doc/docker/Dockerfile-varnish from ibexa/docker. It has to be Varnish 6.0LTS specifically: | ||
| # this VCL returns "miss" from vcl_hit, which 6.5 and later reject. The xkey vmod is not packaged | ||
| # for 6.0LTS, so varnish-modules is built from source, as in the image this mirrors. | ||
|
|
||
| FROM debian:bullseye-slim | ||
|
|
||
| ENV DEBIAN_FRONTEND=noninteractive | ||
|
|
||
| ARG PACKAGECLOUD_URL=https://packagecloud.io/install/repositories/varnishcache/varnish60lts/script.deb.sh | ||
| ARG VARNISH_MODULES_VERSION=0.15.0 | ||
|
|
||
| RUN set -xe \ | ||
| && buildDeps=" \ | ||
| make \ | ||
| automake \ | ||
| autotools-dev \ | ||
| libedit-dev \ | ||
| libjemalloc-dev \ | ||
| libncurses-dev \ | ||
| libpcre3-dev \ | ||
| libtool \ | ||
| pkg-config \ | ||
| python3-docutils \ | ||
| varnish-dev=6.0.12-1~bullseye \ | ||
| " \ | ||
| && apt-get update -q -y \ | ||
| && apt-get install -q -y --no-install-recommends ca-certificates curl \ | ||
| \ | ||
| && curl -s ${PACKAGECLOUD_URL} | bash \ | ||
| && apt-get install -q -y --allow-unauthenticated --no-install-recommends varnish=6.0.12-1~bullseye $buildDeps \ | ||
| \ | ||
| && curl -A "Docker" -o /tmp/varnish-modules.tar.gz -D - -L -s https://github.com/varnish/varnish-modules/archive/refs/tags/${VARNISH_MODULES_VERSION}.tar.gz \ | ||
| && tar zxpf /tmp/varnish-modules.tar.gz -C /tmp/ \ | ||
| && cd /tmp/varnish-modules-${VARNISH_MODULES_VERSION} \ | ||
| && ./bootstrap \ | ||
| && ./configure \ | ||
| && make \ | ||
| && make install \ | ||
| && rm -f /tmp/varnish-modules.tar.gz && rm -Rf /tmp/varnish-modules-${VARNISH_MODULES_VERSION} \ | ||
| \ | ||
| && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $buildDeps \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| Varnish VCL tests | ||
| ================= | ||
|
|
||
| `varnishtest` cases for `resources/upsun/common/5.0/.platform/varnish.vcl`, the VCL shipped to | ||
| Upsun / Ibexa Cloud installations. | ||
|
|
||
| They load the real VCL file into a real Varnish and assert on the request the **backend** receives, | ||
| which is where the reverse proxy header filtering in `vcl_recv` can be observed. | ||
|
|
||
| Cases | ||
| ----- | ||
|
|
||
| | Case | Scenario | Asserts | | ||
| |---|---|---| | ||
| | `no-cdn.vtc` | request straight through the Ibexa Cloud router | the client supplied part of `X-Forwarded-For` is dropped and the header is rebuilt from `X-Client-IP`; `X-Forwarded-Host` / `-Prefix` / `Forwarded` are stripped; `X-Forwarded-Proto` is kept | | ||
| | `via-cdn.vtc` | request arriving through a supported CDN | `X-Forwarded-For`, `X-Client-IP` and `Client-Cdn` are kept as the router left them, so Fastly detection still works | | ||
| | `no-client-ip.vtc` | no `X-Client-IP`, so the request did not come through the router | `X-Forwarded-For` is dropped entirely rather than trusted | | ||
|
|
||
| The header behaviour being relied on is documented at | ||
| <https://fixed.docs.upsun.com/development/headers.html>. | ||
|
|
||
| Running them | ||
| ------------ | ||
|
|
||
| ```bash | ||
| docker build -t ibexa-varnishtest:6.0 tests/varnish | ||
| IMAGE=ibexa-varnishtest:6.0 tests/varnish/run.sh | ||
| ``` | ||
|
|
||
| Notes | ||
| ----- | ||
|
|
||
| - The image has to be **Varnish 6.0LTS specifically**. This VCL returns `miss` from `vcl_hit`, which | ||
| 6.5 and later reject, and the xkey vmod it imports is not packaged for 6.0LTS — hence the source | ||
| build in `Dockerfile`, mirroring `doc/docker/Dockerfile-varnish` in `ibexa/docker`. | ||
| - The VCL cannot be loaded as it stands: Platform.sh supplies the VCL version declaration, the `std` | ||
| import and the `app.backend()` director. `run.sh` prepends the first two and swaps the director for | ||
| a stub, so the shipped file itself is what gets tested. | ||
| - The backend listens on a fixed port (9081) so the stub can point at it. | ||
| - Each case uses its own URL and its own Varnish instance: `X-Forwarded-*` is not part of the cache | ||
| key, so cases sharing a cache would be served each other's responses. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| varnishtest "Without a CDN, X-Forwarded-For is rebuilt from the router supplied X-Client-IP" | ||
|
|
||
| # The Ibexa Cloud router only *appends* the real client IP to whatever the client sent in | ||
| # X-Forwarded-For, so every leading entry is client controlled and must not survive. | ||
| # See https://fixed.docs.upsun.com/development/headers.html | ||
|
|
||
| server s1 -listen "127.0.0.1:9081" { | ||
| rxreq | ||
|
|
||
| # Client supplied prefix dropped: only the router's own value is left. | ||
| expect req.http.X-Forwarded-For == "203.0.113.9" | ||
|
|
||
| # Not filtered by the router, so the VCL strips them. | ||
| expect req.http.X-Forwarded-Host == <undef> | ||
| expect req.http.X-Forwarded-Prefix == <undef> | ||
| expect req.http.Forwarded == <undef> | ||
|
|
||
| # Router authoritative, kept as is. | ||
| expect req.http.X-Client-IP == "203.0.113.9" | ||
| expect req.http.X-Forwarded-Proto == "https" | ||
| expect req.http.X-Forwarded-Port == "443" | ||
|
|
||
| txresp | ||
| } -start | ||
|
|
||
| varnish v1 -arg "-f /etc/varnish/default.vcl" -start | ||
|
|
||
| client c1 { | ||
| txreq -url "/no-cdn" \ | ||
| -hdr "X-Forwarded-For: 6.6.6.6, 203.0.113.9" \ | ||
| -hdr "X-Client-IP: 203.0.113.9" \ | ||
| -hdr "X-Forwarded-Proto: https" \ | ||
| -hdr "X-Forwarded-Host: evil.example" \ | ||
| -hdr "X-Forwarded-Prefix: /admin" \ | ||
| -hdr "Forwarded: for=6.6.6.6;host=evil.example;proto=https" | ||
| rxresp | ||
| expect resp.status == 200 | ||
| } -run |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| varnishtest "Without X-Client-IP there is nothing trustworthy, so X-Forwarded-For is dropped" | ||
|
|
||
| # X-Client-IP is always set by the Ibexa Cloud router. If it is absent the request did not come | ||
| # through the router, so the client supplied X-Forwarded-For must not be handed to the application. | ||
|
|
||
| server s1 -listen "127.0.0.1:9081" { | ||
| rxreq | ||
|
|
||
| expect req.http.X-Forwarded-For == <undef> | ||
| expect req.http.X-Client-IP == <undef> | ||
|
|
||
| expect req.http.X-Forwarded-Host == <undef> | ||
| expect req.http.X-Forwarded-Prefix == <undef> | ||
| expect req.http.Forwarded == <undef> | ||
|
|
||
| txresp | ||
| } -start | ||
|
|
||
| varnish v1 -arg "-f /etc/varnish/default.vcl" -start | ||
|
|
||
| client c1 { | ||
| txreq -url "/no-client-ip" \ | ||
| -hdr "X-Forwarded-For: 6.6.6.6" \ | ||
| -hdr "X-Forwarded-Host: evil.example" \ | ||
| -hdr "X-Forwarded-Prefix: /admin" \ | ||
| -hdr "Forwarded: for=6.6.6.6;host=evil.example" | ||
| rxresp | ||
| expect resp.status == 200 | ||
| } -run |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| #!/bin/bash | ||
| # | ||
| # Runs the varnishtest suite for the Platform.sh / Ibexa Cloud VCL. | ||
| # | ||
| # That VCL is not loadable as it stands: Platform.sh supplies the VCL version declaration, the std | ||
| # import and the app.backend() director. This script prepends the first two and swaps the director | ||
| # for a stub pointing at the test backend, then loads the resulting file into a real Varnish, so | ||
| # what is tested is the shipped file rather than a copy of it. | ||
| # | ||
| # Usage: | ||
| # docker build -t ibexa-varnishtest:7 tests/varnish | ||
| # IMAGE=ibexa-varnishtest:7 tests/varnish/run.sh | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| TESTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| ROOTDIR="$(cd "$TESTDIR/../.." && pwd)" | ||
| VCL="${VCL:-$ROOTDIR/resources/upsun/common/5.0/.platform/varnish.vcl}" | ||
| IMAGE="${IMAGE:-ibexa-varnishtest:7}" | ||
|
|
||
| WORKDIR="$(mktemp -d)" | ||
| trap 'rm -rf "$WORKDIR"' EXIT | ||
|
|
||
| { | ||
| echo "// Prologue supplied by Platform.sh at runtime, added here so the file can be loaded." | ||
| echo "vcl 4.1;" | ||
| echo "import std;" | ||
| echo "backend stub { .host = \"127.0.0.1\"; .port = \"9081\"; }" | ||
| sed 's/app\.backend()/stub/' "$VCL" | ||
| } > "$WORKDIR/default.vcl" | ||
|
|
||
| echo "==> $(basename "$(dirname "$(dirname "$VCL")")")/$(basename "$VCL") (${IMAGE})" | ||
|
|
||
| for vtc in "$TESTDIR"/*.vtc; do | ||
| echo "--> $(basename "$vtc")" | ||
| docker run --rm \ | ||
| -v "$WORKDIR/default.vcl:/etc/varnish/default.vcl:ro" \ | ||
| -v "$vtc:/case.vtc:ro" \ | ||
| --entrypoint varnishtest "$IMAGE" /case.vtc | ||
| done | ||
|
|
||
| echo "All varnishtest cases passed." |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| varnishtest "Behind a supported CDN, the router supplied end client IP and Client-Cdn are kept" | ||
|
|
||
| # When the request arrives via a CDN the router replaces X-Forwarded-For with the end client IP and | ||
| # sets Client-Cdn, discarding whatever the client sent for either. Ibexa DXP uses Client-Cdn to | ||
| # detect Fastly, so it has to reach the application. | ||
| # See https://fixed.docs.upsun.com/development/headers.html | ||
|
|
||
| server s1 -listen "127.0.0.1:9081" { | ||
| rxreq | ||
|
|
||
| expect req.http.X-Forwarded-For == "198.51.100.7" | ||
| expect req.http.X-Client-IP == "198.51.100.7" | ||
| expect req.http.Client-Cdn == "fastly" | ||
|
|
||
| expect req.http.X-Forwarded-Host == <undef> | ||
| expect req.http.X-Forwarded-Prefix == <undef> | ||
| expect req.http.Forwarded == <undef> | ||
|
|
||
| expect req.http.X-Forwarded-Proto == "https" | ||
| expect req.http.X-Forwarded-Port == "443" | ||
|
|
||
| txresp | ||
| } -start | ||
|
|
||
| varnish v1 -arg "-f /etc/varnish/default.vcl" -start | ||
|
|
||
| client c1 { | ||
| txreq -url "/via-cdn" \ | ||
| -hdr "X-Forwarded-For: 198.51.100.7" \ | ||
| -hdr "X-Client-IP: 198.51.100.7" \ | ||
| -hdr "Client-Cdn: fastly" \ | ||
| -hdr "X-Forwarded-Proto: https" \ | ||
| -hdr "X-Forwarded-Host: evil.example" | ||
| rxresp | ||
| expect resp.status == 200 | ||
| } -run |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
@micszo
I need to include new Dockerfile for varnish here ( and in post-install too) which is almost carbon copy of https://github.com/ibexa/docker/blob/v4.6.31/docker/Dockerfile-varnish
I suggest we change the structure of the varnish image in order to make it more general and re-usable. However, that would imply a BC break so not sure if we can do it before 6.0, or if this docker files are "supported" and BC guaranteed .
What I suggest is: In
ibexa/dockerwe could:COPYlines ofdefault.vclandparameters.vcl- So this is not part of the image itselfvarnish.ymlcontain the basic common configuration needed for varnish containervarnish.ymlusesimage:instead ofbuild:varnish7.yml( and in near futurevarnish9,yml) so that they are overlays for varnish.yml, only containing version specific information ( including volumes to mount the vcls an referencing varnish7 image )ibexa/cloudandibeax/post-installcan then create varnish container without duplicated dockerfileIt is a lot of things to do for just removing some duplicated code though ( but keep in mind that it is not only here in
ibexa/cloudandibeax/post-installwe get rid of duplicated code). TheDockerfile-varnish*andvarnish*.ymlfiles inibexa/dockeralso contains a lot of duplicated codeBC breaks are:
image:instead ofbuildIf varnish files doc/docker are used as-is, no problem. However, this might break local workflows and customizations.