# Azure Reachability Assurance Lab toolkit

Version **0.1.1-preview**. Staged source, not a published download. One authorized finite Azure trial has completed; independent reader replay and settled-cost review remain outstanding. See [measured results and negative findings](VALIDATION.md).

## What readers take away

Turn "this workload is contained" into a falsifiable claim: **which exact operation can this identity perform through this path, what removes the unwanted operation, and does required access survive?**

Start offline. Then, only with a separately approved disposable Azure scope and spend estimate, collect a baseline, identity-only, network-only and combined comparison. Finally break required authorization and restore only the narrow grant. Keep denied, timed-out, missing and unexecuted cases distinct.

This toolkit is not a scanner, penetration-testing framework, production remediation script or tenant certification. It tests three direct reads in one topology. It does not prove a universal maximum blast radius.

## Quick start: no cloud account or charges

Prerequisite: Python 3.10+ standard library. From this directory:

```powershell
python -m unittest discover -s tests -v
python exercise.py --output "$env:TEMP\reachability-exercise"
python validate.py --evidence "$env:TEMP\reachability-exercise" --exercise
```

The generated records are explicitly `SYNTHETIC`. They are never accepted as live observations without `--exercise`, and exercise output is never a measured Azure result. The exercise deliberately creates one unexpected spare-container allow; the first validation should **exit 1**. Find the bad record, explain why the network treatment cannot protect two containers on the same endpoint, then run:

```powershell
python exercise.py --output "$env:TEMP\reachability-exercise-corrected" --corrected
python validate.py --evidence "$env:TEMP\reachability-exercise-corrected" --exercise
```

Both fixture sets are fictional learning aids, not results to copy into an assessment.

## Proposed Azure experiment

Read [the runbook](RUNBOOK.md), [permissions and pricing checklist](APPROVAL.md), and [limitations](LIMITATIONS.md) before considering deployment.

The source creates two Linux VMs, two StorageV2 accounts, three containers, two Blob private endpoints, private DNS, a workspace, Blob diagnostics and source NSGs in a **new disposable resource group**. The worker has a system-assigned identity; a separate seeder VM/identity writes deterministic synthetic markers and is deallocated after its temporary writer grants are removed.

R is required data in the primary account, S is a spare container in that same account, and C is a separate canary account. No account keys, SAS tokens or human access tokens are used in probe output.

There are no VM public IPs, inbound access, production peering or VPN links. **There is public management egress:** a NAT public IP and outbound HTTPS to the `AzureCloud` service tag support VM-agent Run Command. This tag is broad, not a destination-specific exfiltration boundary. Do not claim zero public egress. Private Storage public access is independently disabled. The kit is for Azure public cloud only.

Management and the test path are not independent against a hostile Azure administrator. Run Command is privileged guest execution; its output can be truncated and its agent/egress can fail. The runner rejects unparseable output, never turns it into a successful test.

## Local source validation

Azure CLI with its Bicep component is needed only for compilation/deployment:

```powershell
az bicep build --file main.bicep --stdout > "$env:TEMP\reachability-template.json"
python package.py --output "$env:TEMP\reachability-release"
```

Compilation is not region/SKU/policy/permission/runtime validation. `package.py` makes a versioned ZIP, SHA-256 sidecar and per-file manifest from an explicit source allowlist. It does not upload or publish anything. Tests, worksheets and unapproved approval template travel with the package; evidence and filled approvals do not.

## Azure execution: separate approval required for each run

Copy `approval.example.json` **outside this source directory**. Complete every field after reviewing current regional prices and permissions. Set `approved` true only when you have authority for that scope. Choose a real, time-limited expiry and a new unique `ra-lab-...` group name; do not use an existing group. `--approved` is also required for every cloud action.

```powershell
python lab.py plan --approval C:\private\approval.json
python lab.py deploy --approval C:\private\approval.json --approved
python lab.py seed --approval C:\private\approval.json --approved
python lab.py probe --approval C:\private\approval.json --state baseline --approved
```

These are instructions for a new approved run, not permission to reuse the author's subscription or approval. Each state must be probed successfully before transitioning. See RUNBOOK.md for the complete sequence, including recovery and cleanup.

## Evidence and reader adaptation

Raw evidence stays in the external `evidence_directory` named in the approval. Keep it restricted: identities, subscriptions, resource IDs, DNS/IP details and log URIs can be sensitive. Publish only a reviewed sanitized copy with stable aliases. Never commit filled approvals, raw logs or tokens.

Use `WORKSHEET.md` to map your own required and prohibited operations **on paper first**. Adapting the design requires a new scope review, cost estimate, permission review and test matrix; the runner deliberately refuses production groups and arbitrary targets. Do not point it at your application.

Before public release: review the retained live failures and cleanup evidence, confirm attributable settled costs, conduct independent reader replay, then rerun article QA and Council Gate 2. The first finite Azure trial is not a generally proven or release-approved evidence pack.
