Appearance
How the System Works
This page explains the whole platform twice: first in plain language, then technically, step by step, with the files that implement each step.
Part 1: The simple explanation
Think of the Cyber Range as a training gym for cybersecurity.
- You walk in and show your ID. A student opens the website and signs in. The sign-in page belongs to Keycloak, a dedicated login service. It checks the password, then asks for a 6-digit code from an authenticator app on the student's phone (set up with a QR code at the first sign-in). Then it tells the website who you are and which role you have: Student, Instructor or Admin.
- You pick a workout. Students see four labs ("scenarios"), such as scanning a network or defending a web server. Each lab has a guide that explains what to do and why.
- The gym sets up your own equipment. When a student presses Start lab, the platform builds a private mini network just for that student with three small Linux machines inside it: an attacker machine (Kali), a vulnerable server (meta) and a vulnerable website (dvwa). Nobody else uses these machines. This takes about a minute.
- You train in the browser. A terminal window in the web page lets the student type commands directly on those machines. There is nothing to install.
- A coach watches your progress automatically. Every few seconds the platform quietly checks each lab for evidence that a task was done, for example "did this student scan the right network?" When the evidence is there, the task turns green and points are added. Scenarios 1 and 2 end with a "capture the flag" task, where the student types in a code they found.
- Instructors review and grade. Instructors see live labs, each student's progress and the security alerts their labs produced. If the automatic check misses a task, a student gets one Manual Check; if that also fails, the task goes to an instructor, who approves it (the points are added), rejects it or asks for a retry.
- The gym cleans up. When the student ends the session, or when the scenario's time limit runs out (30, 45 or 60 minutes), the platform deletes the machines and the network. The student's scores are kept.
- Admins run the gym. Admins create accounts, assign roles, reset a password or a lost authenticator, check that all services are healthy, force-stop a stuck lab and read the audit log.
Why this is safe
The vulnerable machines live inside private container networks on one cloud server. The server accepts no inbound web traffic at all. The public website is reached through an outbound Cloudflare Tunnel, and the only open inbound port is SSH for the operator, from a single allowed address.
Part 2: The technical explanation
The same journey, now with the real components.
Step 1: Opening the site
- The public hostname is served by a Cloudflare Tunnel that the host dials outbound. There is no inbound port 80 or 443 on the server (
manual/appendix-network-map.md,cyberrange/deploy/systemd/cloudflared.service). - The tunnel's origin is nginx inside the
guacamoleLXD container at10.115.77.12:80. Despite its name, this container does not run Apache Guacamole; it is the HTTP gateway (manual/02-gateway-and-wazuh.md,cyberrange/deploy/guacamole/nginx-ampere.conf). - nginx routes
/auth/to Keycloak,/api/ssh-websocketto the terminal bridge and everything else to the portal on10.115.77.1:3000.
Step 2: Signing in (authentication)
- The portal uses NextAuth with a Keycloak OAuth provider: authorization code flow with PKCE and state checks, scope
openid email profile(cyberrange/portal/src/lib/auth.ts). - Keycloak requires a second factor for every account: after the password it asks for a TOTP code, and a user with no authenticator is sent through QR enrolment first. The realm also enforces a password policy and temporary lockout after repeated failures (
cyberrange/deploy/host/enable_keycloak_mfa.sh,enable_keycloak_password_policy.sh). See Login, Sessions & Tokens. - After sign-in the portal stores an encrypted JWT session cookie valid for 12 hours. The Keycloak access token and refresh token live inside that encrypted cookie. Roles are read from the access token's
realm_access.rolesclaim. - The edge
middleware.tsredirects anyone without a session to/login, and anyone without one of the three application roles to/no-role(cyberrange/portal/src/middleware.ts).
Step 3: Choosing a scenario
- The scenario catalog (names, descriptions, milestones and points) is defined in the portal in
cyberrange/portal/src/hooks/useScenarios.ts. The four live scenarios have internal IDs01,06,09and11and are shown to students as Scenarios 1 to 4 (cyberrange/portal/src/lib/scenarioLabels.ts). - Guides are Markdown files served from
cyberrange/portal/public/scenarios/.
Step 4: Starting a lab (provisioning)
- The browser calls the portal's own API route, which forwards the request to FastAPI with the user's bearer token (
cyberrange/portal/src/lib/apiProxy.ts). This "backend for frontend" pattern means the browser never talks to FastAPI directly. - FastAPI validates the token with Keycloak token introspection (
cyberrange/src/provisioning/auth.py), then applies admission rules inside one database transaction: one live lab per student, theMAX_PODScap, free RAM and free storage (cyberrange/src/provisioning/pods_router.py). - It answers 202 Accepted immediately and builds the lab in a background task: an OVN network
pod-<id>-net, three containers from golden images, Wazuh agent enrollment, DVWA readiness and per-student flags (cyberrange/src/provisioning/provision.py). - Each lab gets the time limit of its scenario: 30 minutes for Scenario 1, 45 for Scenarios 2 and 3, 60 for Scenario 4 (
SCENARIO_TTL_MINUTESincyberrange/src/provisioning/config.py).
Step 5: Using the terminal
- The terminal is xterm.js in the browser, connected by WebSocket to
bridge.pyon the host (cyberrange/portal/src/components/terminal/XtermView.tsx,cyberrange/bridge-src/bridge.py). - The bridge introspects the token, confirms the caller may access the lab by calling the API's
/pods/{id}/status, then openslxc execinto the container asstudent(kali, dvwa) ormsfadmin(meta), inside a reattachable tmux session namedlab.
Step 6: Doing tasks and getting scored
- A background score poller runs every 3 seconds. For each active lab it re-checks every milestone that has not passed yet (
cyberrange/src/provisioning/score_poller.py). - Each check pipes
scoring_checks.shinto the right container withlxc execand readsPASS,FAILorUNKNOWN(cyberrange/src/provisioning/ssh_verifier.py,cyberrange/src/provisioning/scoring_checks.sh). Most checks look for evidence in shell history or in files the student created. - Scenario 2 is also scored from the browser: the portal's DVWA proxy recognizes successful attacks in DVWA's responses and reports them to the API with a shared secret (
cyberrange/portal/src/lib/dvwaScoreSignals.ts). - The final task of Scenarios 1 and 2 is a flag submission: the student types the flag into the lab page, and a correct flag alone scores (
PURE_FLAG_MILESTONESincyberrange/src/provisioning/hybrid_scoring.py). - The lab page polls the milestones every 3 seconds, turns tasks green as they pass, shows a "Task auto-detected" toast with the points, and opens a completion dialog when every task has passed (
cyberrange/portal/src/hooks/useScenarioMilestones.ts).
Step 7: Reviews and instructor oversight
- Manual Check is one-shot. A student may run it once per task. If it fails, the task locks to instructor review (
manual_check_attempts, schema v10). The background poller never uses up that attempt (cyberrange/src/provisioning/pods_router.py). - Students can submit a written report or ask for a manual review, optionally with screenshots. The API freezes a snapshot of the lab's SIEM alerts at that moment (
cyberrange/src/provisioning/lab_history.py). - Instructors see live labs, student progress, SIEM alerts (live and for ended labs) and the review queue, and resolve reviews as Approved, Rejected or Retry. Approving a task-specific review writes the milestone PASS, so the student gets the points; rejecting it later removes that PASS again.
Step 8: Teardown
- Ending a session, an admin force-destroy, or the TTL reaper when the scenario's time limit passes (checked every 60 seconds) marks the lab
DESTROYINGand removes Wazuh agents, the DVWA proxy, the three containers and the network (cyberrange/src/provisioning/reaper.py,cyberrange/src/provisioning/provision.py). - Scores in
milestone_verificationare never deleted with the lab.
Sources
cyberrange/portal/src/lib/auth.ts, cyberrange/portal/src/middleware.ts, cyberrange/deploy/host/enable_keycloak_mfa.sh, cyberrange/src/provisioning/config.py, hybrid_scoring.py, reaper.py, cyberrange/portal/src/lib/apiProxy.ts, cyberrange/src/provisioning/provision_api_fastapi.py, cyberrange/src/provisioning/pods_router.py, cyberrange/src/provisioning/provision.py, cyberrange/src/provisioning/score_poller.py, cyberrange/src/provisioning/ssh_verifier.py, cyberrange/bridge-src/bridge.py, cyberrange/deploy/guacamole/nginx-ampere.conf, manual/appendix-network-map.md.