Isolation and safety
How Invictus Academy isolates hostile range workloads into tiers, defends the control plane and trainees, and keeps an honest, named trust posture across its boundaries.
A range that is hostile by construction
The range runs real adversary tooling by design, so the platform treats it as an internet-attackable, hostile environment from the start. Every isolation control exists to bound what a compromised or runaway run can reach, spend, or poison.
The system is partitioned into three planes with distinct trust levels, credentials, and network fabric. They never share a data plane, and there is no VNet or VPC peering between the control plane and the range.
The evidence plane is kept separate on purpose, and the ledger seal makes any rewrite of sealed evidence by a compromised API or a database administrator detectable rather than silent.
- Control plane: the Invictus platform (Container Apps, PostgreSQL, Valkey, Keycloak, the web app, and the academy-api run-modes), holding all trainee identity, tenant configuration, and orchestration logic, in an EU region in the consortium partner's subscription.
- Range plane: standing lab environments in that subscription's own resource groups (the designed pool of dedicated subscriptions, accounts and Microsoft 365 tenants is not built) where labs detonate and trainees work. Treated as hostile and running attacker-controlled compute in the higher tiers.
- Evidence plane: the evidence store plus a signed, hash-chained custody ledger, never reachable from the range. Write-once (WORM) retention and external time-anchoring are production-path controls.
Tiered isolation by lab risk
Not every lab needs live attacker compute, and running one where a frozen capture would do only adds blast radius and cost. Labs are therefore assigned one of five isolation tiers by risk (see ADR-011, ADR-113), which is the single largest recovery of both safety and schedule in the design.
Most content needs no live attacker-controlled compute, which keeps the live attack surface small and lets labs run at CTF scale. Of the labs shipping today, only two stand on the two highest tiers.
- Frozen static-dataset labs (the default tier): pre-detonated once, captured into an immutable dataset, and replayed from those artefacts. No live attacker-controlled compute at run time, minimal blast radius, and near-zero live cloud cost.
- Downloadable-artefact challenge sets: the evidence ships with the lab and is worked with your own tools. No environment is built at all, so there is nothing to lease, nothing to reclaim and no live cost. Two labs work this way today; the CloudLabs challenge labs are worked in their provider's console instead.
- Shared-estate labs: a whole class queries one standing cloud environment an operator built in advance, rather than one per trainee. It holds no attacker compute and it is not torn down between runs, so its blast radius is bounded by being read-only to trainees rather than by being short-lived.
- Resource-group-scoped live labs (intermediate): each run leases its own resource group inside a pooled subscription, with a tightly-scoped identity and reset between runs. Egress from a live lab is not restricted today, and no preventive policy refuses a dangerous action before it happens; the controls that bound a run are its scoped identity, its lease and the reaper, all of which act after the fact. See the cost and containment list below for what is and is not built.
- Dedicated-account live labs (a small number of advanced only): the highest-risk detonations get a dedicated pooled subscription or account so their blast radius cannot touch a shared one, reset between runs.
Honest asymmetric trust, not zero trust
The model deliberately rejects a "zero trust into the range" framing. That claim would be false: forensic acquisition and live scoring must read into the range, the provisioner must write into it, and a trainee's interactive shell is a human path into a live lab. Naming and bounding those flows is safer than pretending they do not exist (see ADR-013, extended by ADR-031).
Trust is asymmetric. From range to control there is telemetry outbound only: the range emits provider-native logs that a read-only collector pulls, with no inbound path from the range to the control-plane data plane. Everything the range sends is treated as untrusted input.
From control to range there are exactly three sanctioned crossings today, and no others. The security value is precisely the asymmetry: a compromised range gains no foothold back into the control plane, and each inbound flow is reduced to the minimum privilege its function needs.
- Provisioner as sole writer: only the provisioner run-mode can change range state (apply, detonate, reset, teardown). No other control-plane component holds a range-write credential.
- Read-only per-run readers: a narrow, audited broker mints short-lived, read-only, per-run tokens for the collector and acquisition components. They can pull logs and artefacts for one run and nothing else.
- Trainee interactive shell: a short-lived, single-run capability brokered by a dedicated gateway that dials into the range. The range never opens a connection back, and terminal output is rendered but never interpreted.
The platform defends itself against its own content
The provisioner is the single most dangerous component and is treated as a named threat: it consumes work from a queue and writes to the range with cloud credentials. To sever any path from a forged queue message to code execution, it runs on an isolated node pool with its own workload identity, and it authorises every signed, scoped intent before acting. There is no long-lived, broadly-privileged range key anywhere (ADR-009, ADR-012).
Lab bundles contain executable Terraform, detonation code, and Ansible authored by a partner and, in future, by third parties. That is remote code execution unless it is sandboxed, so it runs inside a locked-down ephemeral runner with a per-run identity scoped to that run alone, isolated from CI secrets (ADR-015).
Everything the range emits, including detonation-shaped logs, trainee actions, and evidence bytes, is attacker-influenced and treated as untrusted input at every boundary it crosses (ADR-014).
- On ingest: strict schema validation, size and rate caps, and quarantine of malformed input. Range-supplied content is never executed.
- In the UI: every range-derived field is output-encoded to defeat stored cross-site scripting in the forensic interface.
- On egress: fields are sanitised before any telemetry is shipped to a customer SIEM, so a compromised range cannot poison a customer's production detections.
Keeping runs, budgets, and trainees safe
An internet-exposed range with live compute is a runaway-cost and cryptomining target, and cloud budgets only alert after the money is spent. ADR-016 designs four layers of enforcement on top of those lagging alarms. Two are built and two are not, and the difference is stated below rather than blurred: a cost control you believe in but do not have is worse than none.
Range access uses OIDC workload-identity federation with short-lived, per-run tokens. There are no static keys in Terraform state or in the database, and unavoidable secrets live in a key vault by reference (ADR-012).
Trainees are protected from a gameable or flaky scoring path as well: live labs are graded on the end state you leave, not on keystrokes, and grading runs against captured, normalised telemetry computed in-process rather than a live cloud call per submission (ADR-025).
- Built. Guaranteed teardown: a time-to-live reaper scans every 15 seconds and destroys a run's resources when its lease expires, independently of whether the trainee ended the run properly. A teardown that fails is counted and alertable, because that is the case where an environment keeps billing (ADR-016, ADR-065).
- Built. Operator break-glass: an operator can halt new runs, and can drain the range so every live lab is torn down on the next reaper pass. Halting tells a trainee starting a run that the range is paused, with the reason (ADR-064).
- Not built. Preventive denies: policy and service control policies to refuse expensive SKUs, non-EU regions, and dangerous actions before anything is created. No such policies are deployed today, so an oversized resource is reclaimed after the fact rather than refused.
- Not built. Near-real-time kill-switch: a resource-count check polling cloud inventory rather than billing, plus a tag-scoped nuke as the backstop when a destroy leaves resources behind. Neither exists yet, so spend is bounded in time by the reaper rather than capped.
What this posture claims, and what it does not
The honesty of the trust model is part of the design, so a few claims are stated plainly rather than overclaimed. The two audited read paths into the range are a named, accepted part of the model, which is exactly why the platform does not claim zero trust into the range.
The evidence plane produces tamper-evident training documentation. The custody chain is hash-chained, so any later change is detectable; when a signing key is configured the platform also seals the chain head with a key held outside the database, making tampering detectable even by someone with direct database access. Write-once (WORM) storage and external time-anchoring are production-path controls, not present-tense guarantees. It is built for training and investigation, and is not presented as court-admissible evidence.
Trainee personal data never enters the evidence store, and the range never reaches trainee identity or tenant configuration in the control plane. Where numbers matter, the platform's operational targets are reported as measured programme results, not as statistically powered proofs.