The Junior Climb hardcover mockup
The Spoke Contract: What Platform Guarantees and What Workloads Own

The Spoke Contract: What Platform Guarantees and What Workloads Own

The subscription arrived from the vending pipeline. Right management group. Peering up. DNS linked. Budget attached. The app team opened a ticket anyway: “need the platform team to create our App Service and Key Vault.”

You already paid for that ticket in Deployment Model. Two pipelines. Platform owns the seams. Workload owns the app. Without a written contract, every landing turns into a negotiation.

This is article one of Series 2. Series 1 built the zone and the deployment model. Here is what the next app team can expect from you, and what stays off the platform rota.

A contract is not a Confluence page

If the only copy of “how we land a workload” lives in a wiki that died at the last reorg, you do not have a contract. You have folklore. Folklore becomes a Teams thread at 4 p.m. on Friday when someone needs a private endpoint and the platform engineer who remembers the DNS zones is on PTO.

I still walk into tenants where the “platform onboarding guide” is a PowerPoint from the CAF workshop and a Teams channel named #landing-zone-help. That is not an interface. That is a queue with better branding.

Write the contract in the same place as the spoke module. README is fine. A short markdown file in the platform repo is better. It has to answer four questions without a meeting:

  1. What does the platform always provide when a subscription is vended?
  2. What does the workload team create with their own pipeline?
  3. What requires a platform change request (and why)?
  4. What is explicitly out of scope until the next product increment?

Microsoft’s Cloud Adoption Framework talks about application landing zones as the place workloads land with shared platform services underneath. The contract is how you make that sentence operable. If the app team cannot answer those four questions from a file in git, CAF language will not save Friday.

Subscription design already set the billing and blast-radius boundary. Vending should already return: management group placement, spoke VNet, peering, UDRs, DNS links, tags, budget, workload identity with Contributor in that subscription. The spoke contract starts where that factory stops. Everything after that is either workload-owned or a catalog item you have not built yet.

Spoke contract: vending feeds platform guarantees into a spoke subscription where workloads own apps, SKUs, and blast radius.

Platform guarantees (the boring list)

Platform owns anything every spoke needs, whether the app team knows the resource name or not. Enterprise-scale / ALZ guidance puts connectivity, identity, management, and security in platform subscriptions for a reason. You do not reinvent that split per team.

  • Hub connectivity: peering or virtual hub connection, default route to Azure Firewall or NVA, ExpressRoute or VPN path that already works
  • Private DNS: virtual network links for the privatelink.* zones you actually resolve in production
  • Identity seams: workload service principal or managed identity scoped to the subscription, PIM for humans, no standing Owner on the management group
  • Guardrails: Azure Policy assignments that already apply at the management group, not a custom exemption per team
  • Observability seams: diagnostic settings to the platform Log Analytics workspace (or the second workspace you meant), not a sandbox someone will delete
  • Cost seams: the four tags (Environment, CostCenter, Owner, Application) and a budget that pages Owner

If any of those are “we will peer it later,” you did not vend a spoke. You vendored a ticket. Deployment Model already said the pipeline has to win. Put the list where app teams can read it so they ask for catalog items instead of miracles.

Private DNS is the seam people undersize. Networking already covered why. The contract must say: platform owns the zones and the links; workloads create private endpoints that register into those zones. When two teams each create privatelink.blob.core.windows.net in their own subscription, you get split-brain DNS and a week of “it works from my laptop.”

Publish the guarantee list with the subscription welcome message. Link identity, policy, and logging from that same page. Resource IDs the workload module needs (workspace ID, DNS zone IDs, subnet IDs) belong in vending output, not in a spreadsheet someone emails once.

Workload owns (the uncomfortable list)

Workloads own the resources that make the application real: App Services, Azure SQL, storage, Function Apps, their own Key Vault if the pattern allows it, their containers, their alert rules for app SLOs.

They also own the blast radius of bad choices. Wrong SKU. Public access left on because the private endpoint “was next sprint.” Console logging that fills the workspace. A second VNet created in the portal because the spoke “didn’t have enough subnets.”

Platform is not the app team’s Terraform shop. Create their App Service “just this once” and every other team learns the contract is optional. Microsoft will happily let Contributor in a subscription build almost anything. Your job is to decide what that identity is allowed to build without opening a platform ticket.

