Skip to content

Commit

Permalink
Add new modules for MGs & Subscription Alias with targetScope = MG
Browse files Browse the repository at this point in the history
…(Non-Breaking) (#651)

* add new module

* change telem

* #650 fixes

* add accelerator flex

* update api

* Sub Updates

* typo

* doc updates

* Generate Parameter Markdowns [jtracey93/48d9ad1a]

* remove file not needed

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
jtracey93 and github-actions[bot] authored Oct 9, 2023
1 parent 48d9ad1 commit 58ba4f7
Show file tree
Hide file tree
Showing 9 changed files with 682 additions and 26 deletions.
38 changes: 29 additions & 9 deletions accelerator/pipeline-scripts/Deploy-ALZManagementGroups.ps1
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
param (
[Parameter()]
[String]$NonRootParentManagementGroupId = "$($env:NONROOTPARENTMANAGEMENTGROUPID)",

[Parameter()]
[String]$Location = "$($env:LOCATION)",

[Parameter()]
[String]$TemplateFile = "upstream-releases\$($env:UPSTREAM_RELEASE_VERSION)\infra-as-code\bicep\modules\managementGroups\managementGroups.bicep",
[String]$TemplateFile = "upstream-releases\$($env:UPSTREAM_RELEASE_VERSION)\infra-as-code\bicep\modules\managementGroups\",

[Parameter()]
[String]$TemplateParameterFile = "config\custom-parameters\managementGroups.parameters.all.json",
Expand All @@ -13,13 +16,30 @@ param (
)

# Parameters necessary for deployment
$inputObject = @{
DeploymentName = 'alz-MGDeployment-{0}' -f ( -join (Get-Date -Format 'yyyyMMddTHHMMssffffZ')[0..63])
Location = $Location
TemplateFile = $TemplateFile
TemplateParameterFile = $TemplateParameterFile
WhatIf = $WhatIfEnabled
Verbose = $true

if ($NonRootParentManagementGroupId -eq '') {
$inputObject = @{
DeploymentName = 'alz-MGDeployment-{0}' -f ( -join (Get-Date -Format 'yyyyMMddTHHMMssffffZ')[0..63])
Location = $Location
TemplateFile = $TemplateFile + "managementGroups.bicep"
TemplateParameterFile = $TemplateParameterFile
WhatIf = $WhatIfEnabled
Verbose = $true
}

New-AzTenantDeployment @inputObject
}

New-AzTenantDeployment @inputObject
if ($NonRootParentManagementGroupId -ne '') {
$inputObject = @{
ManagementGroupId = $NonRootParentManagementGroupId
DeploymentName = 'alz-MGDeployment-{0}' -f ( -join (Get-Date -Format 'yyyyMMddTHHMMssffffZ')[0..63])
Location = $Location
TemplateFile = $TemplateFile + "managementGroupsScopeEscape.bicep"
TemplateParameterFile = $TemplateParameterFile
WhatIf = $WhatIfEnabled
Verbose = $true
}

New-AzManagementGroupDeployment @inputObject
}
43 changes: 39 additions & 4 deletions infra-as-code/bicep/CRML/subscriptionAlias/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Module: Subscription Alias

> **IMPORTANT:** We recommend moving to using the [Bicep Subscription Vending Module](https://aka.ms/sub-vending/bicep) instead of this module!
> ⚠️⚠️ **IMPORTANT:** We recommend moving to using the [Bicep Subscription Vending Module](https://aka.ms/sub-vending/bicep) instead of this module! ⚠️⚠️
The Subscription Alias module deploys an Azure Subscription into an existing billing scope that can be from an EA, MCA or MPA as documented in [Create Azure subscriptions programmatically](https://learn.microsoft.com/azure/cost-management-billing/manage/programmatically-create-subscription).

Expand All @@ -10,7 +10,8 @@ The Subscription will be created and placed under the Tenant Root Group, unless

## Parameters

- [Parameters for Azure Commercial Cloud](generateddocs/subscriptionAlias.bicep.md)
- [Parameters for `subscriptionAlias.bicep` Azure Commercial Cloud](generateddocs/subscriptionAlias.bicep.md)
- [Parameters for `subscriptionAliasScopeEscape.bicep` Azure Commercial Cloud](generateddocs/subscriptionAliasScopeEscape.bicep.md)

## Outputs

Expand All @@ -29,7 +30,8 @@ In this example, the Subscription is created upon an EA Account through a tenant

> For the below examples we assume you have downloaded or cloned the Git repo as-is and are in the root of the repository as your selected directory in your terminal of choice.
### Azure CLI
### Azure CLI - `subscriptionAlias.bicep`

```bash

dateYMD=$(date +%Y%m%dT%H%M%S%NZ)
Expand All @@ -41,7 +43,23 @@ TEMPLATEFILE="infra-as-code/bicep/CRML/subscriptionAlias/subscriptionAlias.bicep
az deployment tenant create --name ${NAME:0:63} --location $LOCATION --template-file $TEMPLATEFILE --parameters $PARAMETERS
```

### PowerShell
### Azure CLI - `subscriptionAliasScopeEscape.bicep`

Use this module if you do not want to grant Tenant Root Management Group Deployment permissions.

```bash

dateYMD=$(date +%Y%m%dT%H%M%S%NZ)
NAME="alz-SubscriptionAlias-${dateYMD}"
LOCATION="eastus"
PARAMETERS="@infra-as-code/bicep/CRML/subscriptionAlias/parameters/subscriptionAlias.parameters.all.json"
TEMPLATEFILE="infra-as-code/bicep/CRML/subscriptionAlias/subscriptionAliasScopeEscape.bicep"
MGID="alz"

az deployment mg create --name ${NAME:0:63} --location $LOCATION --template-file $TEMPLATEFILE --parameters $PARAMETERS --management-group-id $MGID
```

### PowerShell - `subscriptionAlias.bicep`

```powershell
Expand All @@ -55,6 +73,23 @@ $inputObject = @{
New-AzTenantDeployment @inputObject
```

### PowerShell - `subscriptionAliasScopeEscape.bicep`

Use this module if you do not want to grant Tenant Root Management Group Deployment permissions.

```powershell
$inputObject = @{
DeploymentName = 'alz-SubscriptionAlias-{0}' -f (-join (Get-Date -Format 'yyyyMMddTHHMMssffffZ')[0..63])
TemplateParameterFile = 'infra-as-code/bicep/CRML/subscriptionAlias/parameters/subscriptionAlias.parameters.all.json'
Location = 'EastUS'
TemplateFile = "infra-as-code/bicep/CRML/subscriptionAlias/subscriptionAliasScopeEscape.bicep"
ManagementGroupId = 'alz'
}
New-AzManagementGroupDeployment @inputObject
```

### Output Screenshot

![Example Deployment Output](media/exampleDeploymentOutput.png "Example Deployment Output")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# ALZ Bicep CRML - Subscription Alias Module with Scope Escape

Module to deploy an Azure Subscription into an existing billing scope that can be from an EA, MCA or MPA, using Scope Escaping feature of ARM to allow deployment not requiring tenant root scope access.

## Parameters

Parameter name | Required | Description
-------------- | -------- | -----------
parSubscriptionName | Yes | Name of the subscription to be created. Will also be used as the alias name. Whilst you can use any name you like we recommend it to be: all lowercase, no spaces, alphanumeric and hyphens only.
parSubscriptionBillingScope | Yes | The full resource ID of billing scope associated to the EA, MCA or MPA account you wish to create the subscription in.
parTags | No | Tags you would like to be applied.
parManagementGroupId | No | The ID of the existing management group where the subscription will be placed. Also known as its parent management group. (Optional)
parSubscriptionOwnerId | No | The object ID of a responsible user, Microsoft Entra group or service principal. (Optional)
parSubscriptionOfferType | No | The offer type of the EA, MCA or MPA subscription to be created. Defaults to = Production
parTenantId | No | The ID of the tenant. Defaults to = tenant().tenantId

### parSubscriptionName

![Parameter Setting](https://img.shields.io/badge/parameter-required-orange?style=flat-square)

Name of the subscription to be created. Will also be used as the alias name. Whilst you can use any name you like we recommend it to be: all lowercase, no spaces, alphanumeric and hyphens only.

### parSubscriptionBillingScope

![Parameter Setting](https://img.shields.io/badge/parameter-required-orange?style=flat-square)

The full resource ID of billing scope associated to the EA, MCA or MPA account you wish to create the subscription in.

### parTags

![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square)

Tags you would like to be applied.

### parManagementGroupId

![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square)

The ID of the existing management group where the subscription will be placed. Also known as its parent management group. (Optional)

### parSubscriptionOwnerId

![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square)

The object ID of a responsible user, Microsoft Entra group or service principal. (Optional)

### parSubscriptionOfferType

![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square)

The offer type of the EA, MCA or MPA subscription to be created. Defaults to = Production

- Default value: `Production`

- Allowed values: `DevTest`, `Production`

### parTenantId

![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square)

The ID of the tenant. Defaults to = tenant().tenantId

- Default value: `[tenant().tenantId]`

## Outputs

Name | Type | Description
---- | ---- | -----------
outSubscriptionName | string |
outSubscriptionId | string |

## Snippets

### Parameter file

```json
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"template": "infra-as-code/bicep/CRML/subscriptionAlias/subscriptionAliasScopeEscape.json"
},
"parameters": {
"parSubscriptionName": {
"value": ""
},
"parSubscriptionBillingScope": {
"value": ""
},
"parTags": {
"value": {}
},
"parManagementGroupId": {
"value": ""
},
"parSubscriptionOwnerId": {
"value": ""
},
"parSubscriptionOfferType": {
"value": "Production"
},
"parTenantId": {
"value": "[tenant().tenantId]"
}
}
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ resource resSubscription 'Microsoft.Subscription/aliases@2021-10-01' = {
properties: {
additionalProperties: {
tags: parTags
managementGroupId: empty(parManagementGroupId) ? null : managementGroup(parManagementGroupId)
managementGroupId: empty(parManagementGroupId) ? null : '/providers/Microsoft.Management/managementGroups/${parManagementGroupId}'
subscriptionOwnerId: empty(parSubscriptionOwnerId) ? null : parSubscriptionOwnerId
subscriptionTenantId: parTenantId
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
targetScope = 'managementGroup'

metadata name = 'ALZ Bicep CRML - Subscription Alias Module with Scope Escape'
metadata description = 'Module to deploy an Azure Subscription into an existing billing scope that can be from an EA, MCA or MPA, using Scope Escaping feature of ARM to allow deployment not requiring tenant root scope access.'

@sys.description('Name of the subscription to be created. Will also be used as the alias name. Whilst you can use any name you like we recommend it to be: all lowercase, no spaces, alphanumeric and hyphens only.')
param parSubscriptionName string

@sys.description('The full resource ID of billing scope associated to the EA, MCA or MPA account you wish to create the subscription in.')
param parSubscriptionBillingScope string

@sys.description('Tags you would like to be applied.')
param parTags object = {}

@sys.description('The ID of the existing management group where the subscription will be placed. Also known as its parent management group. (Optional)')
param parManagementGroupId string = ''

@sys.description('The object ID of a responsible user, Microsoft Entra group or service principal. (Optional)')
param parSubscriptionOwnerId string = ''

@allowed([
'DevTest'
'Production'
])
@sys.description('The offer type of the EA, MCA or MPA subscription to be created. Defaults to = Production')
param parSubscriptionOfferType string = 'Production'

@sys.description('The ID of the tenant. Defaults to = tenant().tenantId')
param parTenantId string = tenant().tenantId

resource resSubscription 'Microsoft.Subscription/aliases@2021-10-01' = {
scope: tenant()
name: parSubscriptionName
properties: {
additionalProperties: {
tags: parTags
managementGroupId: empty(parManagementGroupId) ? null : '/providers/Microsoft.Management/managementGroups/${parManagementGroupId}'
subscriptionOwnerId: empty(parSubscriptionOwnerId) ? null : parSubscriptionOwnerId
subscriptionTenantId: parTenantId
}
displayName: parSubscriptionName
billingScope: parSubscriptionBillingScope
workload: parSubscriptionOfferType
}
}

output outSubscriptionName string = resSubscription.name
output outSubscriptionId string = resSubscription.properties.subscriptionId
67 changes: 64 additions & 3 deletions infra-as-code/bicep/modules/managementGroups/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ The Management Groups module deploys a management group hierarchy in a customer'

## Parameters

- [Link to Parameters](generateddocs/managementGroups.bicep.md)
- [Link to `managementGroup.bicep` Parameters](generateddocs/managementGroups.bicep.md)
- [Link to `managementGroupsScopeEscape.bicep` Parameters](generateddocs/managementGroupsScopeEscape.bicep.md)

### Child Platform & Landing Zone Management Groups Flexibility

Expand Down Expand Up @@ -141,7 +142,7 @@ In this example, the management groups are created at the `Tenant Root Group` th

> For the examples below we assume you have downloaded or cloned the Git repo as-is and are in the root of the repository as your selected directory in your terminal of choice.
### Azure CLI
### Azure CLI - `managementGroups.bicep`

```bash
# For Azure global regions
Expand All @@ -167,7 +168,37 @@ PARAMETERS="@infra-as-code/bicep/modules/managementGroups/parameters/managementG
az deployment tenant create --name ${NAME:0:63} --location $LOCATION --template-file $TEMPLATEFILE --parameters $PARAMETERS
```

### PowerShell
### Azure CLI - `managementGroupsScopeEscape.bicep`

Use this module if you do not want to grant Tenant Root Management Group Deployment permissions.

```bash
# For Azure global regions

dateYMD=$(date +%Y%m%dT%H%M%S%NZ)
NAME="alz-MGDeployment-${dateYMD}"
LOCATION="eastus"
TEMPLATEFILE="infra-as-code/bicep/modules/managementGroups/managementGroupsScopeEscape.bicep"
PARAMETERS="@infra-as-code/bicep/modules/managementGroups/parameters/managementGroups.parameters.all.json"
MGID="alz"

az deployment tenant create --name ${NAME:0:63} --location $LOCATION --template-file $TEMPLATEFILE --parameters $PARAMETERS --management-group-id $MGID
```
OR
```bash
# For Azure China regions

dateYMD=$(date +%Y%m%dT%H%M%S%NZ)
NAME="alz-MGDeployment-${dateYMD}"
LOCATION="chinaeast2"
TEMPLATEFILE="infra-as-code/bicep/modules/managementGroups/managementGroupsScopeEscape.bicep"
PARAMETERS="@infra-as-code/bicep/modules/managementGroups/parameters/managementGroups.parameters.all.json"
MGID="alz"

az deployment tenant create --name ${NAME:0:63} --location $LOCATION --template-file $TEMPLATEFILE --parameters $PARAMETERS --management-group-id $MGID
```

### PowerShell - `managementGroups.bicep`

```powershell
# For Azure global regions
Expand All @@ -193,6 +224,36 @@ $inputObject = @{
New-AzTenantDeployment @inputObject
```

### PowerShell - `managementGroupsScopeEscape.bicep`

Use this module if you do not want to grant Tenant Root Management Group Deployment permissions.

```powershell
# For Azure global regions
$inputObject = @{
DeploymentName = 'alz-MGDeployment-{0}' -f (-join (Get-Date -Format 'yyyyMMddTHHMMssffffZ')[0..63])
Location = 'EastUS'
TemplateFile = "infra-as-code/bicep/modules/managementGroups/managementGroupsScopeEscape.bicep"
TemplateParameterFile = 'infra-as-code/bicep/modules/managementGroups/parameters/managementGroups.parameters.all.json'
ManagementGroupId = 'alz'
}
New-AzManagementGroupDeployment @inputObject
```
OR
```powershell
# For Azure China regions
$inputObject = @{
DeploymentName = 'alz-MGDeployment-{0}' -f (-join (Get-Date -Format 'yyyyMMddTHHMMssffffZ')[0..63])
Location = 'chinaeast2'
TemplateFile = "infra-as-code/bicep/modules/managementGroups/managementGroupsScopeEscape.bicep"
TemplateParameterFile = 'infra-as-code/bicep/modules/managementGroups/parameters/managementGroups.parameters.all.json'
ManagementGroupId = 'alz'
}
New-AzManagementGroupDeployment @inputObject
```

![Example Deployment Output](media/exampleDeploymentOutput.png "Example Deployment Output")

## Bicep Visualizer
Expand Down
Loading

0 comments on commit 58ba4f7

Please sign in to comment.