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.
This commit is contained in:
commit
4d60fdd139
28 files changed
+2609
No files matched your search
@@ -0,0 +1,87 @@
|
||||
# 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/`.
|
||||
Reference in new issue
Block a user