I use a crude test in design reviews: if the resource dies at 2 a.m., whose phone rings for the platform path versus the app path? Hub firewall pages platform. App Service 500s page the app owner. If both ring the same three people for everything, you do not have a contract. You have a hero team.

Workload ownership includes the pipeline identity that deploys those resources. That identity is Contributor in the subscription and nothing above it. If it can edit firewall policy or management group policy, identity already failed. The contract should name the identity, the role, and the repo that is allowed to use it.

The seam most teams get wrong

Shared platform components that look like app resources: private DNS zones, the hub firewall policy, the central Key Vault used for platform secrets, the Log Analytics workspace.

App teams should consume those. They should not own them. Consuming means a link, a private endpoint into a zone you manage, a diagnostic setting to a workspace ID you publish, or Key Vault RBAC on a vault in their subscription. A documented shared vault is fine when it has a naming convention and purge protection you will defend.

When an app team gets Contributor on the hub resource group “so they can add a DNS record,” identity already failed. DNS records for private endpoints belong in a platform pipeline or a tightly scoped role on the zone. Not Owner on the hub. Not a weekend break-glass that never expires.

The same rule applies to policy exemptions. An exemption on a Deny for public network access is a platform change with an owner and an expiry. It is not a favor in chat. Policy only works when the exception path is slower and louder than the default path.

Change requests that are allowed to exist

Some asks are real platform work. Expanding address space. Adding a private DNS zone for a new PaaS type. Opening a firewall network rule that every spoke will need. Changing a Deny policy that blocks a legitimate SKU. Those map to Microsoft-supported patterns: IP planning, Private Link DNS, Azure Firewall policy, Azure Policy effects. They are not “please click the portal for me.”

Those go through a change path: canary first (nonprod management group or one spoke), then a PR, with an on-call who knows the hub is in play. Slack approvals do not count. List the request types and the SLA you will actually meet. Two business days for a firewall rule that already has a pattern. Longer for address space, because address space is a migration pretending to be a parameter.

Everything else is “use the workload module” or “that is not a platform product yet.” Undocumented exceptions feel helpful until the next team expects the same click. Policy taught you Audit then Deny. The contract teaches you the same discipline for human exceptions: date, owner, expiry.

Write the allowed request types into the contract with examples. “Add privatelink.azurecr.io” is a platform PR. “Create App Service plan P1v3” is a workload PR. “Peer spoke A to spoke B” is usually a refuse, with a pointer to the connectivity article later in this series. Ambiguous tickets are how platform engineers become human routers.

What the contract says about AKS and shared runtimes

If you run AKS as a platform product, say so. Cluster lifecycle, node pools, ingress, and cluster-level identity stay platform. Namespaces, deployments, and app-level Key Vault references stay workload. If every team gets their own cluster on day one, say that too. The failure mode is an unspoken hybrid where the platform team rebuilds node pools for every hotfix and the app team still opens tickets for DNS.

Shared App Service plans and shared SQL servers follow the same rule. Name the owner. Name the blast radius. Name who gets Contributor where. Vague “we share compute to save money” language is how two products share an outage channel.

How you know the contract is working

Measure the tickets. If more than half of platform intake is “create my App Service” or “peer my VNet,” the contract is invisible or the workload module does not exist. If intake is “add privatelink.azurecr.io to the hub zones” and “raise the prod SKU allow-list,” the contract is doing its job.

Track three numbers monthly: percentage of intake that is catalog work, median time from vend request to usable nonprod subscription, and count of portal-created resources that policy or the next apply had to clean up. Those numbers tell you whether the contract is a document or an operating model.

Publish the contract next to the vending docs. Link it from the welcome message that goes out with a new subscription ID. The next article turns the contract into three reference spokes you can point at instead of inventing a design per team. Web or API, data, and integration on the same spoke module. That is how you stop negotiating architecture one ticket at a time.

Randy Bordeaux

Azure Trainer | Veteran | Engineer

Helping IT professionals grow through cloud, leadership, and shared knowledge.


Discover more from Randy Bordeaux

Subscribe to get the latest posts sent to your email.

Discover more from Randy Bordeaux

Subscribe now to keep reading and get access to the full archive.

Continue reading