-
Notifications
You must be signed in to change notification settings - Fork 517
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Update configuration to support bootstrap * Add networking type option * Latest updates for bootstrap * Fix RG name * Add manual whatif overrides * Fix MG id * Revert and add new config * Update for viable what if * Add destroy script * Fix script * Idempotent script * Add groups to config file * Add test starter module * Simplify destroy script * Add folders to retain into config * Latest updates for test module * Fix resource group deletion code * Filter down more * Only remove deployments created by this module * Add PREFIX env var * Add prefix param to avoid confusion * Fix linting * Update accelerator docs * Remove china policies * Fix PowerShell Typo * skip delete on no mg * Add on demand folder support * Update version json * Docs typo * Update wiki for clarity * Add header * Support regional availability zones * Fix incorrect link and misspelling --------- Co-authored-by: Zach Trocinski <30884663+oZakari@users.noreply.github.com> Co-authored-by: Zach Trocinski <ztrocinski@outlook.com>
- Loading branch information
1 parent
b700ac4
commit 8dd8d53
Showing
8 changed files
with
1,222 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
## This script is derived from the original by Jack Tracey, which you can find here: https://github.com/jtracey93/PublicScripts/blob/master/Azure/PowerShell/Enterprise-scale/Wipe-ESLZAzTenant.ps1 | ||
|
||
param ( | ||
[bool]$whatIfEnabled = $true, | ||
[string]$prefix = $env:PREFIX, | ||
[string]$intermediateRootGroupID = $env:MANAGEMENT_GROUP_ID, | ||
[string]$tenantRootGroupID = $env:ROOT_PARENT_MANAGEMENT_GROUP_ID, | ||
[string]$connectivitySubscriptionId = $env:CONNECTIVITY_SUBSCRIPTION_ID, | ||
[string]$identitySubscriptionId = $env:IDENTITY_SUBSCRIPTION_ID, | ||
[string]$managementSubscriptionId = $env:MANAGEMENT_SUBSCRIPTION_ID | ||
) | ||
|
||
if($whatIfEnabled) { | ||
Write-Warning "The deploy stage of this run will delete all aspects of your landing zone. This includes all resources in your platform subscriptions. Please ensure you have a backup of any data you wish to keep." | ||
Write-Warning "DANGER! DO NOT APPROVE THIS RUN UNLESS YOU ARE CERTAIN YOU WANT TO DELETE EVERYTHING." | ||
exit 0 | ||
} | ||
|
||
$managementGroups = Get-AzManagementGroup | ||
$managementGroup = $managementGroups | Where-Object { $_.Name -eq $intermediateRootGroupID } | ||
if($null -eq $managementGroup) { | ||
Write-Warning "The $intermediateRootGroupID does not exist, so there is nothing to delete." | ||
exit 0 | ||
} | ||
|
||
if ($tenantRootGroupID -eq "") { | ||
$tenantRootGroupID = (Get-AzContext).Tenant.TenantId | ||
} | ||
$resetMdfcTierOnSubs = $true | ||
|
||
#Toggle to stop warnings with regards to DisplayName and DisplayId | ||
Set-Item Env:\SuppressAzurePowerShellBreakingChangeWarnings "true" | ||
|
||
# Start timer | ||
$StopWatch = New-Object -TypeName System.Diagnostics.Stopwatch | ||
$StopWatch.Start() | ||
|
||
# Get all Subscriptions that are in the Intermediate Root Management Group's hierarchy tree | ||
$intermediateRootGroupChildSubscriptions = Search-AzGraph -Query "resourcecontainers | where type =~ 'microsoft.resources/subscriptions' | mv-expand mgmtGroups=properties.managementGroupAncestorsChain | where mgmtGroups.name =~ '$intermediateRootGroupID' | project subName=name, subID=subscriptionId, subState=properties.state, aadTenantID=tenantId, mgID=mgmtGroups.name, mgDisplayName=mgmtGroups.displayName" | ||
|
||
Write-Output "Moving all subscriptions under root management group" | ||
|
||
# For each Subscription in Intermediate Root Management Group's hierarchy tree, move it to the Tenant Root Management Group | ||
$intermediateRootGroupChildSubscriptions | ForEach-Object -Parallel { | ||
# The name 'Tenant Root Group' doesn't work. Instead, use the GUID of your Tenant Root Group | ||
if ($_.subState -ne "Disabled") { | ||
Write-Output "Moving Subscription: '$($_.subName)' under Tenant Root Management Group: '$($using:tenantRootGroupID)'" | ||
New-AzManagementGroupSubscription -GroupId $using:tenantRootGroupID -SubscriptionId $_.subID | Out-Null | ||
} | ||
} | ||
|
||
# For each Subscription in the Intermediate Root Management Group's hierarchy tree, remove all Resources, Resource Groups and Deployments | ||
Write-Output "Removing all Azure Resources, Resource Groups and Deployments from Subscriptions in scope" | ||
|
||
$subscriptionsToClean = @() | ||
ForEach ($subscription in $intermediateRootGroupChildSubscriptions) { | ||
$subscriptionsToClean += @{ | ||
name = $subscription.subName | ||
id = $subscription.subID | ||
} | ||
} | ||
|
||
$subscriptionIds = $subscriptionsToClean | Select-Object -ExpandProperty id | ||
|
||
if($subscriptionIds -notcontains $managementSubscriptionId) { | ||
$subscriptionsToClean += @{ | ||
name = "Management" | ||
id = $managementSubscriptionId | ||
} | ||
$subscriptionIds += $managementSubscriptionId | ||
} | ||
|
||
if($subscriptionIds -notcontains $identitySubscriptionId) { | ||
$subscriptionsToClean += @{ | ||
name = "Identity" | ||
id = $identitySubscriptionId | ||
} | ||
$subscriptionIds += $identitySubscriptionId | ||
} | ||
|
||
if($subscriptionIds -notcontains $connectivitySubscriptionId) { | ||
$subscriptionsToClean += @{ | ||
name = "Connectivity" | ||
id = $connectivitySubscriptionId | ||
} | ||
$subscriptionIds += $connectivitySubscriptionId | ||
} | ||
|
||
ForEach ($subscription in $subscriptionsToClean) { | ||
Write-Output "Set context to Subscription: '$($subscription.name)'" | ||
Set-AzContext -Subscription $subscription.id | Out-Null | ||
|
||
# Get all Resource Groups in Subscription | ||
$resourceGroups = Get-AzResourceGroup | ||
|
||
$resourceGroupsToRemove = @() | ||
ForEach ($resourceGroup in $resourceGroups) { | ||
if ($resourceGroup.ResourceGroupName -like "rg-$prefix*") { | ||
$resourceGroupsToRemove += $resourceGroup.ResourceGroupName | ||
} | ||
} | ||
|
||
$resourceGroupsToRemove | ForEach-Object -Parallel { | ||
Write-Output "Deleting $_..." | ||
Remove-AzResourceGroup -Name $_ -Force | Out-Null | ||
} | ||
|
||
# Get Deployments for Subscription | ||
$subDeployments = Get-AzSubscriptionDeployment | ||
|
||
Write-Output "Removing All Successful Subscription Deployments for: $($subscription.name)" | ||
|
||
$deploymentsToRemove = @() | ||
ForEach ($deployment in $subDeployments) { | ||
if ($deployment.DeploymentName -like "$prefix*" -and $deployment.ProvisioningState -eq "Succeeded") { | ||
$deploymentsToRemove += $deployment | ||
} | ||
} | ||
|
||
# For each Subscription level deployment, remove it | ||
$deploymentsToRemove | ForEach-Object -Parallel { | ||
Write-Output "Removing $($_.DeploymentName) ..." | ||
Remove-AzSubscriptionDeployment -Id $_.Id | Out-Null | ||
} | ||
|
||
# Set MDFC tier to Free for each Subscription | ||
if ($resetMdfcTierOnSubs) { | ||
Write-Output "Resetting MDFC tier to Free for Subscription: $($subscription.name)" | ||
|
||
$currentMdfcForSubUnfiltered = Get-AzSecurityPricing | ||
$currentMdfcForSub = $currentMdfcForSubUnfiltered | Where-Object { $_.PricingTier -ne "Free" } | ||
|
||
ForEach ($mdfcPricingTier in $currentMdfcForSub) { | ||
Write-Output "Resetting $($mdfcPricingTier.Name) to Free MDFC Pricing Tier for Subscription: $($subscription.name)" | ||
|
||
Set-AzSecurityPricing -Name $mdfcPricingTier.Name -PricingTier 'Free' | Out-Null | ||
} | ||
} | ||
} | ||
|
||
# This function only deletes Management Groups in the Intermediate Root Management Group's hierarchy tree and will NOT delete other Intermediate Root level Management Groups and their children e.g. in the case of "canary" | ||
|
||
function Remove-Recursively { | ||
[CmdletBinding(SupportsShouldProcess = $true)] | ||
param ( | ||
[string]$name | ||
) | ||
if($PSCmdlet.ShouldProcess($name, "Remove-AzManagementGroup")) { | ||
# Enters the parent Level | ||
Write-Output "Entering the scope with $name" | ||
$parent = Get-AzManagementGroup -GroupId $name -Expand -Recurse | ||
|
||
# Checks if there is any parent level | ||
if ($null -ne $parent.Children) { | ||
Write-Output "Found the following Children :" | ||
Write-Output ($parent.Children | Select-Object Name).Name | ||
|
||
foreach ($children in $parent.Children) { | ||
# Tries to recur to each child item | ||
Remove-Recursively($children.Name) | ||
} | ||
} | ||
|
||
# If no children are found at each scope | ||
Write-Output "No children found in scope $name" | ||
Write-Output "Removing the scope $name" | ||
|
||
Remove-AzManagementGroup -InputObject $parent | Out-Null | ||
} | ||
} | ||
|
||
# Check if Management Group exists for idempotency | ||
$managementGroups = Get-AzManagementGroup | ||
$managementGroup = $managementGroups | Where-Object { $_.Name -eq $intermediateRootGroupID } | ||
|
||
if($null -eq $managementGroup) { | ||
Write-Output "Management Group with ID: '$intermediateRootGroupID' does not exist." | ||
} else { | ||
Write-Output "Management Group with ID: '$intermediateRootGroupID' exists. Proceeding with deletion." | ||
|
||
# Remove all the Management Groups in Intermediate Root Management Group's hierarchy tree, including itself | ||
Remove-Recursively($intermediateRootGroupID) | ||
} | ||
|
||
# Stop timer | ||
$StopWatch.Stop() | ||
|
||
# Display timer output as table | ||
Write-Output "Time taken to complete task:" | ||
$StopWatch.Elapsed | Format-Table |
36 changes: 36 additions & 0 deletions
36
accelerator/test_modules/managementGroup/managementGroup.bicep
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
targetScope = 'managementGroup' | ||
|
||
metadata name = 'ALZ Bicep - Management Groups Module with Scope Escape' | ||
metadata description = 'ALZ Bicep Module to set up Management Group structure, using Scope Escaping feature of ARM to allow deployment not requiring tenant root scope access.' | ||
|
||
@sys.description('Prefix used for the management group hierarchy. This management group will be created as part of the deployment.') | ||
@minLength(2) | ||
@maxLength(10) | ||
param parTopLevelManagementGroupPrefix string = 'alz' | ||
|
||
@sys.description('Optional suffix for the management group hierarchy. This suffix will be appended to management group names/IDs. Include a preceding dash if required. Example: -suffix') | ||
@maxLength(10) | ||
param parTopLevelManagementGroupSuffix string = '' | ||
|
||
@sys.description('Display name for top level management group. This name will be applied to the management group prefix defined in parTopLevelManagementGroupPrefix parameter.') | ||
@minLength(2) | ||
param parTopLevelManagementGroupDisplayName string = 'Azure Landing Zones' | ||
|
||
@sys.description('Optional parent for Management Group hierarchy, used as intermediate root Management Group parent, if specified. If empty, default, will deploy beneath Tenant Root Management Group.') | ||
param parTopLevelManagementGroupParentId string = '' | ||
|
||
resource resTopLevelMg 'Microsoft.Management/managementGroups@2023-04-01' = { | ||
scope: tenant() | ||
name: '${parTopLevelManagementGroupPrefix}${parTopLevelManagementGroupSuffix}' | ||
properties: { | ||
displayName: parTopLevelManagementGroupDisplayName | ||
details: { | ||
parent: { | ||
id: empty(parTopLevelManagementGroupParentId) ? '/providers/Microsoft.Management/managementGroups/${tenant().tenantId}' : contains(toLower(parTopLevelManagementGroupParentId), toLower('/providers/Microsoft.Management/managementGroups/')) ? parTopLevelManagementGroupParentId : '/providers/Microsoft.Management/managementGroups/${parTopLevelManagementGroupParentId}' | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Output Management Group IDs | ||
output outTopLevelManagementGroupId string = resTopLevelMg.id |
18 changes: 18 additions & 0 deletions
18
accelerator/test_modules/managementGroup/parameters/managementGroup.parameters.all.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", | ||
"contentVersion": "1.0.0.0", | ||
"parameters": { | ||
"parTopLevelManagementGroupPrefix": { | ||
"value": "alz" | ||
}, | ||
"parTopLevelManagementGroupSuffix": { | ||
"value": "" | ||
}, | ||
"parTopLevelManagementGroupDisplayName": { | ||
"value": "Azure Landing Zones" | ||
}, | ||
"parTopLevelManagementGroupParentId": { | ||
"value": "" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
{ | ||
"version": "0.18.0", | ||
"gitTag": "v0.18.0", | ||
"releaseNotes": "https://github.com/Azure/ALZ-Bicep/releases/tag/v0.18.0", | ||
"releaseDateTimeUTC": "20240709T0222079056Z" | ||
"version": "0.19.0", | ||
"gitTag": "v0.19.0", | ||
"releaseNotes": "https://github.com/Azure/ALZ-Bicep/releases/tag/v0.19.0", | ||
"releaseDateTimeUTC": "20240713T1000000000Z" | ||
} |