├── README.md ├── batchAssignPolicies.ps1 ├── batchCreatePolicies.ps1 └── sample ├── AllowedLocationsForRG ├── policydef.json ├── policydef.params.json ├── values.dev.json ├── values.prod.json └── values.qa.json ├── AllowedLocationsForWebApp ├── policydef.json ├── policydef.params.json ├── values.dev.json ├── values.prod.json └── values.qa.json └── AllowedWebAppSKUs ├── policydef.json ├── policydef.params.json ├── values.dev.json ├── values.prod.json └── values.qa.json /README.md: -------------------------------------------------------------------------------- 1 | # batch-policy-scripts 2 | sample powershell scripts to create and assign Azure policies from Azure Pipelines 3 | 4 | *Pre-requisites:* 5 | - Each Azure policy is maintained in it's own folder - name of the folder is going to be the name of the Policy definition on Policy Center 6 | - Each policy folder contains: 7 | - policydef.json: policy definition 8 | - policydef.params.json: parameters used in the definition (if any) or {} 9 | - values..json: values to be used for the specified pipeline stage. stage names should match. Eg. values.dev.json 10 | - Pipeline task passes the following variables to the powershell script: 11 | - subscriptionName (for batchCreatePolicies.ps1) 12 | - resourceGroupName (for batchAssignPolicies.ps1) 13 | - The policy folder is downloaded/available at: $(System.DefaultWorkingDirectory)/policies 14 | 15 | Refer to the sample folder for example policy folder structure. -------------------------------------------------------------------------------- /batchAssignPolicies.ps1: -------------------------------------------------------------------------------- 1 | $policyObjs = ConvertFrom-Json -InputObject $env:POLICYDEFS 2 | $policyAssignmentRG = "$(resourceGroupName)$(Release.EnvironmentName)" 3 | $policyDefRootFolder = "$(System.DefaultWorkingDirectory)/policies" 4 | 5 | foreach ($policyDefFolder in (Get-ChildItem -Path $policyDefRootFolder -Directory)) { 6 | 7 | Write-Host Processing folder: $policyDefFolder.Name 8 | $selected = $policyObjs | Where-Object { $_.Name -eq $policyDefFolder.Name } 9 | Write-Host Creating assignment for: $selectedObj 10 | 11 | New-AzureRmPolicyAssignment -Name $policyDefFolder.Name -PolicyDefinition $selected -Scope ((Get-AzureRmResourceGroup -Name $policyAssignmentRG).ResourceId) -PolicyParameter "$($policyDefFolder.FullName)\values.$(Release.EnvironmentName).json" 12 | 13 | } -------------------------------------------------------------------------------- /batchCreatePolicies.ps1: -------------------------------------------------------------------------------- 1 | $policyDefRootFolder = "$(System.DefaultWorkingDirectory)/policies" 2 | $subscriptionName = "$(subscriptionName)" 3 | 4 | class PolicyDef { 5 | [string]$PolicyName 6 | [string]$PolicyRulePath 7 | [string]$PolicyParamPath 8 | [string]$ResourceId 9 | } 10 | 11 | function Select-Policies { 12 | [CmdletBinding()] 13 | Param 14 | ( 15 | [Parameter(Mandatory = $true)] 16 | [System.IO.DirectoryInfo[]]$PolicyFolders 17 | ) 18 | 19 | Write-Verbose "Processing policies" 20 | $policyList = @() 21 | foreach ($policyDefinition in $PolicyFolders) { 22 | $policy = New-Object -TypeName PolicyDef 23 | $policy.PolicyName = $policyDefinition.Name 24 | $policy.PolicyRulePath = $($policyDefinition.FullName + "\policydef.json") 25 | $policy.PolicyParamPath = $($policyDefinition.FullName + "\policydef.params.json") 26 | $policyList += $policy 27 | } 28 | 29 | return $policyList 30 | } 31 | 32 | function Add-Policies { 33 | [CmdletBinding()] 34 | Param 35 | ( 36 | [Parameter(Mandatory = $true)] 37 | [PolicyDef[]]$Policies, 38 | [String]$subscriptionId 39 | ) 40 | 41 | Write-Verbose "Creating policy definitions" 42 | $policyDefList = @() 43 | foreach ($policy in $Policies) { 44 | $policyDef = New-AzureRmPolicyDefinition -Name $policy.PolicyName -Policy $policy.PolicyRulePath -Parameter $policy.PolicyParamPath -SubscriptionId $subscriptionId -Metadata '{"category":"Pipeline"}' 45 | $policyDefList += $policyDef 46 | } 47 | return $policyDefList 48 | } 49 | 50 | $subscriptionId = (Get-AzureRmSubscription -SubscriptionName $subscriptionName).Id 51 | Write-Verbose $policyDefRootFolder 52 | Write-Verbose $subscriptionId 53 | 54 | #get list of policy folders 55 | $policies = Select-Policies -PolicyFolders (Get-ChildItem -Path $policyDefRootFolder -Directory) 56 | $policyDefinitions = Add-Policies -Policies $policies -subscriptionId $subscriptionId 57 | $policyDefsJson = ($policyDefinitions | ConvertTo-Json -Depth 10 -Compress) 58 | 59 | Write-Host "##vso[task.setvariable variable=PolicyDefs]$policyDefsJson" -------------------------------------------------------------------------------- /sample/AllowedLocationsForRG/policydef.json: -------------------------------------------------------------------------------- 1 | { 2 | "if": { 3 | "allOf": [ 4 | { 5 | "field": "location", 6 | "notIn": "[parameters('listofAllowedLocations')]" 7 | }, 8 | { 9 | "field": "type", 10 | "equals": "Microsoft.Resources/subscriptions/resourceGroups" 11 | } 12 | ] 13 | }, 14 | "then": { 15 | "effect": "deny" 16 | } 17 | } -------------------------------------------------------------------------------- /sample/AllowedLocationsForRG/policydef.params.json: -------------------------------------------------------------------------------- 1 | { 2 | "listofAllowedLocations": { 3 | "type": "Array", 4 | "metadata": { 5 | "description": "The list of locations that can be specified when deploying resources.", 6 | "strongType": "location", 7 | "displayName": "Allowed locations" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /sample/AllowedLocationsForRG/values.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "listofAllowedLocations": { 3 | "value": [ 4 | "eastus", 5 | "eastus2", 6 | "westus" 7 | ] 8 | } 9 | } -------------------------------------------------------------------------------- /sample/AllowedLocationsForRG/values.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "listofAllowedLocations": { 3 | "value": [ 4 | "eastus", 5 | "eastus2", 6 | "centralus" 7 | ] 8 | } 9 | } -------------------------------------------------------------------------------- /sample/AllowedLocationsForRG/values.qa.json: -------------------------------------------------------------------------------- 1 | { 2 | "listofAllowedLocations": { 3 | "value": [ 4 | "eastus", 5 | "westus" 6 | ] 7 | } 8 | } -------------------------------------------------------------------------------- /sample/AllowedLocationsForWebApp/policydef.json: -------------------------------------------------------------------------------- 1 | { 2 | "if": { 3 | "allOf": [ 4 | { 5 | "field": "location", 6 | "notIn": "[parameters('listofAllowedLocations')]" 7 | }, 8 | { 9 | "field": "type", 10 | "equals": "Microsoft.Web/serverfarms" 11 | } 12 | ] 13 | }, 14 | "then": { 15 | "effect": "deny" 16 | } 17 | } -------------------------------------------------------------------------------- /sample/AllowedLocationsForWebApp/policydef.params.json: -------------------------------------------------------------------------------- 1 | { 2 | "listofAllowedLocations": { 3 | "type": "Array", 4 | "metadata": { 5 | "description": "The list of locations that can be specified when deploying resources.", 6 | "strongType": "location", 7 | "displayName": "Allowed locations" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /sample/AllowedLocationsForWebApp/values.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "listofAllowedLocations": { 3 | "value": [ 4 | "eastus", 5 | "westus" 6 | ] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /sample/AllowedLocationsForWebApp/values.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "listofAllowedLocations": { 3 | "value": [ 4 | "eastus", 5 | "eastus2", 6 | "centralus" 7 | ] 8 | } 9 | } -------------------------------------------------------------------------------- /sample/AllowedLocationsForWebApp/values.qa.json: -------------------------------------------------------------------------------- 1 | { 2 | "listofAllowedLocations": { 3 | "value": [ 4 | "eastus", 5 | "westus" 6 | ] 7 | } 8 | } -------------------------------------------------------------------------------- /sample/AllowedWebAppSKUs/policydef.json: -------------------------------------------------------------------------------- 1 | { 2 | "if": { 3 | "allOf": [ 4 | { 5 | "field": "type", 6 | "equals": "Microsoft.Web/serverfarms" 7 | }, 8 | { 9 | "not": { 10 | "field": "Microsoft.Web/serverfarms/sku.name", 11 | "in": "[parameters('listOfAllowedVMSKUs')]" 12 | } 13 | } 14 | ] 15 | }, 16 | "then": { 17 | "effect": "deny" 18 | } 19 | } -------------------------------------------------------------------------------- /sample/AllowedWebAppSKUs/policydef.params.json: -------------------------------------------------------------------------------- 1 | { 2 | "listOfAllowedVMSKUs": { 3 | "type": "Array", 4 | "metadata": { 5 | "description": "The list of allowed VM SKUs", 6 | "strongType": "string", 7 | "displayName": "Allowed VM SKUs" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /sample/AllowedWebAppSKUs/values.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "listOfAllowedVMSKUs": { 3 | "value": [ 4 | "A1", 5 | "B1" 6 | ] 7 | } 8 | } -------------------------------------------------------------------------------- /sample/AllowedWebAppSKUs/values.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "listOfAllowedVMSKUs": { 3 | "value": [ 4 | "DS1", 5 | "S1", 6 | "B1", 7 | "B2" 8 | ] 9 | } 10 | } -------------------------------------------------------------------------------- /sample/AllowedWebAppSKUs/values.qa.json: -------------------------------------------------------------------------------- 1 | { 2 | "listOfAllowedVMSKUs": { 3 | "value": [ 4 | "A1", 5 | "B1" 6 | ] 7 | } 8 | } --------------------------------------------------------------------------------