« Phase 13 · Warmup · Track Overview
Lab 01 — The Resource Graph & the Reachability Prover
The problem
An examiner asks one question: "can you prove that no inference call on customer data leaves the UAE?"
The architect points at a diagram. There is a private endpoint on the box marked "Azure OpenAI". The VNet has no internet egress. The answer is obviously yes.
It is not. Somewhere in that estate:
- the private endpoint exists and its DNS zone was never linked, so the FQDN still resolves to a public IP and every packet takes the public path — while everything works perfectly;
- the storage account has a private endpoint and public network access still enabled, which are two different settings and only one of them was changed;
- and the platform VNet is peered to a shared services VNet, which is peered to a legacy VNet in West Europe that has had a NAT gateway since 2021.
None of these error. None alert. Each one is invisible in the diagram, and each one makes the answer to the examiner's question "no".
You build the thing that answers it properly: a reachability prover that searches the whole topology and returns a counter-example path when the answer is yes and should not be.
What you build
| # | Component | What it does |
|---|---|---|
| 1 | ResourceGraph | a DAG with deterministic topological order and blast-radius queries |
| 2 | plan, FORCE_NEW | a diff against state, with REPLACE for the attributes that destroy |
| 3 | apply | dependency order, and a failure skips every dependent |
| 4 | detect_drift | three categories, per attribute |
| 5 | AdmissionGate | deny-by-default, every deny naming its rule, fail-closed on a policy bug |
| 6 | NsgRule, Topology | first-match-by-priority, directional non-transitive peerings |
| 7 | ReachabilityProver | intra-VNet + peering search, with a counter-example path |
| 8 | prove_no_egress | the residency claim, as a proof obligation |
| 9 | schedule, NodePool | taints, MIG partitioning, and gang scheduling |
Key concepts
| Concept | Where | Why it matters |
|---|---|---|
| Infrastructure is a graph | ResourceGraph | ordering, parallelism and blast radius fall out of one structure |
| Cycles are rejected at construction | validate | one found mid-apply leaves a state nothing describes |
| Deterministic order | order | a plan that reorders between runs cannot be reviewed |
| Plan diffs state, not reality | plan | which is exactly why drift detection is separate |
FORCE_NEW means destroy | Change.action | the line in a plan nobody reads and everybody should |
| A failure skips dependents | apply | half-built infrastructure is worse than none |
| State is written per resource | apply | a crash must leave a state file matching what got built |
| Drift has three categories | detect_drift | unmanaged is the dangerous one |
| Deny by default | AdmissionGate | — |
| A policy that raises denies | evaluate | one that fails open on its own bug fails open in an incident |
| A private endpoint ≠ closed | requires_private_endpoint | public access is a separate setting |
| A tag is mutable | requires_digest_pin | the signature you verified was for a different artifact |
| Every denial names its rule | AdmissionDecision | "denied" is unactionable |
| NSGs are first-match-by-priority | nsg_verdict | unlike Phase 09, where deny always beats allow |
| Peerings are directional | Peering | one-way configuration carries no traffic |
| Peerings are not transitive | peered | A↔B and B↔C is not A↔C |
| Intra-VNet routing is implicit | reach | "is the PE in my subnet" is the wrong question |
| DNS is what actually breaks | dns_zone_linked | the endpoint exists and traffic still goes public |
| A result is not a boolean | ReachabilityResult | a counter-example is a finding; a "no" is an opinion |
| Residency is a proof obligation | prove_no_egress | not a configuration to inspect |
| MIG slices have a hard ceiling | slices_per_gpu | a 70B model does not fit in 10 GB, however many slices |
| Gang scheduling or deadlock | schedule | 6 of 8 GPUs held, no progress, forever |
| Largest gang first | schedule | fragmentation defeats a sufficient total |
| Warm pools, not autoscaling | scale_out_delay | nine minutes to serving |
Files
| File | Role |
|---|---|
| lab.py | your implementation |
| solution.py | reference; python solution.py runs a seven-part worked session |
| test_lab.py | 115 tests |
| requirements.txt | pytest |
Run
pip install -r requirements.txt
pytest test_lab.py -v
LAB_MODULE=solution pytest test_lab.py -v
python solution.py
Success criteria
-
All 115 tests green against your
lab.py. - A cycle — including a self-dependency — is rejected before any apply.
- The topological order is identical across two runs of the same graph.
-
planon an unchanged graph is empty. -
Changing a
FORCE_NEWattribute produces aREPLACEthat names which attribute forced it. - Deletes are ordered dependents-first.
- A failed resource skips its entire transitive dependent set, and not independent ones.
- Successful resources before the failure remain in state.
- Drift is reported per attribute, in all three categories.
- A private endpoint with public access still enabled is denied.
- A policy function that raises produces a deny, not an allow.
- Every violated rule is reported, not just the first.
- NSG evaluation is first-match-by-priority; swapping priorities swaps the outcome.
- A private endpoint in a different subnet of the same VNet is reachable.
- An unlinked DNS zone makes the endpoint not count, with a stated reason.
- A path through two peerings into another region is found, with a rendered counter-example.
- A gang that does not fit is not partially placed.
- An unplaced workload always carries a reason.
How this maps to the real stack
| This lab | The real thing | What we simplified |
|---|---|---|
ResourceGraph, plan, apply | Terraform / OpenTofu | no HCL, no providers, no modules, no remote state or locking |
FORCE_NEW | a provider's ForceNew schema flag | a hand-written table for four types |
detect_drift | terraform plan -refresh-only, Azure Resource Graph | reality is a dict, not an API |
AdmissionGate | OPA/Gatekeeper, Kyverno, Azure Policy | Python callables, not Rego/CEL; no mutation, no audit mode |
Topology, ReachabilityProver | Azure Network Watcher connectivity check, AWS Reachability Analyzer, batfish | no route tables, UDRs, firewall rules, ASGs or service endpoints |
NsgRule | an Azure NSG | no service tags, no application security groups |
PrivateEndpoint | Azure Private Link | DNS modelled as a boolean; real DNS is a zone, a link and a record |
NodePool, schedule | AKS node pools + Volcano/Kueue | no bin-packing, no preemption, no priority classes, no spot |
MIG_PROFILES | NVIDIA MIG on A100/H100 | the profile table only; no device plugin, no topology awareness |
Honest limits. The reachability model has no route tables — a UDR pointing 0.0.0.0/0 at a
firewall NVA is the single most common real topology and it is not represented, so a "no egress"
proof here is weaker than the real question. There are no service tags (Storage,
AzureCloud), which is how most real NSG rules are written, and no service endpoints, which are
a different mechanism from private endpoints with different residency properties. DNS is a boolean
where reality is a zone, a VNet link and an A record, each independently missable. The scheduler has
no bin-packing, no preemption and no priority classes, so it will not reproduce the fragmentation
patterns that make real GPU scheduling hard. And plan diffs against state with no notion of
ignore_changes, lifecycle blocks, or computed attributes — which are where real Terraform plans
get their surprises.
Extensions
- Add route tables. A UDR sending 0.0.0.0/0 to a firewall NVA. Now the prover has to follow the next hop, and "no internet egress" becomes a much harder claim. This is the extension that makes the model realistic.
- Service tags.
Storage,AzureCloud,Internet— expand them into prefixes and watch how much broader real NSG rules are than they look. - Model DNS properly. A private DNS zone, a VNet link, and a record. Then reproduce the failure where the zone exists, the record exists, and the link to the consuming VNet does not.
- Terraform state locking. Two concurrent applies. Show the interleaving that corrupts state, then add the lock.
ignore_changes. Add lifecycle rules and discover the drift that is deliberately invisible — and the argument for and against it.- Gatekeeper in Rego. Express three of these policies in Rego and run them against real Kubernetes manifests. Compare the expressiveness and the reviewability.
- Bin-packing and preemption. Add priority classes, then preempt a low-priority job to fit a gang. The interaction between preemption and gang scheduling is where real schedulers get complicated.
- A cost model. Attach a price to each pool, and answer "what does a warm pool cost per month, and what does the alternative cost in p99 latency?" (Phase 05)
Interview / resume bullets
- "Built a network reachability prover over the platform's topology that answers 'can this workload reach that endpoint, and does the traffic leave the region?' with a counter-example path — which turned a residency claim from an assertion about configuration into a provable property."
- "Found and closed a residency exposure that a per-VNet review had cleared: two peering hops into a legacy VNet with an internet-facing NAT gateway."
- "Enforced infrastructure policy at admission with deny-by-default and fail-closed evaluation, so a bug in a policy denies rather than admits — and every denial names its rule and its reason."
- "Caught the private-endpoint-with-public-access-still-enabled misconfiguration as a policy rule, because a private endpoint does not close the public path and the difference is invisible in a diagram."
- "Modelled GPU capacity with gang scheduling and MIG partitioning, which surfaced the deadlock where a tensor-parallel deployment holds six of the eight GPUs it needs and makes no progress."
- "Established that a nine-minute node-to-serving time makes reactive autoscaling an outage with a graph, and sized a warm pool against the measured arrival distribution instead."