Most teams want to start using Azure right away: a few VMs, some App Services, maybe an AKS cluster. The groundwork gets skipped because it doesn’t feel like progress. Six months later there are security findings, higher costs than planned, and governance problems that take weeks to clean up.
I’ve seen this happen many times. This post describes the foundation I would put in place first.
What the foundation covers
The foundation is governance policies, network topology, identity and access, a security baseline, and management tooling. Without governance every team does its own thing, without a network design you end up with unrelated network setups, and without identity management you chase security issues one by one. Fixing these later, while production workloads are running, takes months.
Microsoft’s Cloud Adoption Framework and Azure Landing Zones are the reference. They cover everything, which can be too much at the start. You don’t need all of it on day one. Focus on the things that cause the most common problems.
Management group hierarchy
Management groups contain subscriptions and let you apply policies and access control at scale. A typical structure:
Tenant Root Group├── Platform│ ├── Management│ ├── Connectivity│ └── Identity├── Landing Zones│ ├── Production│ └── Non-Production└── SandboxPlatform holds shared infrastructure. The Management subscription runs monitoring and automation, Connectivity has the networking hub, and Identity holds identity infrastructure if you need it.
Landing Zones is where workloads run. Split by environment at minimum. Some organizations add business unit or application levels. The governance framework post goes deeper into governance across this hierarchy.
Sandbox is for experiments: looser policies, isolated from everything else, so developers can break things without affecting production.
Subscription strategy
Subscriptions are the main isolation boundary in Azure. Resource limits, billing and access control all apply at subscription level. Moving resources between subscriptions later is painful, so plan this early.
Start with at least these subscriptions:
- Management: Log Analytics workspace, automation accounts, backup vaults.
- Connectivity: hub VNet, VPN or ExpressRoute gateways, Azure Firewall, DNS.
- Production landing zone: production workloads, possibly several subscriptions per application or business unit.
- Non-production landing zone: dev, test and staging, separate from production for cost tracking and security.
- Sandbox: individual subscriptions for teams that need to experiment.
Each subscription needs a documented owner and purpose, so it’s clear where a new workload goes.
Azure Policy
Azure Policy enforces rules across the environment and prevents mistakes such as deploying in the wrong region or creating public IPs where they shouldn’t exist.
The first policy I assign is allowed locations:
{ "properties": { "displayName": "Allowed Locations", "policyType": "BuiltIn", "mode": "All", "description": "Restrict resource deployment to approved regions", "parameters": { "listOfAllowedLocations": { "type": "Array", "metadata": { "description": "The list of allowed locations for resources" } } } }}Assign it at the root management group. All resources then deploy only in approved regions, which also avoids surprises from regions with higher pricing.
Other policies I add early:
- Require tags: make CostCenter, Environment and Owner mandatory for cost allocation.
- Restrict VM SKUs: an allowlist of sizes, so nobody creates VMs that cost thousands per month.
- Require encryption at rest for storage accounts, SQL databases and managed disks.
- Block public endpoints in production subscriptions unless explicitly approved, so traffic goes through the hub.
- Enforce naming conventions. The Azure name validator checks names against Azure’s rules.
Start with a few policies in Audit mode, look at what would be blocked, talk to the teams, then switch to Deny. Deny from day one causes friction and leads to workarounds outside the platform. For policy at scale across several management groups, see Enterprise Policy as Code (EPAC).
Hub and spoke network
Hub and spoke is the standard Azure topology. The hub VNet contains shared services like firewall, VPN gateway and DNS. Spoke VNets contain workloads and are peered to the hub.
Hub VNet subnets:
Hub VNet (10.0.0.0/16)├── GatewaySubnet (10.0.0.0/24) - VPN/ExpressRoute gateway├── AzureFirewallSubnet (10.0.1.0/24) - Azure Firewall├── Management (10.0.2.0/24) - Jump boxes, management tools└── SharedServices (10.0.3.0/24) - DNS, NTP, etcSpoke VNets:
Production Spoke (10.1.0.0/16)├── Web Tier (10.1.1.0/24)├── App Tier (10.1.2.0/24)└── Data Tier (10.1.3.0/24)
Non-Prod Spoke (10.2.0.0/16)├── Web Tier (10.2.1.0/24)├── App Tier (10.2.2.0/24)└── Data Tier (10.2.3.0/24)Traffic between spokes goes through Azure Firewall in the hub.
Azure Virtual WAN makes sense for multiple regions or complex connectivity. For most environments, standard hub and spoke is enough.
Use RFC 1918 address space and make sure it doesn’t overlap with on-premises networks if you have hybrid connectivity. The subnet calculator helps with the address plan.
Identity and access
In the cloud, identity is the security perimeter, and Entra ID is the base for it.
Enable MFA for everyone, starting with admin accounts. Conditional Access makes this manageable.
Choose the authentication method with the upcoming changes in mind. From September 1st, 2026 Entra rolls out passkeys as the default authentication experience, and on February 1st, 2027 Microsoft-provided SMS and voice are retired with no opt-out. For a new foundation, register passkeys from the start instead of building on a method that is being retired.
Assign permissions to Entra ID groups, never directly to users.
Use Privileged Identity Management (PIM) for admin roles. Nobody should hold Global Administrator permanently. Access is activated when needed and expires automatically, which limits the damage if credentials are compromised. My PIM guide covers the configuration in detail.
Use service principals and managed identities for automation, not personal accounts. Managed identities remove credential handling entirely.
Role assignments should follow least privilege:
# Bad - Too broadNew-AzRoleAssignment -SignInName user@company.com -RoleDefinitionName "Contributor" -Scope "/subscriptions/xxx"
# Good - Specific scope and roleNew-AzRoleAssignment -SignInName user@company.com -RoleDefinitionName "Virtual Machine Contributor" -Scope "/subscriptions/xxx/resourceGroups/rg-prod-web"Built-in roles often grant more than needed. Create custom roles where that’s the case.
Security baseline
Security should be part of the foundation from the start:
- Microsoft Defender for Cloud: enable the Standard tier on all subscriptions for continuous assessment and threat protection.
- Microsoft Sentinel: SIEM and SOAR that collects and analyzes logs and automates responses. Run it from the management subscription.
- Network Security Groups on every subnet, default deny inbound from the internet, explicit allow rules only for required traffic.
- Azure Key Vault for passwords, certificates and keys. No secrets in code or config files. Plan your key management with quantum-safe cryptography in mind.
- Diagnostic settings that send logs from every resource to the central Log Analytics workspace. Without logs you can’t investigate incidents.
- Update Management for automated VM patching in defined maintenance windows. Unpatched VMs are one of the most common ways in.
- Azure Backup for VMs, databases and file shares, with regular restore tests. A backup you never restored is not proven to work.
Defender plans as code:
# Enable individual Microsoft Defender for Cloud plans per subscription# Each plan protects a specific resource typeSet-AzSecurityPricing -Name "VirtualMachines" -PricingTier "Standard"Set-AzSecurityPricing -Name "SqlServers" -PricingTier "Standard"Set-AzSecurityPricing -Name "AppServices" -PricingTier "Standard"Set-AzSecurityPricing -Name "StorageAccounts" -PricingTier "Standard" -SubPlan "DefenderForStorageV2"# Also consider: "Containers", "KeyVaults", "Dns", "Arm", "CosmosDbs"
# Enable Defender CSPM (Cloud Security Posture Management) for governance visibilitySet-AzSecurityPricing -Name "CloudPosture" -PricingTier "Standard"
# Note: Auto-provisioning is now managed through Defender for Cloud's# "Environment settings" in the portal or via the Security Connectors API.# The old Set-AzSecurityAutoProvisioningSetting cmdlet is deprecated.Run this on all subscriptions and automate it, so new subscriptions are configured automatically.
Management and monitoring
Azure Monitor provides the visibility:
- Log Analytics workspace: one central workspace in the management subscription. Retention depends on compliance requirements, 90 days minimum and longer in regulated industries.
- Azure Monitor for VMs: performance metrics, dependency mapping and health for all VMs.
- Application Insights: application telemetry for requests, dependencies, exceptions and custom metrics.
- Alerts on resource health, performance and security events. Too many alerts get ignored, too few miss real issues, so tune them.
- Workbooks: dashboards with the metrics that matter for your environment.
- Cost Management: budgets at subscription and resource group level, so you’re alerted before the budget is exceeded. See budget alerts with Terraform.
A script to deploy diagnostic settings:
# Deploy diagnostic settings to resources that support them$resources = Get-AzResource$workspaceId = "/subscriptions/xxx/resourceGroups/rg-management/providers/Microsoft.OperationalInsights/workspaces/law-central"
foreach ($resource in $resources) { try { Set-AzDiagnosticSetting -ResourceId $resource.ResourceId ` -WorkspaceId $workspaceId ` -Enabled $true ` -Name "send-to-law" ` -ErrorAction Stop } catch { # Not all resource types support diagnostic settings - skip silently Write-Verbose "Skipping $($resource.ResourceType): $_" }}Not all resource types support diagnostic settings, so the try/catch skips the ones that don’t. At scale, a DeployIfNotExists policy is the better option because it also covers new resources without rerunning a script.
Deployment automation
Use Infrastructure as Code, Bicep or Terraform, and stick to one. Deploying through the portal is neither repeatable nor scalable.
Keep the templates in Git and deploy with Azure Pipelines or GitHub Actions. Every infrastructure change then goes through source control and is traceable and reversible.
A Bicep example for a spoke VNet with NSGs and hub peering:
param location string = resourceGroup().locationparam vnetName stringparam addressPrefix stringparam subnets arrayparam hubVnetId string
resource vnet 'Microsoft.Network/virtualNetworks@2023-05-01' = { name: vnetName location: location properties: { addressSpace: { addressPrefixes: [ addressPrefix ] } subnets: [for subnet in subnets: { name: subnet.name properties: { addressPrefix: subnet.addressPrefix networkSecurityGroup: { id: resourceId('Microsoft.Network/networkSecurityGroups', '${subnet.name}-nsg') } } }] }}
resource peering 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2023-05-01' = { parent: vnet name: 'peer-to-hub' properties: { remoteVirtualNetwork: { id: hubVnetId } allowVirtualNetworkAccess: true allowForwardedTraffic: true allowGatewayTransit: false useRemoteGateways: true }}useRemoteGateways: true requires a virtual network gateway in the hub. On a first deployment the peering fails if the gateway doesn’t exist yet. Either deploy the gateway first, or start with useRemoteGateways: false and change it once the gateway is ready.
Documentation
Document the foundation briefly and in a form people will actually read:
- Management group and subscription structure, with the purpose of each
- Network topology and IP address allocation
- RBAC model and how to request access
- Naming conventions and tagging standards
- Deployment process for new workloads
- Security requirements and policies
- Monitoring and alerting configuration
- Incident response procedures
Keep it in the Git repository next to the IaC templates and update it together with the infrastructure. Outdated documentation misleads people.
What to do first
You won’t build all of this on day one. Prioritize by risk. My week-one list:
- Management group structure
- Initial subscriptions
- Azure Policy for allowed locations and tagging
- Hub VNet with Azure Firewall
- Entra ID groups for access control
- Log Analytics workspace
- Microsoft Defender for Cloud
The rest can follow step by step, as long as there is a plan.
Common mistakes
- Starting without a plan. Deploying first and sorting it out later creates expensive technical debt.
- Over-engineering. Build for current needs with room to grow, not for a scale you won’t reach with 50 VMs.
- Manual processes. They don’t scale and lead to configuration drift.
- Weak RBAC. Giving everyone Contributor because it’s easier causes security problems later.
- Ignoring cost. Without budget alerts and SKU restrictions, costs grow quickly.
- No monitoring. You should know about failures before your users do.
The foundation is never finished. New services, requirements and threats keep coming, so build it to change while keeping security, governance and manageability in place.
Sources
- “Azure landing zones,” Cloud Adoption Framework, Microsoft Learn, https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/
- “What are Azure management groups?,” Microsoft Learn, https://learn.microsoft.com/en-us/azure/governance/management-groups/overview
- “Hub-spoke network topology in Azure,” Azure Architecture Center, https://learn.microsoft.com/en-us/azure/architecture/networking/architecture/hub-spoke
- “Define your naming convention,” Cloud Adoption Framework, Microsoft Learn, https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming
- “Conditional Access overview,” Microsoft Learn, https://learn.microsoft.com/en-us/entra/identity/conditional-access/overview
- “What is Microsoft Defender for Cloud?,” Microsoft Learn, https://learn.microsoft.com/en-us/azure/defender-for-cloud/defender-for-cloud-introduction
- “What is Microsoft Sentinel?,” Microsoft Learn, https://learn.microsoft.com/en-us/azure/sentinel/overview
- “Azure Policy overview,” Microsoft Learn, https://learn.microsoft.com/en-us/azure/governance/policy/overview
- “Azure Monitor overview,” Microsoft Learn, https://learn.microsoft.com/en-us/azure/azure-monitor/overview