The brief
The client's requirement, one sentence longer than last time: "We want a small web application whose storage is not reachable from the internet at all — not firewalled, not permissioned, unreachable — and we want proof, because our last vendor said private and meant password-protected." That distinction — a locked door versus no door — is Class Fourteen's entire argument, and this build makes you construct it, break it once on purpose, and document the difference.
- Deliverable
- A running two-tier arrangement — public web front, private storage back — inside the Build I estate, plus an evidence runbook in the repository: the tests a stranger could re-run to verify each privacy claim.
Build inside Build I's nonprod environment; the governance you made there now governs you, which is the point — your own allowed-locations policy and tag rules should be felt at least once during this build, and the runbook should say where.1 Everything runs at the cheapest tiers and deletes cleanly; the one component that bills meaningfully while idle is named in the marginalia.
Requirements — the ledger you build against
Rows in dependency order. R4 through R6 are the heart; everything else exists so they have somewhere to happen.
| # | Requirement | Taught in | Evidence |
|---|---|---|---|
| R1 | A VNet with a deliberate address plan and at least an app and a data subnet, sized with headroom | Class 10 | The plan in the README — ranges, sizes, and one sentence on why they overlap nothing you might bridge to |
| R2 | An NSG on the data subnet admitting only the app subnet on the service port, nothing else | Class 10 | The rule list, with the immovable default-deny visible beneath your rules |
| R3 | A small web app (App Service) integrated into the VNet for outbound traffic | Classes 11, 14 | The integration blade; a request from the app reaching a private address |
| R4 | A storage account reached through a private endpoint in the data subnet, with its private DNS zone linked to the VNet | Classes 12, 14 | An nslookup from inside the VNet resolving the account's name to the private IP — the load-bearing screenshot |
| R5 | Public network access on the storage account: Disabled — and anonymous blob access off at the account level | Classes 12, 14 | The same blob fetched twice in the runbook: from the app, succeeding; from your laptop, refused |
| R6 | The app authenticates to storage with its managed identity and a data-plane role — no connection string, no key in configuration | Classes 9, 12 | The app settings, keyless; the role assignment on the account |
| R7 | The evidence runbook: every claim above paired with the command or test that proves it, re-runnable by a stranger | Classes 15–16 | The repository — including the one test that fails correctly (the laptop fetch) |
Private means no door — prove the absence.
The boundaries again. Do not over-build: no pipelines, no custom domains, no multi-region — Build III automates, and the front-door tier from Class Thirteen is deliberately out of scope until the interviewer question asks why. The deliberate break is required, not optional: once everything works, unlink the private DNS zone, watch the app fail exactly as Class Fourteen's case file predicted, relink it, and write down both observations. An engineer who has seen the failure owns the pattern; one who has only seen success has memorised it.
The rubric — how a reviewer marks it
Same bands as Build I, sharpened for a build whose subject is proof.
- Functional — the floor
- The app serves, the blob loads through the private path, and public access is genuinely disabled. The plumbing works; the story is thin.
- Reasoned — the target
- Functional, plus the runbook: each privacy claim paired with its passing test, the laptop fetch failing on camera, and the address plan defended in writing. "It is private" has become "here is how you would check."
- Professional — the ceiling
- Reasoned, plus the deliberate break documented — the DNS unlink, the failure mode, the fix — and the estate still clean under Build I's governance: tagged, in-region, least-privileged. This version converts Class Fourteen's hardest interview question into a story you have personally survived.
The capping deduction, in this build's spirit: a storage account key or connection string anywhere in app settings caps the build at Functional — the private path is worth little if the credential beside it grants the public one back.
What an interviewer will ask
The questions this artifact provokes, in arrival order. Rehearse aloud.
- "Why isn't a firewall rule enough?"
- A firewalled public endpoint is a locked door on a public street — still visible, still probed, still one misconfiguration from open. A private endpoint removes the door. If you can draw the two side by side, do.
- "Walk me through what happens when the app resolves the storage name."
- The Class Fourteen chain, aloud: the public name, the privatelink CNAME, the private DNS zone linked to the VNet, the private IP. Interviewers ask this one precisely because the DNS half is the half people skip.
- "What broke when you unlinked the zone?"
- The honest answer from your own runbook: resolution fell back to the public address, which refused the call because public access is disabled — a silent path change surfacing as a loud failure. Having done this on purpose is the seniority signal.
- "How does the app authenticate to storage?"
- Managed identity and a data-plane role — nothing stored, nothing to rotate, nothing to leak. The follow-up is always "and if it lived outside Azure?"; the answer is Build III's subject, and saying so shows you know the map.
- "What would you change for production?"
- Bigger tiers, a WAF at the front door per Class Thirteen, monitoring per Phase Four — named as deliberate omissions. Scope chosen, not stumbled into, exactly as in Build I.
The pattern Campux tripped on, in your hands
Campux built exactly this arrangement across Phase Two — and, in Class Fourteen's case file, shipped the classic mistake: the private endpoint green, the DNS zone forgotten, the storefront's images dark. You will make the same mistake on purpose, which is better than reading about it and cheaper than making it in production. When Build III arrives, this environment is what the pipeline will learn to deploy; keep the repository, because its README grows a pipelines section next.
- If you tore down Build I's Azure resources, re-create the nonprod resource group and the two policy assignments first — twenty minutes, and this build's estate lands governed from birth, which is the habit the sequence is teaching. VNet integration on App Service needs a paid tier; the cheapest that supports it is fine, and the runbook should note the tier and its monthly price so the cost is a decision, not a surprise. ↩