Warmup Guide — The Azure Principal: Control Plane, Well-Architected & Tradeoffs
Zero-to-principal primer for Phase 00. We start from "what even is Azure when you strip the portal away" and end with the arithmetic and the artifacts that turn architectural opinion into engineering: the single control plane and the resource-ID address space, the control-plane/data-plane split, the five Well-Architected pillars, SLA composition and downtime math, first-order cost modeling, and the Architecture Decision Record. Every later phase plugs a real Azure service into a slot in the model built here.
Table of Contents
- Chapter 1: Azure Resource Manager — The One Control Plane
- Chapter 2: The Resource ID — Azure's Address Space
- Chapter 3: Control Plane vs Data Plane
- Chapter 4: The Well-Architected Framework — Five Pillars
- Chapter 5: SLA Composition — The Reliability Arithmetic
- Chapter 6: Availability Zones & Paired Regions
- Chapter 7: Cost Modeling and "Spend the Headroom"
- Chapter 8: The ADR — Making a Tradeoff Durable
- Lab Walkthrough Guidance
- Success Criteria
- Interview Q&A
- References
Chapter 1: Azure Resource Manager — The One Control Plane
From zero. When you click "Create a virtual machine" in the portal, run
az vm create, terraform apply, or New-AzVM, none of those is "talking to a VM." They
are all generating one thing: an HTTPS request to a single deployment-and-management API
called Azure Resource Manager (ARM). The portal is a JavaScript app that calls ARM. The
CLI is a Python app that calls ARM. Terraform's azurerm provider is a Go binary that calls
ARM. There is exactly one front door, and everything in this curriculum sits behind it.
What it is. ARM is the control-plane API and deployment engine in front of every Azure write. A request is an HTTP method against a resource URI with an API version:
PUT https://management.azure.com
/subscriptions/{sub}/resourceGroups/{rg}
/providers/Microsoft.Storage/storageAccounts/{name}?api-version=2023-01-01
Authorization: Bearer <Entra access token>
Content-Type: application/json
{ "location": "eastus", "sku": { "name": "Standard_LRS" }, "kind": "StorageV2" }
Why it exists. Before ARM (the "classic"/ASM era), each service had its own management API, its own permissions model, and no shared notion of grouping, tagging, templating, or dependency ordering. ARM unifies all of that: one auth model (Entra), one authorization model (RBAC + Policy), one identity for resources (the resource ID), one grouping primitive (resource groups), one templating/deployment engine, and one audit log (Activity Log). The payoff is that governance, automation, and reasoning generalise across every service.
How it works under the hood. A single write travels a fixed pipeline. Memorise it; it is the spine of phases 01–05:
client (portal / az / Terraform / SDK)
│ PUT /subscriptions/.../{type}/{name}?api-version=… + Bearer token
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Azure Resource Manager (management.azure.com) │
│ │
│ 1. AUTHENTICATE — validate the Entra (Azure AD) JWT: signature, iss, │
│ aud=https://management.azure.com, exp/nbf │
│ 2. AUTHORIZE — RBAC: union(Actions) − union(NotActions) across all │
│ role assignments at this scope and every ancestor; │
│ then DENY ASSIGNMENTS — a deny always wins │
│ 3. POLICY — Azure Policy: deny / append / modify / audit / │
│ deployIfNotExists evaluated against the request │
│ 4. ROUTE — hand the validated request to the resource provider │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
Resource Provider (Microsoft.Storage) → reconciles desired state, returns 200/201
Idempotency is the load-bearing property. ARM PUT is idempotent by design: the body
describes the desired state of the resource, not a delta. Issue the same PUT twice and
the second one is a no-op convergence to the same state — no duplicate resource, no error.
Formally, if apply is the state transition and s the desired state, then
$$ \text{apply}(\text{apply}(x, s), s) = \text{apply}(x, s) $$
— applying twice equals applying once. This is why Terraform, Bicep, and ARM templates can
re-run safely, why a retried deployment doesn't double your VMs, and why "declarative
infrastructure" works at all. (POST actions — start/stop/regenerate-key — are the
non-idempotent exceptions; they are operations, not state.)
Production significance. When something fails to deploy, the question is which stage of
that pipeline rejected it: a 401 is authentication (token), a 403 is authorization
(RBAC or a deny assignment or a Policy deny), a 409 is a conflict, a 429 is
throttling, and a 5xx from the provider is the service itself. Knowing the pipeline turns a
vague "it won't deploy" into a one-line diagnosis.
Common misconceptions.
- "The portal does special things the API can't." No — the portal is strictly a client of ARM. Anything it does, the API does.
- "
PUTandPOSTare interchangeable." No —PUTis idempotent desired-state;POSTis a non-idempotent action. Retrying aPOSTcan double-execute. - "ARM stores my data." No — ARM manages the resource's existence and configuration (control plane). Your blobs, secrets, and messages live in the data plane (Chapter 3).
Chapter 2: The Resource ID — Azure's Address Space
From zero. Every resource in Azure has exactly one canonical name — a path, like a file path, called the resource ID:
/subscriptions/{subscriptionId}/resourceGroups/{rgName}/providers/{namespace}/{type}/{name}
A concrete example:
/subscriptions/0000…/resourceGroups/rg-prod/providers/Microsoft.Storage/storageAccounts/stprod001
Why it exists. The resource ID is not just a name — it is simultaneously the unit of RBAC scope, Policy scope, tagging, locks, and the audit trail. When you grant a role, assign a policy, place a delete-lock, or read the Activity Log, you do it at a resource ID (or a prefix of one). One address space, reused for everything.
How it works under the hood — the hierarchy and scopes. Read the segments as key/value pairs:
| Segments present | Scope level | Example |
|---|---|---|
subscriptions/{s} | subscription | /subscriptions/0000… |
…/resourceGroups/{rg} | resourceGroup | …/resourceGroups/rg-prod |
…/providers/{ns}/{type}/{name} | resource | …/Microsoft.Storage/storageAccounts/st001 |
Above subscriptions sit management groups (P05), giving the full inheritance chain:
Tenant Root MG ──▶ Management Group ──▶ Subscription ──▶ Resource Group ──▶ Resource
(/providers/Microsoft.Management/managementGroups/{name}) (this is where the ID address space starts)
A role or policy assigned at any node inherits down to every descendant. Assign Reader
at the subscription and the principal can read every RG and resource under it. This is the
single most important fact for reasoning about "who can touch this?": you cannot answer it
by looking at the resource alone — you must look up the chain.
Nested types. Some resources live inside others, and the ID nests the type path:
/subscriptions/0000…/resourceGroups/rg-net
/providers/Microsoft.Network/virtualNetworks/vnet-hub/subnets/snet-app
Here the type is the slash-joined path virtualNetworks/subnets and the name is the
leaf (snet-app), not the parent (vnet-hub). Subnets, blob containers, Key Vault
secrets, and SQL databases are all nested types. Your lab's parse_resource_id must keep
the leaf name and join the type path — exactly the rule production tooling uses.
Resource providers. The {namespace} (Microsoft.Storage, Microsoft.Compute,
Microsoft.Network, …) names the resource provider (RP) — the service that owns those
types and implements their control-plane CRUD. An RP must be registered on a subscription
before its types can be created (az provider register --namespace Microsoft.Storage); the
classic "the subscription is not registered to use namespace X" error is a missing
registration.
Production significance. Parsing and classifying a resource ID is the first move in every governance and incident task: what scope is this, what inherits onto it, and which RP do I escalate to? The lab makes you build that parser so the structure is muscle memory.
Common misconceptions.
- "The resource group's region is where my resource runs." No — the RG region is where the
RG's metadata lives; the resource has its own
location. - "GUIDs in the ID are the names." The subscription is a GUID; resource and RG names are human strings you choose. Don't confuse the two.
- "A subnet's name is the vnet." No — it's the leaf segment after
subnets/.
Chapter 3: Control Plane vs Data Plane
From zero. There are two completely separate systems hiding behind one resource:
- The control plane manages the resource's existence and configuration: create the
storage account, change its SKU, set its firewall, delete it. This is ARM (Chapter 1),
authorized by RBAC
Actions. - The data plane is the stuff inside the resource: the blobs in the account, the
secrets in the vault, the messages in the queue, the rows in the database. This is a
different endpoint (
stprod001.blob.core.windows.net, notmanagement.azure.com), with its own throttling, its own SLA, and its own authorization via RBACDataActions.
Why it exists. Managing a resource and using its data are genuinely different concerns with different blast radii. The person who provisions a storage account (an infra engineer) is often not the person who should read customer blobs (an application). Splitting the authorization lets you grant one without the other.
How it works under the hood. A role definition carries four lists:
Actions — control-plane verbs allowed (e.g. Microsoft.Storage/storageAccounts/read)
NotActions — control-plane verbs subtracted
DataActions — data-plane verbs allowed (e.g. .../blobServices/containers/blobs/read)
NotDataActions — data-plane verbs subtracted
Effective permission is union(Actions) − union(NotActions) for the control plane and the
DataActions equivalent for the data plane — evaluated independently. The canonical trap:
| Role | Control plane (Actions) | Data plane (DataActions) | Can it read a blob? |
|---|---|---|---|
| Owner | * (everything, incl. manage keys) | (none) | No — not directly by Entra identity |
| Storage Blob Data Reader | (none) | …/blobs/read | Yes |
So a storage-account Owner can change the firewall, regenerate keys, and delete the account — but is not automatically allowed to read a blob with their Entra identity. (They can grab the account key — a control-plane action — and use that, which is exactly why key-based access bypasses data-plane RBAC and why principals disable shared-key auth.)
Production significance. A large share of "I'm an Owner but I get 403 Authorization Permission Mismatch" tickets are this exact split: control-plane access, no DataAction.
The fix is to assign a data role (Storage Blob Data Reader/Contributor,
Key Vault Secrets User), not to escalate the control-plane role. Recognising it on sight is
a principal signal.
Common misconceptions.
- "Owner can do anything." On the control plane, yes; on the data plane, only via keys, not via their Entra identity by default.
- "It's the same SLA." No — control plane and data plane publish separate SLAs and have separate throttling limits.
Chapter 4: The Well-Architected Framework — Five Pillars
From zero. The Azure Well-Architected Framework (WAF) is Microsoft's rubric for "is this a good architecture?", expressed as five pillars. It exists because "good" is meaningless without axes, and these are the five every design review scores against:
- Reliability — does it stay up and recover? (SLA, redundancy, failover, retries, no single points of failure). Quantified by the math in Chapter 5.
- Security — is it safe? (identity as the perimeter, least privilege, encryption, network isolation, secrets in Key Vault, deny-by-default).
- Cost Optimization — is the spend justified? (right-sizing, reservations/savings plans, autoscale, scale-to-zero, lifecycle tiering, egress awareness — Chapter 7).
- Operational Excellence — can a team run it? (IaC, CI/CD, monitoring, runbooks, incident response — the pillar that dominates total cost over a system's life).
- Performance Efficiency — does it meet its latency/throughput targets and scale without over-provisioning? (the right SKU, caching, async, partitioning).
Why it exists and why it's a tradeoff model. You cannot maximise all five — they pull against each other:
| You add… | Pillar it helps | Pillar it hurts |
|---|---|---|
| Multi-region active/active | Reliability, Performance | Cost (2× compute + egress), Operational Excellence (more to run) |
| Private Endpoints everywhere | Security | Operational Excellence (DNS complexity — the #1 failure) |
| Aggressive autoscale-to-zero | Cost | Performance (cold starts), Reliability (warm-up gaps) |
| Strict policy-as-code gates | Security, Operational Excellence | velocity (developer friction) |
So the WAF is not a checklist you "pass" — it is a scoring function whose weights come from
the workload. A payments system weights Reliability and Security; an internal batch tool
weights Cost. The principal move is: name the pillar you are trading, quantify both ends,
choose, and write the ADR (Chapter 8). The lab's resolve_tradeoff is this scoring
function, and its headline test proves the consequence: the same two architectures flip
winners when the weights change.
The math the lab uses. Score each architecture $A$ on each pillar $p \in P$ as $s_{A,p} \in [0,1]$, with workload weights $w_p \ge 0$. The weighted, normalised score is
$$ \text{Score}(A) = \sum_{p \in P} s_{A,p} \cdot \frac{w_p}{\sum_{q} w_q} $$
The winner is the higher score; the deciding pillar is the one with the largest weighted advantage for the winner, $\arg\max_p (s_{\text{win},p} - s_{\text{lose},p}) \cdot \frac{w_p}{\sum_q w_q}$ — the one sentence you put in the ADR ("we chose multi-region because reliability dominated for this workload").
Common misconceptions.
- "There's a best architecture." No — there's a best architecture for a given set of weights. Asking "what's the best?" without the workload is a category error.
- "Security and cost are separate teams' problems." No — they are pillars you trade in one design, simultaneously.
Chapter 5: SLA Composition — The Reliability Arithmetic
From zero. A Service Level Agreement (SLA) is a published availability number — App Service 99.95 %, zone-redundant SQL 99.99 %, a single VM with premium SSD 99.9 %. The catch: Azure publishes a number per service, never a composite for your topology. You compose it by hand. This is the single most useful piece of arithmetic in a design review.
Serial dependencies multiply. If a request must traverse several components and any one being down fails the request (a hard dependency chain — web app → SQL → Key Vault), the availabilities multiply:
$$ A_{\text{serial}} = \prod_{i} A_i $$
Three 99.9 % services in series:
$$ 0.999 \times 0.999 \times 0.999 = 0.999^3 \approx 0.997002999 $$
— roughly 99.7 %, about 3× the downtime of a single component. Every hop you add to the request path lowers the composite SLA. This is the quantitative reason "just add another microservice" is never free.
Redundant copies combine. If you have several interchangeable copies and the system is down only when all of them are down (active/active across zones), the un-availabilities multiply:
$$ A_{\text{redundant}} = 1 - \prod_{i} (1 - A_i) $$
Two 99 % copies:
$$ 1 - (1 - 0.99)^2 = 1 - 0.01^2 = 1 - 0.0001 = 0.9999 $$
— two cheap 99 % things give you 99.99 %. Redundancy is how you buy nines.
Nines → minutes (the number that ends the argument). Convert availability to downtime per month (30-day month = 43,200 minutes):
$$ \text{downtime}_{\text{min/month}} = (1 - A) \times 43{,}200 $$
| Availability | Downtime / month | Downtime / year |
|---|---|---|
| 99 % (two nines) | ~432 min (7.2 h) | ~3.65 days |
| 99.9 % (three nines) | ~43.2 min | ~8.76 h |
| 99.95 % | ~21.6 min | ~4.38 h |
| 99.99 % (four nines) | ~4.32 min | ~52.6 min |
| 99.999 % (five nines) | ~0.43 min | ~5.26 min |
The leap from three to four nines is not a config flag — it's multi-AZ or multi-region, a different architecture and a different bill. Knowing the minutes makes the conversation concrete: "you're asking for four nines; that's 4 minutes a month; here's the redundancy that buys it and here's what it costs."
Production significance. Before you commit to an SLA in a contract, you compose it: list the serial path, multiply, then decide which links need a redundant pair to hit the target. The lab makes you compute exactly this.
Common misconceptions.
- "My SLA is the weakest component's SLA." No — serial is the product, which is worse than the weakest link.
- "Redundant copies are independent." Rarely fully — a shared region, shared dependency, or
correlated failure breaks independence, so
1 − ∏(1 − Aᵢ)is an upper bound. Say so in the interview; it's the honest, principal-level caveat (and the lab's extension). - "99.9 % and 99.99 % are basically the same." They are 43 minutes vs 4 minutes a month — a 10× difference and usually a different architecture.
Chapter 6: Availability Zones & Paired Regions
From zero. The redundant-SLA math in Chapter 5 only helps if you have somewhere to put the copies that fails independently. Azure gives you three tiers of blast-radius isolation:
- Availability Zone (AZ) — physically separate datacenter(s) within one region, with independent power, cooling, and network. Spreading replicas across ≥2 zones survives a datacenter-level failure and is the cheapest way to add the redundant term (the cross-zone latency is sub-millisecond; egress between zones in-region is cheap or free for many services). This is how you go from 99.9 % to 99.99 % within one region.
- Region — a geography (East US, West Europe). Multi-region active/active survives an entire region outage but adds full cross-region egress cost and replication complexity — the most expensive reliability you can buy.
- Paired region — most Azure regions have a designated pair in the same geography with platform-coordinated maintenance (the pair isn't updated simultaneously) and, for some services, built-in geo-replication for disaster recovery (e.g. GRS storage, geo-redundant backups). The pair is your DR target, not necessarily your active/active target.
How it maps to the math. "Zone-redundant" services apply Chapter 5's redundant formula for you across zones and publish the higher composite (e.g. zone-redundant SQL 99.99 % vs 99.9 % single-zone). When you go multi-region yourself, you apply the formula — and you discount it for correlation, because a region pair shares a geography and some platform fate.
Production significance. The reliability ladder is: single instance → multi-AZ (zone-redundant) → multi-region active/passive (failover) → multi-region active/active. Each rung adds a redundant term and a cost/operability term. The principal picks the lowest rung that hits the workload's downtime target, because every rung above it is paid for forever.
Common misconception. "Multi-region is always more reliable than multi-AZ." For most workloads multi-AZ already hits four nines at a fraction of the cost and complexity; multi-region buys you region-outage survival specifically, and you should only pay for it if a region outage is in your threat model and your data layer can actually replicate that far without breaking consistency.
Chapter 7: Cost Modeling and "Spend the Headroom"
From zero. You cannot be the cost-optimization person WAF asks for without arithmetic. The first-order monthly bill has three terms, and most real bills are dominated by one of them:
$$ \text{cost}{\text{month}} = \underbrace{H \cdot p{\text{vcpu}}}{\text{compute}} + \underbrace{G_s \cdot p{\text{storage}}}{\text{storage}} + \underbrace{G_e \cdot p{\text{egress}}}_{\text{egress}} $$
where $H$ = compute (vCPU-)hours, $G_s$ = stored GB-months, $G_e$ = egress GB, and the prices approximate Azure list ($p_{\text{storage}}\approx$0.018$/GB-month LRS hot, $p_{\text{egress}}\approx$0.087$/GB internet after the free tier).
The terms to watch.
- Compute is usually the headline, and the levers are right-sizing the SKU, reserved instances / savings plans (up to ~72 % off for a 1–3 year commit), autoscale, and scale-to-zero (Consumption Functions/Container Apps) — trading cold-start latency for near-zero idle cost.
- Storage is cheap per GB but accumulates; lifecycle tiering (hot → cool → archive) and not hoarding redundant copies (LRS vs GRS vs ZRS is a 1–2× multiplier) are the levers.
- Egress is the ambush. Ingress is free; egress (data leaving Azure, or crossing regions) is billed per GB and is what makes chatty multi-region designs quietly expensive. A cross-region call pattern can make egress dominate a bill that "looked like compute."
"Spend the headroom." This is the principal mindset that separates cost-aware design from cheese-paring. If your reliability target is met with headroom, don't buy more nines. If your latency SLA is 15 minutes and you consume 40 seconds, the other ~14 minutes is a cost lever — batch writes harder, use spot/low-priority compute, compact lazily, scale to zero. Juniors optimise the dimension they can see; principals find the unused headroom in one pillar and convert it into savings in another. The same logic runs in reverse: if you're over budget, look for the pillar you're over-delivering on and trade it down.
Production significance. "Make it cheaper" becomes concrete the moment you (a) tag every resource with an owner so the bill is a map, and (b) write the three-term model so you can see which term to attack. Optimising compute when egress dominates is the classic wasted sprint.
Common misconceptions.
- "Storage is the big cost." Usually compute is, then sometimes egress; raw storage is rarely the headline (small files and request costs aside).
- "Reserved instances lock me in dangerously." They commit spend, not a specific VM; savings plans are even more flexible. For steady-state baseline load, not reserving is leaving 30–70 % on the table.
- "Cheaper architecture = better." Only if operability holds — an architecture that needs a dedicated on-call team is not cheaper.
Chapter 8: The ADR — Making a Tradeoff Durable
From zero. A principal's decisions outlive their memory of them and must survive their absence. The Architecture Decision Record (ADR) is the one-page artifact that makes a tradeoff reviewable, teachable, and reversible-on-purpose. It is the output of everything above — you do the SLA math and the cost model, then you record the call.
The template you'll reuse all track:
# ADR-NNN: <short title>
Status: proposed | accepted | superseded by ADR-MMM
Date: YYYY-MM-DD
## Context
The workload's requirements as numbers on the five pillars: target SLA (and the
composed math), budget, latency target, security/compliance constraints, who operates it.
## Decision
What we chose, in one sentence — and the DECIDING PILLAR.
## Alternatives Considered
Each option, and the pillar it traded the wrong way for OUR weights.
## Consequences
What gets better, what gets worse, what we must now monitor, and the number (or
event) that would make us revisit this.
A worked one-liner the lab can emit: "For the payments workload (weights: reliability 4, security 2, cost 1), we chose multi-region active/active over single-region because reliability dominated — composing to 99.99 % (4.3 min/month) vs the single region's 99.9 % (43 min/month). We accept ~2× compute + egress cost and higher operational load; we revisit if a minute of downtime costs less than $X or if the data layer can't sustain cross-region consistency."
Why it matters for your career. An architecture review (interview Round 5, and your day job) is a room full of people pressure-testing your ADRs. The discipline the ADR enforces is exactly Chapter 4's: name the pillar, quantify both ends, choose, and write down what would change your mind. The person whose decisions are legible gets trusted with bigger ones.
Common misconception. "ADRs are bureaucratic overhead." A good ADR is one page and takes ten minutes; it saves the hour-long re-litigation six months later when someone asks "why did we do it this way?" — and you point at the numbers instead of arguing from memory.
Lab Walkthrough Guidance
Lab 01 — WAF Tradeoff Modeler, suggested order (matches the file top-to-bottom):
ResourceId+parse_resource_id(Ch. 1–2). Split on/, strip the leading slash, reject empty/odd segments, then readsubscriptions/{s}→ optionalresourceGroups/{rg}→ optionalproviders/{ns}/{type}/{name}[/{type2}/{name2}…]. For nested types, join the type segments with/and keep the leaf name. RaiseValueErroron every malformed shape — interviewers will hand you a bad ID to see if you validate.resource_scope_level(Ch. 2). Parse, then classify by the deepest field set: provider →resource; resource_group →resourceGroup; elsesubscription.- SLA functions (Ch. 5):
serial_sla(product),redundant_sla(1 − ∏(1 − aᵢ)),downtime_minutes_per_month((1 − A) × 43200). Validate each availability in[0, 1]. The exact-number tests (0.999³ ≈ 0.997002999, two0.99→0.9999) are the boundary probes. monthly_cost_usd(Ch. 7): three terms, all inputs non-negative.Architecture.__post_init__(Ch. 4): all five pillars present, none unknown, each in[0, 1].resolve_tradeoff(Ch. 4): weight-normalised score per architecture; winner + deciding pillar; tie withintol. Maketest_weights_flip_the_winnerpass — and make sure you understand why it's the point of the whole lab.
Success Criteria
You are ready for Phase 01 when you can, from memory:
- Draw the control-plane request pipeline (Entra authenticate → ARM authorize via RBAC,
deny-wins → Policy → resource provider) and say which stage a
401/403/409/429came from. - Explain why every ARM write is an idempotent
PUTto a resource ID, and what idempotency buys IaC. - Parse any resource ID into subscription / RG / provider / type / name (including a nested type) and name its scope and what inherits onto it.
- State why a storage
Ownercannot read a blob with their Entra identity, and the fix. - List the five WAF pillars and give a real tradeoff between two of them.
- Compose a serial and a redundant SLA in your head and convert it to minutes/month.
- Write the three-term cost model and name which term ambushes multi-region designs.
- Write a one-page ADR that names the pillar, quantifies both ends, and states what would change your mind.
Interview Q&A
Q: Walk me through what happens between az storage account create and the account
existing.
The CLI acquires an Entra access token (audience https://management.azure.com) and issues
an idempotent PUT to the resource ID /subscriptions/…/providers/Microsoft.Storage/ storageAccounts/{name}?api-version=…. ARM authenticates the token (signature, iss, aud,
exp), authorizes via RBAC — union(Actions) − union(NotActions) across every assignment at
this scope and its ancestors, then deny assignments where deny wins — evaluates Azure
Policy (a deny effect blocks the write here), and routes the validated request to the
Microsoft.Storage resource provider, which reconciles desired state and returns 201/200.
Re-issuing the same PUT converges with no duplicate — that's the idempotency the whole IaC
model rests on.
Q: I'm an Owner on a storage account but I get 403 reading a blob. Why?
Control plane vs data plane. Owner grants Actions: * — manage the account, set its
firewall, regenerate keys — but no DataActions, so your Entra identity can't read blob
data directly. The fix isn't a bigger control-plane role; it's a data role like
Storage Blob Data Reader. (You could pull the account key — a control-plane action — and
use shared-key auth, which bypasses data-plane RBAC; that's exactly why hardened
environments disable shared-key access and rely on DataActions + Managed Identity.)
Q: A team wants 99.99 % availability. How do you respond?
First I make it concrete: 99.99 % is 4.32 minutes of downtime a month versus 99.9 %'s 43
minutes — a 10× ask. Then I compose their actual topology: if the request path is web → SQL
→ Key Vault, that's serial, so the composite is the product — three 99.9 % services already
fall to ~99.7 %, worse than the target, before we add redundancy. So I find which links
need a redundant pair (zone-redundant SQL gets that link to 99.99 % via 1 − ∏(1 − Aᵢ)),
price the multi-AZ option, and only reach for multi-region if a region outage is in scope —
because that's the most expensive nine and it adds egress and operational load. I write the
ADR with the composed number and the cost.
Q: How do you make a "make it cheaper" mandate concrete? Attribute first — tag every resource with an owner so the bill becomes a map — then write the three-term model (compute + storage + egress) to see which term dominates. The levers are mechanical per term: compute falls with right-sizing + reservations/savings plans + autoscale + scale-to-zero; storage with lifecycle tiering and the right redundancy SKU; egress by killing chatty cross-region patterns. Crucially I hunt for unused headroom — if the SLA or latency target has slack, I spend it: batch harder, use spot, compact lazily. Most "expensive" systems are over-delivering on a pillar nobody is paying for.
Q: Why is "what's the best architecture?" a bad question? Because "best" is undefined without the workload's pillar weights. The Well-Architected pillars conflict — multi-region buys reliability and costs you cost and operability — so the same two designs genuinely flip winners when the weights change (my lab proves this with a test). The right question is "best for these requirements," and the principal's job is to extract those requirements as numbers, score the options, and record the deciding pillar in an ADR. Anyone who answers "best architecture" without asking about the workload is reciting patterns, not engineering.
Q: Difference between a senior and a principal Azure engineer, in one sentence? A senior deploys a correct architecture for a given design; a principal defines the design by composing the SLA, modeling the cost, naming the pillar being traded, and recording the decision in an ADR — so hundreds of other engineers inherit correct tradeoffs by default.
References
- Azure Resource Manager overview — the control plane, request pipeline, resource providers.
- Resource ID & scopes and Understand scope — the address space and inheritance.
- Control plane and data plane operations — the split this phase hammers.
- Azure Well-Architected Framework — the five pillars and the design-review methodology.
- WAF Reliability pillar and target metrics / availability math — SLA composition and downtime targets.
- Azure SLAs for Online Services — the published per-service numbers you compose by hand.
- Availability zones & region pairs and cross-region replication — the redundancy you buy nines with.
- Azure pricing calculator and bandwidth (egress) pricing — the cost model's real numbers.
- Michael Nygard, Documenting Architecture Decisions (2011) — the ADR pattern.
- The track's own CHEATSHEET.md and GLOSSARY.md — the running references.