Skip to content

Commit

Permalink
Implement bicep bootstrap (#799)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
Co-authored-by: Zach Trocinski <[email protected]>
  • Loading branch information
3 people authored Jul 18, 2024
1 parent b700ac4 commit 8dd8d53
Show file tree
Hide file tree
Showing 8 changed files with 1,222 additions and 14 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ For support on the artifacts contained in this repository, please refer to [this
[wiki_resiliency]: https://github.com/Azure/ALZ-Bicep/wiki/Resiliency "Wiki - Resiliency"
[wiki_contributing]: https://github.com/Azure/ALZ-Bicep/wiki/Contributing "Wiki - Contributing"
[wiki_accelerator]: <https://github.com/Azure/ALZ-Bicep/wiki/Accelerator> "Wiki - Accelerator"
[wiki_amba]: <https://github.com/Azure/ALZ-Bicep/wiki/Accelerator> "Wiki - AMBA"
[wiki_amba]: <https://github.com/Azure/ALZ-Bicep/wiki/AzureMonitorBaselineAlerts> "Wiki - AMBA"
[wiki_faq]: <https://github.com/Azure/ALZ-Bicep/wiki/FAQ> "Wiki - FAQs"
[wiki_cuaid]: <https://github.com/Azure/ALZ-Bicep/wiki/CustomerUsage> "Wiki - Telemetry Usage ID"
[wiki_acrdeploy]: <https://github.com/Azure/ALZ-Bicep/wiki/ACRDeployment> "Wiki - Private Bicep Registry"
Expand Down
955 changes: 955 additions & 0 deletions accelerator/.config/ALZ-Powershell-Auto.config.json

Large diffs are not rendered by default.

190 changes: 190 additions & 0 deletions accelerator/scripts/destroy-landing-zone.ps1
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 accelerator/test_modules/managementGroup/managementGroup.bicep
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
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": ""
}
}
}
26 changes: 18 additions & 8 deletions docs/wiki/Accelerator.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
<!-- markdownlint-disable -->
## ALZ Bicep Accelerator
## ALZ Bicep Accelerator (Classic)
<!-- markdownlint-restore -->

This document provides prescriptive guidance around implementing, automating, and maintaining your ALZ Bicep module with the ALZ Bicep Accelerator.
> [!IMPORTANT]
> The ALZ Bicep Accelerator has been updated to automate the bootstrapping of your Version Control System and Azure resources. The ALZ Bicep Accelerator's documentation has been moved to [aka.ms/alz/accelerator/docs](https://aka.ms/alz/accelerator/docs). Head over there now to get started!
> Use the instructions below only if you need to use the classic version of the ALZ Bicep Accelerator.
### What is the ALZ Bicep Accelerator?
### Deprecation Notice

> [!WARNING]
> The classic version of the ALZ Bicep Accelerator will be maintained for a limited time. We recommend migrating to the new version as soon as possible.
### What is the ALZ Bicep Accelerator (Classic)?

> [!NOTE]
> These instructions now include the `-bicepLegacyMode $true` parameter, which needs be set explicily to use the classic version.
The ALZ Bicep Accelerator framework was developed to provide end-users with the following abilities:

Expand Down Expand Up @@ -67,7 +77,7 @@ In order to setup the Accelerator framework with the production GitHub Action Wo
1. Create your ALZ Bicep Accelerator framework with the following ALZ PowerShell Module cmdlet:
```powershell
Deploy-Accelerator -o <output_directory> -i "bicep" -b "alz_github
Deploy-Accelerator -o <output_directory> -i "bicep" -b "alz_github" -bicepLegacyMode $true
```

> **Note:**
Expand Down Expand Up @@ -137,7 +147,7 @@ In order to setup the Accelerator framework with the production ready Azure DevO
1. Create your ALZ Bicep Accelerator framework with the following ALZ PowerShell Module cmdlet:
```powershell
Deploy-Accelerator -o <output_directory> -i "bicep" -b "alz_azuredevops"
Deploy-Accelerator -o <output_directory> -i "bicep" -b "alz_azuredevops" -bicepLegacyMode $true
```

> **Note:**
Expand Down Expand Up @@ -217,20 +227,20 @@ The ALZ-Bicep repository regularly releases new [versions](https://github.com/Az

With the ALZ Accelerator framework, we have designed the pipelines and directory structure to make it easy to upgrade to the latest ALZ Bicep version. The following steps will guide you through the upgrade process.

1. Prior to upgrading, read the release note:s for the version you are upgrading to. The release note:s will provide you with information on any breaking changes that may impact your deployment. This is especially important if you have created any custom modules or have [modified any of the ALZ Bicep modules](#incorporating-modified-alz-modules) that may have dependencies on the modules that are being upgraded.
1. Prior to upgrading, read the release notes for the version you are upgrading to. The release notes will provide you with information on any breaking changes that may impact your deployment. This is especially important if you have created any custom modules or have [modified any of the ALZ Bicep modules](#incorporating-modified-alz-modules) that may have dependencies on the modules that are being upgraded.

1. Using the ALZ PowerShell Module, you can update to the latest or a specified version. You must specifiy the same IaC, Bootstrap and Output directory that you used when you initially deployed the ALZ Bicep Accelerator.

Here is an example of using the cmdlet to upgrade to the latest version:

```powershell
Deploy-Accelerator -i "bicep" -b "alz_github" -o "C:\Repos\ALZ\accelerator"
Deploy-Accelerator -i "bicep" -b "alz_github" -o "C:\Repos\ALZ\accelerator" -bicepLegacyMode $true
```

Here is an example of using the to upgrade to version v0.17.2:

```powershell
Deploy-Accelerator -i "bicep" -b "alz_github" -v "v0.17.2" -o "C:\Repos\ALZ\accelerator"
Deploy-Accelerator -i "bicep" -b "alz_github" -v "v0.17.2" -o "C:\Repos\ALZ\accelerator" -bicepLegacyMode $true
```

You will be prompted for inputs again and the upgrade will be run for you.
Expand Down
1 change: 0 additions & 1 deletion infra-as-code/bicep/modules/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ To get started with ALZ Bicep, please refer to the [Deployment Flow wiki page][w
2. High-level deployment flow.
3. Links to more detailed instructions on individual modules.


[//]: # (************************)
[//]: # (INSERT LINK LABELS BELOW)
[//]: # (************************)
Expand Down
8 changes: 4 additions & 4 deletions version.json
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"
}

0 comments on commit 8dd8d53

Please sign in to comment.