Path 2 · Module 1 · Draft version B: Case study
Design governance
You've just been hired as the Azure architect at Kestrel Logistics. Over the next hour, four colleagues come to you with requests. Each request is one unit of the Microsoft Learn module: management groups, subscriptions, resource groups, tags, Azure Policy, RBAC and landing zones. By the end, you've designed Kestrel's whole governance model, one decision at a time.
- Read the request (orange box). Somebody wants something.
- Predict: before reading on, decide what you'd answer. Then open "My prediction check". Guessing first, even wrong, makes the theory stick much better.
- Learn: the theory you need for this request, and nothing else.
- Decide: the green decision record is what you'd write in a real design document. Together they form Kestrel's design, shown at the end.
Meet Kestrel Logistics
Kestrel moves goods by road across the Netherlands, Germany and Poland. About 2,000 employees. Today, everything runs in one Azure subscription that a developer created three years ago with a company credit card. It holds:
- TrackIt: the customer-facing shipment tracking website (internet-facing, 24/7).
- Fleet: an internal app that collects GPS data from 1,200 trucks (IoT, lots of data).
- Payroll: the HR and payroll system (personal data, strict access).
- A pile of test VMs nobody admits to owning.
The people you'll meet:
| Who | Cares about | |
|---|---|---|
| CFO | Chief Financial Officer | Who spends what. Why is the bill growing? |
| CISO | Chief Information Security Officer | GDPR, data location, who can touch what. |
| DEV | Head of Development | Speed. Teams want to try new services without waiting for tickets. |
| OPS | Platform team lead | Network, identity, monitoring. Fewer surprises at 3 a.m. |
The requests
1 · "Where do we even start?" · Design for governance
"I want control. Data in the wrong country, costs nobody owns, people with admin rights they shouldn't have. Can you fix governance? Where do you start?"
Request 1 of 8
My prediction check · think first, then open
Did you say "start by writing policies"? Most people do. The better first step is structure: a hierarchy to attach the policies to. Read on.
Governance means keeping control over your applications and resources: deciding requirements, planning initiatives and setting priorities. But rules need a place to live. If Kestrel has one subscription, every rule applies to everything: production, test VMs and payroll alike.
So the first step is a hierarchy with four levels, each a place to attach rules:
- Management groups: access, policy and compliance across multiple subscriptions.
- Subscriptions: units of management, billing and scale.
- Resource groups: containers to deploy and manage resources in.
- Resources: the VMs, databases and storage accounts themselves.
Above them is the tenant root group, which contains everything in the Entra tenant. Anything assigned at a level is inherited by everything below it. The governance tools in this module are Azure Policy, tags and RBAC; the hierarchy decides where each one applies.
- Context
- One subscription, no hierarchy; any rule hits everything.
- Decision
- Design a management group → subscription → resource group hierarchy first, then attach Policy, tags and RBAC at the right level.
- Why
- Inheritance means a rule written once covers everything below, including future subscriptions.
2 · "Same rules for every country" · Design for management groups
"GDPR: all our data must stay in the EU. Also in subscriptions teams create next year. And our German entity has a works council that wants HR data in Germany only. How?"
Request 2 of 8
My prediction check · think first, then open
EU-only for everything, now and later → a policy on a top-level management group. Germany-only HR data is one extra rule for a small set; that doesn't automatically need a whole geographic branch (more in request 3).
A management group holds subscriptions (and other management groups) so you can manage them as one. Use them to limit regions across subscriptions, grant access to many subscriptions with one role assignment, and audit roles and policies across subscriptions.
Facts to know:
- The tree can be six levels deep, not counting the root or the subscriptions.
- Each management group or subscription has one parent.
- New subscriptions land under the root by default. That's exactly how the CISO's "next year's subscriptions" would slip through; set a default management group.
- RBAC authorization for creating management groups is off by default; turn on hierarchy protection so not everyone can reshape the tree.
Design recommendations:
- Design with governance in mind: workloads that need the same security, compliance and connectivity rules share a management group.
- Keep it flat: three or four levels.
- A top-level management group (here: "Kestrel") for organisation-wide policies and roles.
- By department or by geography, when rules differ per department or region.
- A production management group for rules that apply to all production workloads.
- A sandbox management group for experiments, isolated from dev, test and production.
- Isolate sensitive data (like the corporate office's HR) in its own management group with enhanced policies.
- Context
- EU-only for all current and future subscriptions; HR has stricter rules; developers want to experiment.
- Decision
- Top-level MG Kestrel (Allowed locations = EU). Under it: Platform, Landing zones (→ Corp, Online), Sandbox. Default MG for new subscriptions = Sandbox. Hierarchy protection on.
- Why
- Three levels, each with its own rules. No country branches: only HR differs per country, which is handled at subscription level.
3 · "Who's paying for all this?" · Design for subscriptions
"One bill, one big number. I want to see what TrackIt, Fleet and Payroll each cost, and test separately from production. Should we split the subscription?"
Request 3 of 8
My prediction check · think first, then open
Yes, split, but not only for cost (tags can do cost too). Split where you need a boundary for billing, admins, scale or compliance. Fleet's IoT volume and Payroll's access rules both qualify.
A subscription is the container you create and pay for resources in. It's a billing boundary, a management boundary and a scale unit (each subscription has limits and quotas). Policies for an individual subscription can meet different compliance standards.
Considerations, applied to Kestrel:
- Treat subscriptions as a democratised unit of management, aligned to business needs: one per application and environment.
- Group them under management groups that carry the shared rules.
- A dedicated shared services subscription for the network (ExpressRoute, Virtual WAN, hub VNet), billed together and isolated from workloads.
- Scale limits: large specialised workloads (IoT, HPC, SAP) get their own subscription so they don't hit limits shared with others. That's Fleet.
- Administration: do these teams need different admins? Payroll does.
- Policy boundary: a workload with extra rules (PCI, or German HR data) can be isolated by a subscription rather than yet another management group.
- Network: a VNet can't span subscriptions; workloads that talk need peering or VPN.
- Owners' responsibilities: run access reviews quarterly or twice a year with Entra Privileged Identity Management.
- Context
- Costs per app and environment; Fleet is IoT-heavy; Payroll needs separate admins; German HR data must stay in Germany.
- Decision
- Platform:
sub-connectivity,sub-identity,sub-management. Online:sub-trackit-prod/dev. Corp:sub-fleet-prod/dev,sub-payroll-prod,sub-payroll-de-prod(extra policy: Germany West Central only). Sandbox: one per team. - Why
- Billing per app/env, Scale for Fleet, Admins and Compliance for Payroll. The German rule sits on one subscription, so no extra MG.
4 · "Let me just delete the test stuff" · Design for resource groups
"My team spins up a whole test environment for every release and forgets to clean up. I want one click to delete it all. But the database team says their databases must never be deleted with the app."
Request 4 of 8
My prediction check · think first, then open
Different lifecycles → different resource groups. The release environment gets its own RG (delete the RG = delete everything); the databases live in another, with a delete lock.
A resource group is the container you deploy resources into. You use it to group resources of similar usage, type or location; to organise by lifecycle; to apply roles; and to protect resources with locks.
Facts that matter in design:
- An RG has a region where its metadata is stored. If that region is down, you can't update its resources, though they keep running.
- Resources in an RG can be in other regions, and can connect to resources in other RGs.
- Resources can be moved between RGs (with some exceptions) and added or removed at any time.
- RGs can't be nested or renamed; each resource is in exactly one.
Strategies: by application (everything for one app, same policies and lifecycle; good for test and prototypes) or by type (all SQL in one RG, all web in another; for shared, on-demand services). Less common: by department, region or cost centre. Most designs combine them, then check: lifecycle, administration overhead (central or decentralised admins?), access control (policy, roles, locks at RG level) and compliance (must the metadata be in a particular region?).
- Context
- Release environments are short-lived; databases are long-lived and shared.
- Decision
- Per app:
rg-<app>-web,rg-<app>-data(CanNotDelete lock),rg-<app>-monitor. Release tests:rg-<app>-rel-<n>, deleted after the release. RG region = West Europe for EU metadata. - Why
- Group by lifecycle; locks protect what must survive.
5 · "Who owns this VM?" · Design for resource tags
"The bill shows 40 VMs called test-vm-something. Nobody owns them. And I still need costs per country, which doesn't match your subscriptions. Can Azure tell me?"
Request 5 of 8
My prediction check · think first, then open
Tags: owner and country, enforced with Azure Policy so they can't be forgotten. Cost Management can group by tag.
Tags add metadata to resources as name-value pairs (env = production). You can put them on resources, resource groups and subscriptions, and add, change or remove them with the portal, CLI, PowerShell, ARM/Bicep or REST. Important: tags on a resource group aren't inherited by its resources.
Start with the goal (search, automation, cost?) and the organisation's own taxonomy. Then choose an alignment: IT-aligned tags (workload, function, environment) simplify operations; business-aligned tags (ownership, cost responsibility, criticality) show business value. Many organisations are moving towards business-aligned, usually mixed with a few IT tags.
| Type | Answers | Kestrel example |
|---|---|---|
| Functional | What does it do? | app = trackit, tier = web, env = prod |
| Classification | How sensitive / critical? | confidentiality = personal, SLA = 24hours |
| Accounting | Who pays? | country = de, costcenter = 4100 |
| Partnership | Who's involved? | owner = fleet-team, contactalias = fleet-ops |
| Purpose | Which business value? | businessprocess = delivery, revenueimpact = high |
Start small: prototype a few critical tags, see if they're used, then add more. Enforce with Azure Policy (require tags on creation, re-add removed ones). And not every resource needs every tag: if only critical resources get impact, the rest are by definition not critical. Ask stakeholders for input before you decide.
- Context
- Unowned resources; costs per country cut across subscriptions.
- Decision
- Mandatory on RGs:
owner,app,env,country,costcenter. Inherited by resources through Policy.confidentialityonly on data resources. - Why
- Five tags is a start the teams will actually fill in. Policy makes them consistent.
6 · "Make it impossible" · Design for Azure Policy
"Decision 2 says EU only. But I don't want a document, I want it impossible to deploy outside the EU. And the storage accounts that already have public access: can those be fixed automatically?"
Request 6 of 8
My prediction check · think first, then open
"Impossible" = a Deny effect. Fixing what already exists = a Modify (or DeployIfNotExists) policy plus a remediation task. Assigning alone only fixes new and updated resources.
Azure Policy creates, assigns and manages rules over resource configurations. Know these:
- Individual policies and groups of them called initiatives; many are built in.
- Policies are inherited down the hierarchy and can be assigned at any level.
- They evaluate Azure resources and Arc-enabled resources outside Azure.
- They show non-compliant resources, prevent new ones, and remediate.
- They integrate with Azure Pipelines (pre- and post-deployment checks).
When does Policy evaluate? On create, update or delete of a resource in scope; on a new assignment; on an updated assignment; and in the standard 24-hour cycle. Expect a short delay before non-compliance shows.
What happens to a non-compliant resource is your choice: deny the change (Deny), log it (Audit), alter the resource (Modify, Append), or deploy a related compliant resource (DeployIfNotExists). The compliance dashboard shows the overall state with drill-down and bulk remediation.
Policy isn't RBAC. RBAC decides who may act; Policy decides what the result may look like, whoever acts. Even an Owner can't deploy a VM in Brazil if Policy denies it. Use both. In the bigger picture: a user gets access via RBAC, it's checked by Conditional Access, watched by Entra ID Protection, and confirmed by access reviews.
- Context
- EU-only must be enforced; existing public storage must be fixed.
- Decision
- On Kestrel MG: Allowed locations (Deny), Require tags on RGs (Deny), Inherit tags (Modify). On Landing zones MG: Storage public access disabled (Modify) + remediation task. On Corp MG: deny public IPs.
- Why
- Deny where a mistake is unacceptable; Modify + remediation where the fix is automatic.
7 · "Everybody is Owner" · Design for RBAC
"In the old subscription, 35 people are Owner, assigned one by one. Developers need to deploy their apps, but they must never touch the network. And the Payroll vendor needs to restart one VM, nothing else."
Request 7 of 8
My prediction check · think first, then open
Assign roles to groups; developers get Contributor on their own subscriptions (the network lives in the connectivity subscription they have no role on); the vendor gets a custom role (VM start/restart) scoped to that one VM.
Azure RBAC evaluates each request and allows or blocks it. It's an allow model: you can do only what a role explicitly allows. Typical uses: one user manages VMs, another VNets; a DBA group manages all SQL databases; a user manages one resource group; an application accesses a resource group.
How to design it:
- Define roles → assign them to principals (users, groups, service principals) → scope them (MG, subscription, RG, resource). Assign at the highest scope that meets the requirement, no higher.
- Least privilege: limit roles and scopes, so a compromised account can do less damage. A scope-role matrix helps.
- Groups, not users: fewer assignments to manage.
- Custom roles when no built-in role fits; they can be shared between subscriptions that trust the same Entra tenant.
- Overlapping assignments add up: Contributor on the subscription + Reader on an RG = Contributor on that RG too.
| Azure Policy | Azure RBAC | |
|---|---|---|
| Focus | Properties of resources | What users can access |
| Implement by | Rules | Roles + scopes |
| Default | Allow | Deny |
- Context
- Too many individual Owners; devs must not change the network; a vendor needs one action.
- Decision
- Entra groups per team.
grp-platform: Owner on Platform MG.grp-<app>-dev: Contributor on their app subscriptions. Vendor: custom role "VM Operator" (start/restart/read) on one VM. Quarterly access reviews via PIM. - Why
- Least privilege at the highest fitting scope; groups keep it manageable.
8 · "Can we do this again next year?" · Design for landing zones
"Love the design. Next year we acquire a company with 30 apps. I don't want to do all of this by hand again. And please don't break TrackIt while you build it."
Request 8 of 8
My prediction check · think first, then open
Package decisions 1–7 as a landing zone, deployed with code (the Azure landing zone accelerator). Build it in parallel in the same tenant, then move the old subscription over.
An Azure landing zone is the environment workloads land in, with the foundation in place before they arrive. Like a new neighbourhood where water, gas and electricity are connected before the houses go up: network, identity and access, policies and monitoring are ready first.
- Landing zones are management groups and subscriptions designed to scale.
- A platform landing zone (Identity, Connectivity, Management subscriptions, run centrally) plus application landing zones for workloads in dev, test and prod.
- Policies keep them compliant.
- They're pre-provisioned through code. The recommended way is the Azure landing zone IaC accelerator (Bicep or Terraform with Azure Verified Modules); a portal accelerator exists for teams without IaC skills.
Design considerations: include landing zones in the design; build them in code and expect to refactor (a central team reviewing short- and long-term scenarios limits that); use the accelerator; focus on applications rather than lifting VMs; prefer Azure-native services and follow the platform roadmap; scope for migrations and greenfield across the whole portfolio; and to transition an existing estate, deploy the accelerator into the same tenant in parallel with a new MG structure, then move subscriptions. An Azure landing zone review assessment helps check the result.
- Context
- Growth by acquisition; the existing subscription runs production.
- Decision
- Deploy decisions 1–7 with the landing zone accelerator (Bicep) in the existing tenant, in parallel. Move TrackIt, Fleet and Payroll into new subscriptions one by one. New acquisitions get application landing zones from the same code.
- Why
- Repeatable, reviewed in code, no disruption to running workloads.
Kestrel's design, all together
Which decision answered "EU only, also for future subscriptions", and with what?
Decisions 2 and 6: an Allowed locations policy with Deny, on the top-level Kestrel management group, plus a default MG for new subscriptions.
Why did Payroll-DE get a subscription and not a management group?
One extra rule for one workload: a subscription is also a policy boundary, so it isolates it without growing the tree.
How do developers deploy apps but never touch the network?
Contributor on their own app subscriptions; the network lives in sub-connectivity, where only the platform group has a role.
Module assessment
1. All current and future subscriptions in the company may only use EU regions. Where do you assign the policy?
C. A management group assignment is inherited by every subscription under it, including new ones.
2. One application processes card payments and needs extra PCI policies. You want as few management groups as possible. What do you do?
B. A subscription is a policy boundary too, so it isolates the workload without another MG.
3. Resources must carry their resource group's costcenter tag, including resources that already exist. What do you use?
D. Tags don't inherit. The Modify policy fixes new resources; a remediation task fixes existing ones.
4. A user is Contributor on a subscription and Reader on one resource group in it. What can they do in that resource group?
A. RBAC is additive. Contributor from the subscription still applies.
5. The region of a resource group has an outage. Its VMs run in another region. What's true?
C. The RG's metadata is unavailable, so management operations fail; the resources themselves keep working.
6. A company with an existing Azure estate wants landing zones without disrupting running workloads. What do you recommend?
B. A new MG structure next to the existing one, in the same tenant, doesn't affect current workloads.
Design exercise
Larkspur Health runs three hospitals in the Netherlands and one clinic in Belgium. Requirements:
- All patient data must stay in EU regions. The Belgian clinic has an extra national rule: its data must stay in Belgium Central.
- Finance wants costs per hospital and per application.
- Three applications: the patient portal (internet-facing), the internal HR system, and a research platform that needs large GPU quotas.
- Each application has dev and prod. Developers must be able to try new services without risk to production.
- A central platform team runs the network (ExpressRoute to the hospitals) and identity. Application teams must not change the network.
- Minimise administrative effort.
-
Task
Design the management group hierarchy
Draw the tree from the tenant root down to (but not including) subscriptions. Write next to each management group why it exists.
Done when- The tree has at most 4 levels below the root.
- Every management group has a governance reason (a policy or access rule that differs from its siblings).
- There's a place for experiments that's isolated from production.
Hint
Start from the landing zone reference architecture (Platform, Landing zones, Sandbox, Decommissioned). Which requirement is different for the Belgian clinic?
Model answer
- Larkspur (top level): Allowed locations = EU regions; required tags; Defender for Cloud.
- └ Platform: only the platform team has write access.
└ Identity · Management · Connectivity. - └ Landing zones: deny changes to the hub network for app teams; diagnostics to the central workspace.
└ Corp (internal: HR, research): deny public IPs.
└ Online (patient portal): WAF in front of public endpoints. - └ Sandbox: no ExpressRoute connectivity, budget alerts, looser service list.
- └ Decommissioned.
The Belgian rule applies to the clinic's subscriptions (an extra Allowed locations assignment), not a separate geographic MG, since it's one rule for a few subscriptions. Splitting by hospital isn't needed: hospitals differ in cost, not in governance, and tags solve cost.
-
Task
Decide subscriptions and resource groups
List the subscriptions and, for one application, its resource groups. Give the "BASC" reason for each subscription.
Done when- Dev and prod are separated.
- The GPU-heavy research platform doesn't share quota with others.
- The network has its own subscription.
Model answer
sub-connectivity(Admins + Billing: ExpressRoute, hub VNet),sub-identity,sub-management(Log Analytics, automation).sub-portal-prod,sub-portal-devunder Online (Compliance: internet-facing rules).sub-hr-prod,sub-hr-devunder Corp.sub-research-prod,sub-research-devunder Corp (Scale: GPU quota).sub-sandbox-*per team under Sandbox.- For the patient portal (prod):
rg-portal-web,rg-portal-data,rg-portal-monitor; grouped by lifecycle (data lives longer than the web tier).
-
Task
Attach tags, policies and roles
Make a table: requirement → control → scope, for every requirement in the scenario.
Done when- Each requirement maps to Policy, RBAC, tags, or a structure choice.
- Roles are assigned to groups, at the highest scope that fits.
- Cost per hospital is possible even for shared resources.
Model answer
Requirement Control Scope EU only Policy: Allowed locations (Deny) Larkspur MG Belgium Central for the clinic Policy: Allowed locations (Deny), narrower Clinic subscriptions Cost per hospital and app Tags hospital,app,env(accounting/functional); Policy: require on RG + inherit to resourcesLanding zones MG App teams can't change the network RBAC: Network Contributor only for the platform group; app groups get Contributor on their own subscriptions Connectivity subscription / app subscriptions Safe experiments Sandbox MG + budget alerts, no peering to hub Sandbox MG Minimise effort Landing zone accelerator in code; groups instead of users Whole tenant
- You can explain what each level of the hierarchy is a boundary for, and when to create a new one.
- You can choose between Policy, RBAC and tags for a requirement, and pick the scope.
- You can describe a landing zone and how to adopt one next to an existing estate.