Files
keycloak-pattern/deploy/lab/scripts/measure-proxy-headers.sh
T
2026-09-03 11:46:56 +09:00

43 lines
1.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# Measure what the nginx -> Traefik chain actually delivers to the application.
#
# docs/reverse-proxy-headers.md documents a single-hop nginx contract. The lab
# runs two hops, so the forwarded headers are measured rather than assumed.
# Run from anywhere that can resolve the lab hostnames.
#
# ./deploy/lab/scripts/measure-proxy-headers.sh
set -euo pipefail
HOST="${HOST:-app1.hyeonworks.com}"
URL="https://${HOST}/api/echo"
jqf() {
if command -v jq >/dev/null 2>&1; then jq "$@"; else python3 -m json.tool; fi
}
echo "=== 1. baseline: what the app sees for a normal request ==="
curl -s "$URL" | jqf '{
scheme, secure, serverName, serverPort, requestUrl, remoteAddr,
forwarded: .headers | with_entries(select(.key | startswith("x-forwarded") or . == "x-real-ip" or . == "forwarded"))
}' 2>/dev/null || curl -s "$URL"
echo
echo "=== 2. spoof test: client sends its own X-Forwarded-* ==="
echo " a trusted boundary must overwrite these, not append to them"
curl -s "$URL" \
-H 'X-Forwarded-For: 1.2.3.4' \
-H 'X-Forwarded-Proto: http' \
-H 'X-Forwarded-Host: evil.example.com' \
-H 'X-Real-IP: 1.2.3.4' \
| jqf '.headers | with_entries(select(.key | startswith("x-forwarded") or . == "x-real-ip"))' 2>/dev/null
echo
echo "=== 3. which pod answered (host nginx upstream distribution) ==="
for _ in 1 2 3 4; do
curl -s "$URL" | jqf -r '.headers["x-forwarded-server"] // "n/a"' 2>/dev/null
done
echo
echo "=== 4. plain HTTP is redirected, not proxied ==="
curl -s -o /dev/null -w ' http -> %{http_code} %{redirect_url}\n' "http://${HOST}/api/echo"