mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
chore(infra): add internal routing smoke-test script
scripts/verify-internal.sh runs the exact verification sequence before
the edge is touched. Checks (in order):
0. Port listeners — host Caddy owns :80, Traefik NodePort on :30080
1. GET / — 200 Homer or 302 → auth.researchstack.info (not internal IP)
2. /api/* bypass — none of /api/*/health may 302 to Authentik
3. auth.researchstack.info — 200/302 from Authentik, no internal-IP loop
4. Host header passthrough — Traefik :30080 /ping reachable; /api/jobs/health
routes end-to-end through host Caddy → Traefik → Ingress
5. X-Forwarded-Proto — https header survives the server-Caddy hop
Usage:
# on nixos-laptop directly:
bash 4-Infrastructure/k3s-flake/scripts/verify-internal.sh
# from any tailnet node:
bash 4-Infrastructure/k3s-flake/scripts/verify-internal.sh --remote
Exit 0 = safe to deploy edge. Exit 1 = fix red checks first.
Generated with Devin (https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
8d1d94b256
commit
aae680ad3c
1 changed files with 192 additions and 0 deletions
192
4-Infrastructure/k3s-flake/scripts/verify-internal.sh
Normal file
192
4-Infrastructure/k3s-flake/scripts/verify-internal.sh
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
#!/usr/bin/env bash
|
||||
# verify-internal.sh — internal routing smoke test
|
||||
#
|
||||
# Run on nixos-laptop (100.102.173.61) after nixos-rebuild switch,
|
||||
# BEFORE deploying the edge Caddy. Exercises the host-Caddy → Traefik
|
||||
# → Ingress path directly so you know the internal leg is clean.
|
||||
#
|
||||
# Usage:
|
||||
# bash 4-Infrastructure/k3s-flake/scripts/verify-internal.sh
|
||||
# bash 4-Infrastructure/k3s-flake/scripts/verify-internal.sh --remote
|
||||
# (runs via ssh root@100.102.173.61 if not already on the node)
|
||||
#
|
||||
# Exit 0 = all checks passed.
|
||||
# Exit 1 = one or more checks failed; details printed to stderr.
|
||||
set -euo pipefail
|
||||
|
||||
NODE_IP="100.102.173.61"
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
# ── helpers ──────────────────────────────────────────────────────────────────
|
||||
|
||||
green() { printf '\033[32m✓ %s\033[0m\n' "$*"; }
|
||||
red() { printf '\033[31m✗ %s\033[0m\n' "$*" >&2; }
|
||||
|
||||
check() {
|
||||
local label="$1"; shift
|
||||
if "$@" 2>/dev/null; then
|
||||
green "$label"
|
||||
(( PASS++ )) || true
|
||||
else
|
||||
red "$label"
|
||||
(( FAIL++ )) || true
|
||||
fi
|
||||
}
|
||||
|
||||
# Run from remote if requested and not already on the node.
|
||||
if [[ "${1:-}" == "--remote" ]]; then
|
||||
echo "[verify] running remotely on $NODE_IP..."
|
||||
exec ssh "root@$NODE_IP" bash -s < "$0"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "═══════════════════════════════════════════════════════"
|
||||
echo " Internal routing smoke test — $(date -u '+%Y-%m-%dT%H:%M:%SZ')"
|
||||
echo " Target node: $NODE_IP"
|
||||
echo "═══════════════════════════════════════════════════════"
|
||||
echo
|
||||
|
||||
# ── 0. Listener sanity ───────────────────────────────────────────────────────
|
||||
echo "── 0. Port listeners ──"
|
||||
|
||||
check "host Caddy owns :80" \
|
||||
bash -c "ss -tlnp | grep -q ':80 '"
|
||||
|
||||
check "Traefik NodePort :30080 is bound" \
|
||||
bash -c "ss -tlnp | grep -q ':30080 '"
|
||||
|
||||
echo
|
||||
|
||||
# ── 1. Root path: Homer or Authentik redirect ────────────────────────────────
|
||||
echo "── 1. GET / (expect 200 Homer or 302 → Authentik) ──"
|
||||
|
||||
root_status=$(curl -so /dev/null -w '%{http_code}' \
|
||||
-H "Host: researchstack.info" \
|
||||
-H "X-Forwarded-Proto: https" \
|
||||
--max-time 5 \
|
||||
"http://$NODE_IP/")
|
||||
|
||||
check "/ returns 200 or 302 (got $root_status)" \
|
||||
bash -c '[[ '"$root_status"' == 200 || '"$root_status"' == 302 ]]'
|
||||
|
||||
if [[ "$root_status" == "302" ]]; then
|
||||
root_loc=$(curl -so /dev/null -w '%{redirect_url}' \
|
||||
-H "Host: researchstack.info" \
|
||||
-H "X-Forwarded-Proto: https" \
|
||||
--max-time 5 \
|
||||
"http://$NODE_IP/")
|
||||
check "/ redirect points to auth.researchstack.info (not an http://10x... internal URL)" \
|
||||
bash -c '[[ '"\"$root_loc\""' == *"auth.researchstack.info"* ]]'
|
||||
fi
|
||||
|
||||
echo
|
||||
|
||||
# ── 2. API bypass: /api/* must NOT 302 to Authentik ─────────────────────────
|
||||
echo "── 2. /api/* paths must not redirect to Authentik ──"
|
||||
|
||||
for path in /api/registry/health /api/jobs/health /api/blobs/health; do
|
||||
status=$(curl -so /dev/null -w '%{http_code}' \
|
||||
-H "Host: researchstack.info" \
|
||||
--max-time 5 \
|
||||
"http://$NODE_IP$path")
|
||||
|
||||
check "$path → $status (not 302)" \
|
||||
bash -c '[[ '"$status"' != 302 ]]'
|
||||
|
||||
if [[ "$status" == "302" ]]; then
|
||||
loc=$(curl -so /dev/null -w '%{redirect_url}' \
|
||||
-H "Host: researchstack.info" \
|
||||
--max-time 5 \
|
||||
"http://$NODE_IP$path")
|
||||
red " redirect target: $loc"
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
||||
|
||||
# ── 3. auth.researchstack.info → Authentik (no forward_auth loop) ───────────
|
||||
echo "── 3. auth.researchstack.info serves Authentik (200 or 302, no loop) ──"
|
||||
|
||||
auth_status=$(curl -so /dev/null -w '%{http_code}' \
|
||||
-H "Host: auth.researchstack.info" \
|
||||
-H "X-Forwarded-Proto: https" \
|
||||
--max-time 5 \
|
||||
"http://$NODE_IP/")
|
||||
|
||||
check "auth.researchstack.info returns 200 or 302 (got $auth_status)" \
|
||||
bash -c '[[ '"$auth_status"' == 200 || '"$auth_status"' == 302 ]]'
|
||||
|
||||
# If it's a redirect, the location must not point back to an internal IP
|
||||
if [[ "$auth_status" == "302" ]]; then
|
||||
auth_loc=$(curl -so /dev/null -w '%{redirect_url}' \
|
||||
-H "Host: auth.researchstack.info" \
|
||||
-H "X-Forwarded-Proto: https" \
|
||||
--max-time 5 \
|
||||
"http://$NODE_IP/")
|
||||
check "auth redirect does not loop to internal IP ($auth_loc)" \
|
||||
bash -c '[[ '"\"$auth_loc\""' != *"100.102"* && '"\"$auth_loc\""' != *"127.0"* ]]'
|
||||
fi
|
||||
|
||||
# Response body should look like Authentik (may be empty if redirecting to flow)
|
||||
auth_body=$(curl -s \
|
||||
-H "Host: auth.researchstack.info" \
|
||||
-H "X-Forwarded-Proto: https" \
|
||||
-L --max-redirs 3 --max-time 10 \
|
||||
"http://$NODE_IP/" 2>/dev/null || true)
|
||||
|
||||
check "auth response contains Authentik markers" \
|
||||
bash -c '[[ '"\"$auth_body\""' == *"authentik"* || '"\"$auth_body\""' == *"ak-flow"* || '"\"$auth_body\""' == *"Sign in"* ]]'
|
||||
|
||||
echo
|
||||
|
||||
# ── 4. Host header passthrough ────────────────────────────────────────────────
|
||||
echo "── 4. Host header passthrough (server Caddy → Traefik) ──"
|
||||
|
||||
# The Traefik dashboard is disabled, but /ping is available by default
|
||||
ping_status=$(curl -so /dev/null -w '%{http_code}' \
|
||||
--max-time 5 \
|
||||
"http://$NODE_IP:30080/ping" 2>/dev/null || echo "000")
|
||||
|
||||
check "Traefik /ping on :30080 responds (got $ping_status — 200/404 both ok, 000 = not reachable)" \
|
||||
bash -c '[[ '"$ping_status"' != 000 ]]'
|
||||
|
||||
# Confirm Host is forwarded by checking a real Ingress path
|
||||
jobs_status=$(curl -so /dev/null -w '%{http_code}' \
|
||||
-H "Host: researchstack.info" \
|
||||
--max-time 5 \
|
||||
"http://$NODE_IP/api/jobs/health")
|
||||
|
||||
check "/api/jobs/health via host Caddy → Traefik → service (got $jobs_status, not 000)" \
|
||||
bash -c '[[ '"$jobs_status"' != 000 ]]'
|
||||
|
||||
echo
|
||||
|
||||
# ── 5. X-Forwarded-Proto passthrough ─────────────────────────────────────────
|
||||
echo "── 5. X-Forwarded-Proto preserved through server Caddy ──"
|
||||
|
||||
# Hermes placeholder echoes back X-Forwarded headers in its /health response
|
||||
# if deployed. If not, check that Traefik doesn't return 000 on the path.
|
||||
proto_status=$(curl -so /dev/null -w '%{http_code}' \
|
||||
-H "Host: researchstack.info" \
|
||||
-H "X-Forwarded-Proto: https" \
|
||||
--max-time 5 \
|
||||
"http://$NODE_IP/api/registry/health")
|
||||
|
||||
check "X-Forwarded-Proto: https request routes without error (got $proto_status)" \
|
||||
bash -c '[[ '"$proto_status"' != 000 ]]'
|
||||
|
||||
echo
|
||||
echo "═══════════════════════════════════════════════════════"
|
||||
printf " Results: %d passed, %d failed\n" "$PASS" "$FAIL"
|
||||
echo "═══════════════════════════════════════════════════════"
|
||||
echo
|
||||
|
||||
if (( FAIL > 0 )); then
|
||||
echo "[verify] FAIL — fix the red checks before deploying the edge." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[verify] PASS — internal leg is clean. Safe to deploy k3s-edge."
|
||||
echo " Next: nixos-rebuild switch on microvm-racknerd, then run:"
|
||||
echo " cd 4-Infrastructure/k3s-flake/tests && npm test"
|
||||
Loading…
Add table
Reference in a new issue