Appearance
Threat Model
A lightweight, STRIDE-style model of the platform. It names the trust boundaries, the assets worth protecting, who the threat actors are, and the main threats with the control that addresses each. It is a reasoning tool for the panel and maintainers, not a penetration-test report.
Trust boundaries
| Boundary | Between | Crossing is controlled by |
|---|---|---|
| B0 | Operator and host | OCI security list: SSH 22 from the operator /32 only |
| B1 | Internet and edge | Cloudflare Tunnel; no inbound ports open on the host |
| B2 | Edge and application | nginx routes / to the portal, /auth/ to Keycloak, /api/ssh-websocket to the bridge |
| B3 | Browser and data | Portal BFF requires a session and injects the token server-side; API re-validates by introspection and authorizes per route |
| B4 | Host and lab zone | LXD control plane (lxc exec) only; the host has no IP route into lab networks |
| B5 | Lab zone and monitoring | Lab networks are peered only to the monitoring network so agents can reach the manager. Each lab network carries an egress ACL (default reject) that allows only the lab's own subnet and the manager on TCP 1514/1515 (pull request 308); the Wazuh API is bound to loopback inside its container by harden_wazuh_api.sh (pull request 303) |
Assets
| Asset | Why it matters | Where it lives |
|---|---|---|
| Student, instructor and admin identities | Account takeover would expose grades and admin actions | Keycloak |
| Access tokens | Bearer tokens authorize every API call | Browser session (memory), server-side, and the terminal WebSocket URL |
| Scores, reviews, telemetry | Academic integrity of the capstone | SQLite pod_mgmt.db |
| The host | One VM runs everything; host compromise is total | OCI Ampere instance |
| Lab isolation | A break from one lab into another or the host would undermine the whole design | OVN networks, unprivileged containers |
| Platform secrets | Client secrets, the flag secret, Wazuh and admin credentials, the Wazuh internal CA private key | env files (mode 600), secrets file, ~/cyberrange-data/wazuh-ca/ (keys mode 600) |
| SIEM integrity | Scenario 3 scoring and instructor alert views depend on the shared manager's agent list and alerts | wazuh-manager container |
Threat actors
- A curious or malicious student. Authenticated, has root inside their own lab by design, and controls a machine on a lab network. The primary actor the isolation is built against.
- An unauthenticated internet user. Can reach only the login page and the public
/health,/capacityand browser-score endpoints through the tunnel. - A compromised lab target. The vulnerable machines are meant to be exploited; treat them as attacker-controlled.
- An insider with instructor or admin rights. Trusted, but their powerful actions should be audited.
STRIDE-style threats
| Threat | Category | Vector | Control | Residual risk |
|---|---|---|---|---|
| Impersonate another user | Spoofing | Steal a password, guess one, or steal or forge a token | Required TOTP MFA; password policy with blocklist; temporary lockout after 10 failures; PKCE + state; introspection every request; short cache; owner checks return 404 | Access token is exposed to the browser and travels in the terminal WebSocket URL (see Findings) |
| Tamper with another student's score | Tampering | Call the API for another student | Identity is taken from the token, never a parameter; owner checks; parameterized SQL | Low |
| Deny a scoring conflict happened | Repudiation | Admin destroys a lab or grades unfairly | Append-only audit_log; force-destroy and user-management writes record the actor | Logs are in /tmp (lost on reboot); no off-host shipping |
| Read another student's data | Information disclosure | Guess IDs, browse the API | require_owner returns 404; instructor and admin routes gated; DVWA proxy path allowlist | /capacity is public; admin token can open any lab terminal |
| Exhaust the host | Denial of service | Provision many labs, fill disk, spam scoring | MAX_PODS, RAM and storage gates, one lab per student, per-scenario time limit (30 to 60 min) checked every 60 s | SQLite grows from per-check rows |
| Pollute the shared SIEM | Tampering | Register fake agents or flood events from a lab | Lab egress ACL allows only TCP 1514/1515 to the manager; the API (55000) is not reachable from a lab; a lab is not marked ACTIVE while a stale agent with the student's name is still registered | Enrollment is still passwordless, so the enrollment port accepts any agent from a lab (F6) |
| Escape a lab | Elevation of privilege | Root in a container, attack the host or another lab, or use the lab as a jump box to the internet | Unprivileged containers with caps; no lab-to-lab peering; host has no route into labs; per-lab egress ACL rejects internet, uplink DNS and the lab's own gateway address, re-applied by the reaper | Host operator SSH key is installed in every lab's root account; the egress ACL is new and needs a live test from a disposable lab |
| Exploit the internet-facing portal | Elevation of privilege / Information disclosure | A known framework vulnerability | Image Optimization API disabled; framing, nosniff and referrer headers; portal binds a private address behind nginx and the tunnel | no HSTS or full CSP (F14) |
| Break out of the gateway | Elevation of privilege | Reach the Keycloak admin API through nginx | Admin console intended to be SSH-tunnel only | Repo nginx config exposes admin/master-realm routes through the origin (D3) |
Design assumptions to validate on the live host
These come straight from the Open Questions and matter to the model: whether the new egress ACL really blocks internet and DNS from a live lab, whether harden_wazuh_api.sh and issue_wazuh_internal_ca.py --install have been run on each host (their evidence records are still Pending), whether the Keycloak admin routes are exposed, whether Keycloak runs its dev H2 database in production, whether gateway access logs (which capture the token in the WebSocket URL) are enabled, and whether backups exist.
Sources
manual/appendix-network-map.md, manual/02-gateway-and-wazuh.md, manual/06-scoring.md, cyberrange/src/provisioning/auth.py, pods_router.py, pod_net.py, provision.py, wazuh_client.py, bridge-src/bridge.py, cyberrange/deploy/guacamole/nginx-ampere.conf, cyberrange/deploy/host/harden_wazuh_api.sh, issue_wazuh_internal_ca.py, cyberrange/portal/next.config.mjs. Severity judgments are the reviewer's, from a read of the code at commit daeb43f, re-checked at 220e6d3 and 6971373.