Files
imperva-demo/docs/ARCHITECTURE.md
T
matt 4d60fdd139 Initial commit: Imperva WAF demo lab
Flight-booking app scaffolded from the source running on the GCP host,
plus the four-screen frontend and three OWASP attack endpoints (SQLi,
reflected XSS, path traversal) built and locally verified against a
live uvicorn/vite dev pair. Includes deploy.sh (local build -> ship
over ssh -> swap on host) and docs/ carried over from the handoff.
2026-07-29 11:08:56 -07:00

4.3 KiB

Architecture

Overview

Single GCP e2-micro running three rootless Podman containers under user matt. Imperva Cloud WAF sits in front of everything. The origin is network-isolated so that the only things that can reach the app are Imperva's edge nodes.

Visitor ──TLS──▶ Imperva Cloud WAF ──TLS (re-encrypt)──▶ Caddy :443 ──HTTP──▶ backend/frontend
                 (terminates,                             (self-signed cert)
                  inspects,
                  re-encrypts)

The two TLS legs (this is the crux of the design)

There are two independent TLS connections, and they use different certificates. Mixing them up is the single easiest way to break this setup.

Leg 1 — Visitor → Imperva (edge). Imperva presents a publicly-trusted certificate for flytoouter.space to browsers. This is Imperva's managed cert (auto-provisioned by Imperva). It must be publicly trusted or every visitor gets a browser warning. We do not touch this with our self-signed cert.

Leg 2 — Imperva → origin (re-encryption). Imperva opens a second TLS connection back to the GCP origin and inspects/re-encrypts before forwarding. Caddy serves this leg on :443 with a self-signed certificate. Imperva is the only client that ever sees this cert, so self-signed is fine and produces no visitor-facing warnings.

DNS for flytoouter.space must point at Imperva, not at 35.203.147.44. If it resolves straight to the origin, browsers try to negotiate TLS with the self-signed origin cert and fail.

Request flow through the origin

Caddy (caddy-proxy) is the only container bound to a public port. It terminates the re-encryption TLS and reverse-proxies over plain HTTP to the app containers via the host.containers.internal alias on the default rootless bridge network:

  • handle /api/* → host.containers.internal:8000 (FastAPI backend)
  • handle /* → host.containers.internal:8080 (Vue frontend)

handle (not handle_path) is used so the /api prefix is preserved for the backend routes (/api/v1/users, etc.).

Container stack

Container Image Port Role
caddy-proxy docker.io/library/caddy:2-alpine 443:443 TLS termination (re-encryption leg) + reverse proxy
backend-api custom Python 3.11-slim (FastAPI) 8000:8000 REST API + local SQLite demo.db
frontend-vue custom multi-stage (Node build → Nginx) 8080:8080 Vue SPA (flight booking UI)

Caddy currently serves only :443. There is intentionally no :80 site block (see DECISIONS.md — a stray :80 block under auto_https off caused the ambiguous site definition failure). If Imperva needs an HTTP health check, an :80 block can be added back as a separate, non-conflicting listener.

Network / edge security

  • Origin target tag: imperva-origin.
  • allow-imperva-waf: HTTP/HTTPS ingress restricted to Imperva's published IPv4 CIDR blocks (e.g. 199.83.128.0/21, 198.143.32.0/19, …). Confirm tcp:443 is in the allowed ports since the origin path is now 443-only.
  • allow-home-ssh: SSH (22) locked to the operator's static residential IP.
  • All default open (0.0.0.0/0) rules purged.

Because the origin only answers Imperva CIDRs, the deliberately-vulnerable endpoints are unreachable directly. Every attack must pass through the WAF — which is exactly why they register as blocked events in the portal.

Host hardening (from original build)

  • /swapfile mounted via /etc/fstab to mitigate OOM kills on the burstable e2-micro.
  • loginctl enable-linger matt so rootless containers persist across reboots.
  • sysctl net.ipv4.ip_unprivileged_port_start=80 to let rootless Caddy bind low ports.

Cert details (origin, Leg 2)

  • Self-signed, RSA 2048, 3650-day validity.
  • SAN covers both DNS:flytoouter.space and IP:35.203.147.44, so whichever way Imperva addresses the backend, the cert matches.
  • Files live on the host at ~/imperva-proxy/certs/{origin.crt,origin.key} and are bind-mounted read-only into Caddy at /etc/caddy/certs/.