Skip to main content

Architecture overview

The Azure Baseline is one Microsoft Entra ID tenant with a management group, mg-acme, that holds 14 subscriptions in two groups, a hub virtual network (VNet) whose Azure Firewall carries every spoke's egress and transit traffic, guardrail and compliance policies assigned at the top of the tree, and a pipeline that plans every change on a pull request and applies it on merge. Everything is OpenTofu and Terragrunt code, reviewed in GitHub and applied by continuous integration (CI).

The subscriptions​

mg-acme sits under the Tenant Root Group with two children: mg-acme-core for the subscriptions that run the landing zone and mg-acme-plat for the four workload subscriptions. acme-core-root sits directly under mg-acme. Every policy is assigned at mg-acme, so no subscription Owner can remove it.

GroupSubscriptionsWhat they hold
Rootacme-core-rootManagement groups, subscription creation, guardrail and compliance policy, the state storage account, the Entra ID diagnostic settings
Security and evidenceacme-core-security, acme-core-auditThe security workspace and alert action group, the SOPS keys, the DDoS plan switch; the audit workspace, immutable audit storage and its key, the KQL alerts
Identityacme-core-identityEntra ID group role assignments, Privileged Identity Management (PIM), Conditional Access
Network and DNSacme-core-network, acme-core-dnsThe address plan, hub VNet, Azure Firewall, DNS Private Resolver, private DNS zones, the point-to-site VPN switch; the public DNS zones with DNSSEC
Deliveryacme-core-artifacts, acme-core-autoContainer registry, shared storage, Unity Catalog metastore storage; the CI identities, the CI platform Key Vault, the runner VNet and the Container Apps runners
Reservedacme-core-corp, acme-core-publicBaselined and ready; acme-core-public is the only subscription where public blob access is allowed
Workloadsacme-plat-sandbox, acme-plat-dev, acme-plat-staging, acme-plat-prodOne subscription per stage, identical in shape: a spoke VNet peered to the hub, its route table, private DNS links and the contract Key Vault the blueprints read

Every subscription carries the same subscription baseline: registered resource providers, Microsoft Defender for Cloud plans and the security contact, Activity Log export to the audit workspace and storage, Network Watcher and a locked baseline resource group. Each one also has ten Center for Internet Security (CIS) activity-log alerts and an observability link to the security subscription. Multi-subscription topology lists the units of every subscription.

The network​

Each workload subscription has one spoke VNet with purpose-named subnets for Kubernetes, ingress, private endpoints, Private Link Service, Container Apps, Databricks and data stores, and no public subnet. In the default egress mode a spoke has no NAT gateway of its own: its route table sends 0.0.0.0/0 and the organization range to the firewall's private address, so internet egress and traffic between spokes both pass Azure Firewall in the hub.

The firewall policy groups the spokes into isolation domains, prod and nonprod (sandbox, dev, staging) by default. Traffic inside a domain and to the hub and runner networks is allowed; traffic between domains is denied before any web rule. Web egress is TCP 80 and 443 to the internet, or an allow-list of domain names on the Standard and Premium firewall. Platform services are reached through private endpoints whose records live in ten central Private Link zones, resolved through the DNS Private Resolver beside internal.company.com. Every address range comes from one file, vnet_map.yaml.

Two network options are built and off, each one switch in network.hcl with its price beside it: a point-to-site VPN gateway with Entra ID sign-in for engineers, and a NAT gateway per spoke (hub_egress = "spoke_nat") in place of the firewall. Azure Firewall Standard is the default and costs about $912 per month plus $0.016 per GB in eastus2 at list price. Hub-and-spoke networking describes the routing.

Identity and access​

People sign in with Entra ID. Thirteen ACME_* groups and ACME_BreakGlass, owned by your identity provider or created by the code, are mapped to Azure role-based access control (RBAC) at management-group and subscription scope. Owner and Security Admin can become just-in-time PIM roles with one switch, which needs Entra ID P2. Four Conditional Access policies (multifactor authentication for every user, no legacy authentication, phishing-resistant multifactor authentication for privileged roles, multifactor authentication for Azure management) are deployed in report-only mode until their results are reviewed.

Pipelines hold no secret. Each repository has its own user-assigned managed identity in acme-core-auto, federated to GitHub Actions through OpenID Connect (OIDC) for exact subjects only: the pull request, the main branch or a named GitHub Environment.

Security, compliance and audit​

ServiceDefaultRole
Microsoft Defender for CloudOnContainers, Storage, Key Vault and Resource Manager plans in every subscription; servers, CSPM, Cosmos DB and API plans off
Azure Policy guardrailsOnSecurity guardrails, region restriction, audit protection and the tag policy, assigned at mg-acme
Compliance initiativesOnMicrosoft cloud security benchmark and the 13-control SOC 2 baseline initiative in audit mode; nine more, one switch each
Audit workspace and storageOnLog Analytics with 365-day retention; storage with 365-day immutability, encrypted with a customer-managed key
Entra ID log exportOnSign-in and audit logs to the audit workspace
CIS activity-log and KQL alertsOnTen activity-log alerts per subscription and six KQL alerts on the audit workspace, sent to one action group
Microsoft SentinelOffOnboarding of the security workspace, $2.46 per GB analytics tier
Azure DDoS Network ProtectionOffOne plan for the organization's virtual networks, $2,944 per month
Defender for Storage malware scansOffOn-upload malware scanning, $0.15 per GB scanned

All security switches live in one file, security.hcl, owned by the security team.

Delivery​

State for every unit lives in one storage account in acme-core-root with Entra ID authentication only, blob versioning and a delete lock. Four workflows move changes: a plan on every pull request after static guardrails, an apply on merge behind the prod GitHub Environment's required reviewers, scheduled drift detection that opens an issue, and a runner-image build. The plan and apply run on self-hosted GitHub runners in Azure Container Apps, which reach the state account and the vaults through private endpoints. See GitOps and infrastructure as code.

Where the blueprints fit​

Each workload subscription publishes a contract Key Vault, kv-acme-eus2-<stage>-plat, with the values its workloads need: subnet and route table IDs, DNS zones, the registry, the action group and the deployer identities. The blueprints read it at plan time with their own identities and never read Baseline state. Start with the Web App Blueprint, the Data and ETL Blueprint or the Secrets Blueprint.