Migration Patterns
How to migrate existing Azure environments to landing zone architecture.
Migration Scenarios
Migration Assessment
Current State Analysis
Assessment Queries
// Get all subscriptions
ResourceContainers
| where type == "microsoft.resources/subscriptions"
| project subscriptionId, name, tags
// Get resource count by type
Resources
| summarize count() by type
| order by count_ desc
| take 20
// Get VNets and address spaces
Resources
| where type == "microsoft.network/virtualnetworks"
| extend addressSpace = properties.addressSpace.addressPrefixes
| project name, resourceGroup, subscriptionId, addressSpace
// Check for public IP addresses
Resources
| where type == "microsoft.network/publicipaddresses"
| project name, resourceGroup, subscriptionId, properties.ipAddress
// Check encryption status
Resources
| where type == "microsoft.storage/storageaccounts"
| extend encryption = properties.encryption.services.blob.enabled
| project name, resourceGroup, encryption
Migration Phases
Phase 1: Foundation
Phase 2: Governance
Phase 3: Workload Migration
Subscription Migration
Moving Subscriptions to Management Groups
// Move subscription to target management group
resource subscriptionPlacement 'Microsoft.Management/managementGroups/subscriptions@2021-04-01' = {
name: '${managementGroupId}/${subscriptionId}'
}
PowerShell Migration Script
# Migration script
param(
[string]$SubscriptionId,
[string]$TargetManagementGroupId
)
# Get current placement
$subscription = Get-AzSubscription -SubscriptionId $SubscriptionId
$currentMG = Get-AzManagementGroup | Where-Object {
$_.Children.Id -contains "/subscriptions/$SubscriptionId"
}
Write-Host "Current MG: $($currentMG.DisplayName)"
Write-Host "Target MG: $TargetManagementGroupId"
# Move subscription
New-AzManagementGroupSubscription `
-GroupId $TargetManagementGroupId `
-SubscriptionId $SubscriptionId
Write-Host "Subscription moved successfully"
Network Migration
VNet Integration Pattern
Peering Existing VNets
// Create peering from hub to existing VNet
resource peeringToExisting 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2023-05-01' = {
parent: hubVnet
name: 'peer-to-existing-vnet'
properties: {
remoteVirtualNetwork: {
id: existingVnetId
}
allowVirtualNetworkAccess: true
allowForwardedTraffic: true
allowGatewayTransit: true
useRemoteGateways: false
}
}
// Create reverse peering
resource peeringFromExisting 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2023-05-01' = {
parent: existingVnet
name: 'peer-to-hub'
properties: {
remoteVirtualNetwork: {
id: hubVnet.id
}
allowVirtualNetworkAccess: true
allowForwardedTraffic: true
allowGatewayTransit: false
useRemoteGateways: true
}
}
Policy Migration
Gradual Policy Enforcement
Audit-First Approach
// Step 1: Deploy in audit mode
resource policyAssignmentAudit 'Microsoft.Authorization/policyAssignments@2022-06-01' = {
name: 'require-encryption-audit'
location: location
properties: {
policyDefinitionId: policyDefinition.id
displayName: 'Require encryption (Audit)'
enforcementMode: 'DoNotEnforce' // Audit only
}
}
// Step 2: After remediation, enable enforcement
resource policyAssignmentEnforce 'Microsoft.Authorization/policyAssignments@2022-06-01' = {
name: 'require-encryption-enforce'
location: location
properties: {
policyDefinitionId: policyDefinition.id
displayName: 'Require encryption (Enforce)'
enforcementMode: 'Default' // Full enforcement
}
}
Remediation Tasks
// Create remediation task for non-compliant resources
resource remediationTask 'Microsoft.PolicyInsights/remediations@2021-10-01' = {
name: 'remediate-diagnostics'
properties: {
policyAssignmentId: policyAssignment.id
policyDefinitionReferenceId: 'deployDiagnostics'
resourceDiscoveryMode: 'ExistingNonCompliant'
}
}
Tagging Migration
Tag Discovery Query
// Find resources without required tags
Resources
| where isnull(tags.CostCenter) or isnull(tags.Environment)
| project name, type, resourceGroup, subscriptionId, tags
Bulk Tag Update Script
# Update tags on existing resources
param(
[string]$SubscriptionId,
[hashtable]$RequiredTags
)
Set-AzContext -SubscriptionId $SubscriptionId
$resources = Get-AzResource | Where-Object {
$null -eq $_.Tags.CostCenter
}
foreach ($resource in $resources) {
$tags = $resource.Tags
if ($null -eq $tags) {
$tags = @{}
}
# Add missing tags
foreach ($key in $RequiredTags.Keys) {
if (-not $tags.ContainsKey($key)) {
$tags[$key] = $RequiredTags[$key]
}
}
Set-AzResource -ResourceId $resource.ResourceId -Tag $tags -Force
Write-Host "Updated: $($resource.Name)"
}
Migration Runbook
Pre-Migration Checklist
## Pre-Migration Checklist
### Discovery
- [ ] Complete resource inventory
- [ ] Document network topology
- [ ] Identify IP address conflicts
- [ ] Catalog existing policies
- [ ] List RBAC assignments
- [ ] Identify compliance requirements
### Planning
- [ ] Define target architecture
- [ ] Create management group hierarchy plan
- [ ] Plan IP address scheme
- [ ] Define subscription organization
- [ ] Create migration wave plan
- [ ] Identify dependencies
### Preparation
- [ ] Deploy landing zone foundation
- [ ] Configure hub networking
- [ ] Set up centralized logging
- [ ] Prepare policy definitions
- [ ] Test in sandbox subscription
### Communication
- [ ] Notify stakeholders
- [ ] Schedule migration windows
- [ ] Document rollback procedures
- [ ] Establish support channels
Migration Wave Template
## Migration Wave: [Wave Name]
### Subscriptions in Scope
| Subscription | Current MG | Target MG | Owner |
|--------------|-----------|-----------|-------|
| sub-app1-prod | None | Corp-Prod | Team A |
| sub-app1-dev | None | Corp-Dev | Team A |
### Pre-Migration Tasks
- [ ] Backup configurations
- [ ] Document current RBAC
- [ ] Snapshot network config
### Migration Steps
1. [ ] Move subscription to target MG
2. [ ] Verify policy inheritance
3. [ ] Peer VNet to hub
4. [ ] Update DNS settings
5. [ ] Validate connectivity
6. [ ] Assign RBAC
### Post-Migration Validation
- [ ] Test application connectivity
- [ ] Verify policy compliance
- [ ] Check monitoring data
- [ ] Validate access controls
### Rollback Plan
If issues occur:
1. Move subscription back to original MG
2. Remove VNet peering
3. Restore original DNS
4. Contact support
Common Challenges
IP Address Conflicts
Dependency Discovery
// Find cross-subscription dependencies
Resources
| where type == "microsoft.network/privateendpoints"
| extend targetResource = tostring(properties.privateLinkServiceConnections[0].properties.privateLinkServiceId)
| project name, subscriptionId, targetResource
| where targetResource !contains subscriptionId
Quick Reference Card
| Phase | Duration | Activities |
|---|---|---|
| Assessment | 2-4 weeks | Discovery, gap analysis |
| Foundation | 2-4 weeks | MG, policies, hub network |
| Governance | 2-4 weeks | Policy rollout (audit → deny) |
| Migration | 4-12 weeks | Workload waves |
| Optimization | Ongoing | Continuous improvement |
Conclusion
Congratulations! You've completed the Azure Landing Zones guide. You now have the knowledge to:
- ✅ Design enterprise-scale Azure environments
- ✅ Implement governance with Azure Policy
- ✅ Configure hub-spoke or Virtual WAN networking
- ✅ Deploy with Bicep or Terraform
- ✅ Automate subscription vending
- ✅ Handle multi-region and hybrid scenarios
- ✅ Migrate existing environments