This reference implementation uses Built-In and Custom Policies to provide guardrails in the Azure environment. The goal of this authoring guide is to provide step-by-step instructions to manage and customize policy definitions and assignments that align with your organization's compliance requirements.
- Existing configuration
- Built-in policy sets
- Custom policies
- New custom policy definition
- New custom policy set definition & assignment
- Update custom policy definition
- Update custom policy set definition & assignment
- Remove custom policy definition
- Remove custom policy set definition and assignment
- Enable or disable custom policy set enforcement
- Auto generate custom Diagnostic Settings policies for PaaS services
Built-in policy set assignment templates are located in /policy/builtin/assignments
directory.
Policy Set | Description | Deployment Template | Configuration |
---|---|---|---|
Canada Federal PBMM | This initiative includes audit and virtual machine extension deployment policies that address a subset of Canada Federal PBMM controls. | pbmm.bicep | pbmm.parameters.json |
NIST SP 800-53 Revision 4 | This initiative includes policies that address a subset of NIST SP 800-53 Rev. 4 controls. | nist80053r4.bicep | nist80053r4.parameters.json |
NIST SP 800-53 Revision 5 | This initiative includes policies that address a subset of NIST SP 800-53 Rev. 5 controls. | nist80053r5.bicep | nist80053r5.parameters.json |
Azure Security Benchmark | The Azure Security Benchmark initiative represents the policies and controls implementing security recommendations defined in Azure Security Benchmark, see https://aka.ms/azsecbm. This also serves as the Microsoft Defender for Cloud default policy initiative. | asb.bicep | asb.parameters.json |
CIS Microsoft Azure Foundations Benchmark 1.3.0 | This initiative includes policies that address a subset of CIS Microsoft Azure Foundations Benchmark recommendations. | cis-msft-130.bicep | cis-msft-130.parameters.json |
FedRAMP Moderate | This initiative includes policies that address a subset of FedRAMP Moderate controls. | fedramp-moderate.bicep | fedramp-moderate.parameters.json |
HIPAA / HITRUST 9.2 | This initiative includes audit and virtual machine extension deployment policies that address a subset of HITRUST/HIPAA controls. | hitrust-hipaa.bicep | hitrust-hipaa.parameters.json |
Location | Restrict deployments to Canadian regions. | location.bicep | location.parameters.json |
Custom policy set definition templates are located in /policy/custom/definitions/policyset
directory.
Custom policy set assignment templates are located in /policy/custom/assignments
directory.
Policy Set | Description | Policy set definition deployment template | Configuration |
---|---|---|---|
Azure Kubernetes Service | Azure Policy Add-on to Azure Kubernetes Service clusters & Pod Security. | AKS.bicep | AKS.parameters.json |
Microsoft Defender for Cloud | Configures Microsoft Defender for Cloud, including Azure Defender for subscription and resources. | DefenderForCloud.bicep | DefenderForCloud.parameters.json |
Private DNS Zones for Private Endpoints | Policies to configure DNS zone records for private endpoints. Policy set is assigned through deployment pipeline when private endpoint DNS zones are managed in the Hub Network. | DNSPrivateEndpoints.bicep | DNSPrivateEndpoints.parameters.json |
Log Analytics for Azure Services (IaaS and PaaS) | Configures monitoring agents for IaaS and diagnostic settings for PaaS to send logs to a central Log Analytics Workspace. | LogAnalytics.bicep | LogAnalytics.parameters.json |
Networking | Configures policies for network resources. | Network.bicep | Network.parameters.json |
Tag Governance | Configures required tags and tag propagation from resource groups to resources. | Tags.bicep | Tags.parameters.json |
The built-in policy sets are used as-is to ensure future improvements from Azure Engineering teams are automatically incorporated into the Azure environment.
Steps
- Step 1: Collect information
- Step 2: Create Bicep template & parameters JSON file
- Step 3: Update Azure DevOps Pipeline
- Step 4: Deploy built-in policy set assignment
- Step 5: Verify policy set assignment
We will not be assigning the policy through Azure Portal, but use these steps to identify the necessary info, such as name, definition ID, permissions, and parameters, which are required for the Policy Assignment.
-
Navigate to Azure Portal -> Azure Policy -> Definitions
-
Open the Built-In Policy Set (it is also called an Initiative) that will be assigned through automation. For example:
Canada Federal PBMM
Collect the following information:
- Name (e.g.
Canada Federal PBMM
) - Definition ID (e.g.
/providers/Microsoft.Authorization/policySetDefinitions/4c4a5f27-de81-430b-b4e5-9cbd50595a87
)
- Name (e.g.
-
Click the Assign button and select a scope for the assignment. We will not be assigning the policy through Azure Portal, but use this step to identify the permissions required for the Policy Assignment.
Collect the following information from the Remediation tab:
- Permissions - required when there are auto remediation policies. You may see zero, one (e.g.
Contributor
) or many comma-separated (e.g.Log Analytics Contributor, Virtual Machine Contributor, Monitoring Contributor
) roles listed. Permissions will not be listed when none are required for the policy assignment to function.
Once the permissions are identified, click the Cancel button to discard the changes.
Use Azure Built-In Roles table to map the permission name to it's Resource ID. Resource ID will be used when defining the role assignments.
- Permissions - required when there are auto remediation policies. You may see zero, one (e.g.
-
Click on the Duplicate initiative button. We will not be duplicating the policy set definition, but use this step to identify the parameter names that will need to be populated during policy assignment.
Collect the following information from the Initiative parameters tab:
- Parameters (e.g.
logAnalytics
,logAnalyticsWorkspaceId
,listOfResourceTypesToAuditDiagnosticSettings
). You may see zero, one or many parameters listed. It is possible that a policy set doesn't have any parameters.
- Parameters (e.g.
-
Navigate to
policy/builtin/assignments
directory and create two files. ReplacePOLICY_ASSIGNMENT
with the name of your assignment such aspbmm
.- POLICY_ASSIGNMENT.bicep (i.e.
pbmm.bicep
) - this file defines the policy assignment deployment - POLICY_ASSIGNMENT.parameters.json (i.e.
pbmm.parameters.json
) - this file defines the parameters used to deploy the policy assignment.
- POLICY_ASSIGNMENT.bicep (i.e.
-
Edit the Bicep file to include the following template. This template can be customized as required. Pre-requisites are:
- targetScope must be
managementGroup
- parameter
policyAssignmentManagementGroupId
must be defined. It is used to set the policy assignment through automation.
Sample Template
targetScope = 'managementGroup' @description('Management Group scope for the policy assignment.') param policyAssignmentManagementGroupId string @allowed([ 'Default' 'DoNotEnforce' ]) @description('Policy set assignment enforcement mode. Possible values are { Default, DoNotEnforce }. Default value: Default') param enforcementMode string = 'Default' // Start - Any custom parameters required for your policy assignment param ... // End - Any custom parameters required for your policy assignment // Add the GUID from the Definition ID that was gathered above var policyId = '<< GUID >>' // Add the policy set assignment name (i.e. the name of the Policy Set Name) var assignmentName = '<< POLICY ASSIGNMENT NAME >>' var scope = tenantResourceId('Microsoft.Management/managementGroups', policyAssignmentManagementGroupId) var policyScopedId = resourceId('Microsoft.Authorization/policySetDefinitions', policyId) resource policySetAssignment 'Microsoft.Authorization/policyAssignments@2020-03-01' = { // Set the name of the policy assignment // Example: name: 'pbmm-${uniqueString('pbmm-',policyAssignmentManagementGroupId)}' name: '<< NAME >>' properties: { displayName: assignmentName policyDefinitionId: policyScopedId scope: scope notScopes: [ ] parameters: { // Add any parameters identified earlier into this section } // The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. enforcementMode: enforcementMode } identity: { type: 'SystemAssigned' } location: deployment().location } // These role assignments are required to allow Policy Assignment to remediate. // Add this section only when there are permissions to assign to the policy set. // Ensure that the name is a GUID and generated with a deterministic formula such as the example below. // Set the role definition id based on the information gathered earlier. resource policySetRoleAssignmentContributor 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = { name: guid(policyAssignmentManagementGroupId, 'pbmm-Contributor') scope: managementGroup() properties: { roleDefinitionId: '/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' principalId: policySetAssignment.identity.principalId principalType: 'ServicePrincipal' } }
Example: PBMM Policy Set Assignment
targetScope = 'managementGroup' @description('Management Group scope for the policy assignment.') param policyAssignmentManagementGroupId string @allowed([ 'Default' 'DoNotEnforce' ]) @description('Policy set assignment enforcement mode. Possible values are { Default, DoNotEnforce }. Default value: Default') param enforcementMode string = 'Default' @description('Log Analytics Resource Id to integrate Microsoft Defender for Cloud.') param logAnalyticsWorkspaceId string @description('List of members that should be excluded from Windows VM Administrator Group.') param listOfMembersToExcludeFromWindowsVMAdministratorsGroup string @description('List of members that should be included in Windows VM Administrator Group.') param listOfMembersToIncludeInWindowsVMAdministratorsGroup string var policyId = '4c4a5f27-de81-430b-b4e5-9cbd50595a87' // Canada Federal PBMM var assignmentName = 'Canada Federal PBMM' var scope = tenantResourceId('Microsoft.Management/managementGroups', policyAssignmentManagementGroupId) var policyScopedId = resourceId('Microsoft.Authorization/policySetDefinitions', policyId) resource policySetAssignment 'Microsoft.Authorization/policyAssignments@2020-03-01' = { name: 'pbmm-${uniqueString('pbmm-',policyAssignmentManagementGroupId)}' properties: { displayName: assignmentName policyDefinitionId: policyScopedId scope: scope notScopes: [ ] parameters: { logAnalyticsWorkspaceIdforVMReporting: { value: logAnalyticsWorkspaceId } listOfMembersToExcludeFromWindowsVMAdministratorsGroup: { value: listOfMembersToExcludeFromWindowsVMAdministratorsGroup } listOfMembersToIncludeInWindowsVMAdministratorsGroup: { value: listOfMembersToIncludeInWindowsVMAdministratorsGroup } } enforcementMode: enforcementMode } identity: { type: 'SystemAssigned' } location: deployment().location } // These role assignments are required to allow Policy Assignment to remediate. resource policySetRoleAssignmentContributor 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = { name: guid(policyAssignmentManagementGroupId, 'pbmm-Contributor') scope: managementGroup() properties: { roleDefinitionId: '/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' principalId: policySetAssignment.identity.principalId principalType: 'ServicePrincipal' } }
- targetScope must be
-
Edit the JSON parameters file to define the input parameters for the Bicep template. This parameters JSON file is used by Azure Resource Manager (ARM) for runtime inputs.
You can use any of the templated parameters to set values based on environment configuration or hard code them as needed.
Sample Template
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "policyAssignmentManagementGroupId": { "value": "{{var-policyAssignmentManagementGroupId}}" }, "enforcementMode": { "value": "Default" }, "EXTRA_POLICY_ASSIGNMENT_PARAMETER_NAME_1": { "value": "EXTRA_POLICY_ASSIGNMENT_PARAMETER_VALUE_1" }, "EXTRA_POLICY_ASSIGNMENT_PARAMETER_NAME_2": { "value": "EXTRA_POLICY_ASSIGNMENT_PARAMETER_VALUE_2" } } }
Example: PBMM Policy Set Parameters
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "policyAssignmentManagementGroupId": { "value": "{{var-policyAssignmentManagementGroupId}}" }, "enforcementMode": { "value": "Default" }, "logAnalyticsWorkspaceId": { "value": "{{var-logging-logAnalyticsWorkspaceId}}" }, "listOfMembersToExcludeFromWindowsVMAdministratorsGroup": { "value": "__tbd__implementation_specific__" }, "listOfMembersToIncludeInWindowsVMAdministratorsGroup": { "value": "__tbd__implementation_specific__" } } }
- Edit
/.pipelines/policy.yml
- Navigate to the
BuiltInPolicyJob
Job definition - Navigate to the
Assign Policy Set
Step definition - Add the policy assignment file name (without extension) to the
deployTemplates
array parameter
Execute Azure DevOps Policy pipeline
to deploy. The policy set assignment will be deployed to the top level management group
(i.e. pubsec
).
It takes approximately 30 minutes for the assignment to be applied to the defined scope. Once it's applied, the evaluation cycle begins for resources within that scope against the newly assigned policy or initiative, and depending on the effects defined by the policy or initiative, resources are marked as compliant, non-compliant, or exempt. A large policy or initiative evaluated against a large scope of resources can take time. As such, there's no pre-defined expectation of when the evaluation cycle completes. Once evaluation completes, the updated compliance results are available in the portal and to SDKs. See Azure Docs for more information.
-
You can navigate to Azure Policy Compliance to verify in Azure Portal.
-
If there are deployment errors:
- Navigate to Management Groups in Azure Portal
- Select the top level management group (i.e.
pubsec
) - Select Deployments
- Review the deployment errors
Automation does not remove an existing policy set assignment. Removing the policy set assignment from the Azure DevOps pipeline ensures that it's no longer created. Any existing policy set assignments must be deleted manually.
Steps
- Step 1: Remove built-in policy set assignment from Azure DevOps Pipeline
- Step 2: Remove built-in policy set assignment's IAM assignments
- Edit
/.pipelines/policy.yml
- Navigate to the
BuiltInPolicyJob
Job definition - Navigate to the
Assign Policy Set
Step definition - Remove the policy set assignment from the
deployTemplates
array parameter
- Navigate to Azure Policy Assignments in Azure Portal
- Find the policy set assignment
- Click on the
...
beside the policy set assignment and selectDelete assignment
- Navigate to Management Groups in Azure Portal
- Select the top level management group (i.e.
pubsec
) - Select Access control (IAM)
- Select Role Assignments
- Use the
Type
filter to find anyUnknown
role assignments and delete them. This step is required since deleting the policy set assignment does not automatically remove any role assignments. When the policy set assignment is removed, it's managed identity is also removed thus marking these role assignments asUnknown
.
- Select the top level management group (i.e.
You may want to evaluate the compliance in your environment without any automatic remediation, either through DeployIfNotExists
or modify
policies. To support this scenario, all policy set assignments support an enforcementMode
setting. This can be set to either: Default
or DoNotEnforce
:
Default
= enable policy set enforcementDoNotEnforce
= disable policy set enforcement
Please review guidance and expected behaviour of these settings prior to making any modification:
You can switch between these modes per-policy set based on your Azure Policy adoption strategy.
To manage this setting:
- Navigate to policy/builtin/assignments
- Open
*.parameters.json
. There is 1 parameters file per policy set assignment - Modify
enforcementMode
parameter with eitherDefault
orDoNotEnforce
- Re-run the
policy-ci
Azure DevOps pipeline to update Azure
Custom policies and policy sets enable an organization to expand their governance in Azure. Prior to creating any custom policies, we recommend searching for a suitable built-in policy through Azure Policy Definitions. You can create custom policy sets that contain built-in and custom policies.
We recommend organizing the custom policies into a custom policy sets and assigned as a unit. This approach will reduce the management overhead and complexity in the future. You can have as many custom policy sets as required.
Steps
- Step 1: Create policy definition template
- Step 2: Deploy policy definition template
- Step 3: Verify policy definition deployment
- Step 4: Add policy definition to a new custom policy set or update an existing policy set
-
Create a subdirectory in
policy/custom/definitions/policy
directory. Each policy is organized into it's own directory. The directory name must not have any spaces nor special characters. -
Create 3 files in the newly created directory:
azurepolicy.config.json
- metadata used by Azure DevOps Pipeline to configure the policy.azurepolicy.parameters.json
- contains parameters used in the policy.azurepolicy.rules.json
- the policy rule definition.
-
Edit
azurepolicy.config.json
.Information from this file is used as part of deploying Azure Policy definition.
Example
{ "name": "Audit diagnostic setting - Logs", "mode": "all" }
The
mode
determines which resource types are evaluated for a policy definition. The supported modes are:- all: evaluate resource groups, subscriptions, and all resource types
- indexed: only evaluate resource types that support tags and location
See Azure Policy Reference for more information.
-
Edit
azurepolicy.parameters.json
.Define parameters that are required by the policy definition. Using parameters enable the policy to be used with different configuration.
See Azure Parameter Reference for more information.
Example
{ "listOfResourceTypes": { "type": "Array", "metadata": { "displayName": "Resource Types", "description": null, "strongType": "resourceTypes" } } }
-
Edit
azurepolicy.rules.json
Describes the policy rule that will be evaluated by Azure Policy. The rule can have any effect such as Audit, Deny, DeployIfNotExists.
See Azure Policy docs for more information on creating custom policies.
Example
{ "if": { "field": "type", "in": "[parameters('listOfResourceTypes')]" }, "then": { "effect": "AuditIfNotExists", "details": { "type": "Microsoft.Insights/diagnosticSettings", "existenceCondition": { "allOf": [ { "field": "Microsoft.Insights/diagnosticSettings/logs.enabled", "equals": "true" } ] } } } }
Execute Azure DevOps Policy pipeline
to deploy. The policy definition will be deployed to the top level management group
(i.e. pubsec
).
Deploying the policy definition does not put it in effect. You must either create a new custom policy set or update an existing custom policy set to put it in effect.
Navigate to Azure Policy Definitions to verify that the policy has been created.
When there are deployment errors:
- Navigate to Management Groups in Azure Portal
- Select the top level management group (i.e.
pubsec
) - Select Deployments
- Review the deployment errors
Steps
- Step 1: Create policy set definition template
- Step 2: Create policy set assignment template
- Step 3: Configure Azure DevOps Pipeline
- Step 4: Deploy definition & assignment
- Step 5: Verify policy set definition and assignment deployment
-
Navigate to
policy/custom/definitions/policyset
and create two files. ReplacePOLICY_SET_DEFINITION
with the name of your assignment such asloganalytics
.- POLICY_SET_DEFINITION.bicep (i.e.
loganalytics.bicep
) - this file defines the policy set definition deployment - POLICY_SET_DEFINITION.parameters.json (i.e.
loganalytics.parameters.json
) - this file defines the parameters used to deploy the policy set definition
- POLICY_SET_DEFINITION.bicep (i.e.
-
Edit the Bicep file to include the following template. This template can be customized as required. Pre-requisites are:
- targetScope must be
managementGroup
- parameter
policyDefinitionManagementGroupId
must be defined. This parameter identifies the scope of the policy set definition (i.e.pubsec
).
Example See Log Analytics Policy Set definition.
Sample Template
targetScope = 'managementGroup' @description('Management Group scope for the policy definition.') param policyDefinitionManagementGroupId string var customPolicyDefinitionMgScope = tenantResourceId('Microsoft.Management/managementGroups', policyDefinitionManagementGroupId) resource policyset_name 'Microsoft.Authorization/policySetDefinitions@2020-03-01' = { // Policy definition name. This value is used when setting up the policy assignment template in the follow steps. It should be all lowercase and no spaces. // i.e. name: 'custom-enable-logging-to-loganalytics' name: '<< NAME >> properties: { // Display name for the policy set definition displayName: '<< POLICY SET DEFINITION DISPLAY NAME >> ' parameters: { // Add any parameters required for the policy set definition. These parameters are used to pass down information to each policy. } policyDefinitionGroups: [ // Define policy definition groups. These are arbitrary groups that can be created based on your organization's requirements. // The group names are referenced when defining the policies. { name: 'BUILTIN' displayName: 'Additional Controls as Builtin Policies' } { name: 'CUSTOM' displayName: 'Additional Controls as Custom Policies' } ] policyDefinitions: [ // List the policies in this policy set. Repeat this block for every policy definition // An example of a built in policy where the policy definition id can be retrieved from Azure Portal. { groupNames: [ 'BUILTIN' ] policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/5ee9e9ed-0b42-41b7-8c9c-3cfb2fbe2069' policyDefinitionReferenceId: toLower(replace('Deploy Log Analytics agent for Linux virtual machine scale sets', ' ', '-')) parameters: { // Set the values of parameters for each policy. } } // An example of a custom policy where the policy definition id is inferred from the customPolicyDefinitionMgScope variable. // The policy definition name is the directory name. In this example the directory is 'LA-Logs-Diagnostic-Settings' and located in /policy/custom/definitions/policy/LA-Logs-Diagnostic-Settings { groupNames: [ 'CUSTOM' ] policyDefinitionId: extensionResourceId(customPolicyDefinitionMgScope, 'Microsoft.Authorization/policyDefinitions', 'LA-Logs-Diagnostic-Settings') policyDefinitionReferenceId: toLower(replace('Audit diagnostic setting', ' ', '-')) parameters: { listOfResourceTypes: { value: '[parameters(\'listOfResourceTypesToAuditDiagnosticSettings\')]' } } } ] } }
- targetScope must be
-
Edit the JSON parameters file to define the input parameters for the Bicep template. This JSON parameters file is used by Azure Resource Manager (ARM) for runtime inputs.
You can use any of the templated parameters to set values based on environment configuration or hard code them as needed.
Sample Template
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "policyDefinitionManagementGroupId": { "value": "{{var-topLevelManagementGroupName}}" }, "EXTRA_POLICY_SET_ASSIGNMENT_PARAMETER_NAME_1": { "value": "EXTRA_POLICY_SET_ASSIGNMENT_PARAMETER_VALUE_1" }, "EXTRA_POLICY_SET_ASSIGNMENT_PARAMETER_NAME_2": { "value": "EXTRA_POLICY_SET_ASSIGNMENT_PARAMETER_VALUE_2" } } }
Example: Log Analytics Policy Set Parameters
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "policyDefinitionManagementGroupId": { "value": "{{var-topLevelManagementGroupName}}" } } }
-
Navigate to
/policy/custom/assignments
and create two files. ReplacePOLICY_SET_ASSIGNMENT
with the name of your assignment such asloganalytics
.- POLICY_SET_ASSIGNMENT.bicep (i.e.
loganalytics.bicep
) - this file defines the policy set assignment deployment - POLICY_SET_ASSIGNMENT.parameters.json (i.e.
loganalytics.parameters.json
) - this file defines the parameters used to deploy the policy set assignment
- POLICY_SET_ASSIGNMENT.bicep (i.e.
-
Edit the Bicep file to include the following template. This template can be customized as required. Pre-requisites are:
- targetScope must be
managementGroup
- parameter
policyDefinitionManagementGroupId
must be defined. This parameter identifies the scope of the policy set definition (i.e.pubsec
). - parameter
policyAssignmentManagementGroupId
must be defined. This parameter identifies the scope of the policy set assignment (i.e.pubsec
).
Sample Template
targetScope = 'managementGroup' @description('Management Group scope for the policy definition.') param policyDefinitionManagementGroupId string @description('Management Group scope for the policy assignment.') param policyAssignmentManagementGroupId string @allowed([ 'Default' 'DoNotEnforce' ]) @description('Policy set assignment enforcement mode. Possible values are { Default, DoNotEnforce }. Default value: Default') param enforcementMode string = 'Default' // Start - Any custom parameters required for your policy set assignment param ... // End - Any custom parameters required for your policy set assignment var policyId = '<< NAME OF THE POLICY SET DEFINITION >>' var assignmentName = '<< DISPLAY NAME OF THE POLICY SET ASSIGNMENT >>' var scope = tenantResourceId('Microsoft.Management/managementGroups', policyAssignmentManagementGroupId) var policyScopedId = '/providers/Microsoft.Management/managementGroups/${policyDefinitionManagementGroupId}/providers/Microsoft.Authorization/policySetDefinitions/${policyId}' resource policySetAssignment 'Microsoft.Authorization/policyAssignments@2020-03-01' = { // Set the name of the policy set assignment // Example: name: 'logging-${uniqueString('law-',policyAssignmentManagementGroupId)}' name: '<< NAME >>' properties: { displayName: assignmentName policyDefinitionId: policyScopedId scope: scope notScopes: [ ] parameters: { // Add any parameters identified earlier into this section } // The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. enforcementMode: enforcementMode } identity: { type: 'SystemAssigned' } location: deployment().location } // These role assignments are required to allow Policy Assignment to remediate. // Add this section only when there are permissions to assign to the policy set. // Ensure that the name is a GUID and generated with a deterministic formula such as the example below. // Set the role definition id based on the policies in the policy set resource policySetRoleAssignmentLogAnalyticsContributor 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = { name: guid(policyAssignmentManagementGroupId, 'loganalytics', 'Log Analytics Contributor') scope: managementGroup() properties: { roleDefinitionId: '/providers/Microsoft.Authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293' principalId: policySetAssignment.identity.principalId principalType: 'ServicePrincipal' } }
Example: Log Analytics Policy Set Assignment
targetScope = 'managementGroup' @description('Management Group scope for the policy definition.') param policyDefinitionManagementGroupId string @description('Management Group scope for the policy assignment.') param policyAssignmentManagementGroupId string @allowed([ 'Default' 'DoNotEnforce' ]) @description('Policy set assignment enforcement mode. Possible values are { Default, DoNotEnforce }. Default value: Default') param enforcementMode string = 'Default' @description('Log Analytics Workspace Resource Id') param logAnalyticsResourceId string @description('Log Analytics Workspace Id') param logAnalyticsWorkspaceId string var policyId = 'custom-enable-logging-to-loganalytics' var assignmentName = 'Custom - Log Analytics for Azure Services' var scope = tenantResourceId('Microsoft.Management/managementGroups', policyAssignmentManagementGroupId) var policyScopedId = '/providers/Microsoft.Management/managementGroups/${policyDefinitionManagementGroupId}/providers/Microsoft.Authorization/policySetDefinitions/${policyId}' resource policySetAssignment 'Microsoft.Authorization/policyAssignments@2020-03-01' = { name: 'logging-${uniqueString('law-',policyAssignmentManagementGroupId)}' properties: { displayName: assignmentName policyDefinitionId: policyScopedId scope: scope notScopes: [ ] parameters: { logAnalytics: { value: logAnalyticsResourceId } logAnalyticsWorkspaceId: { value: logAnalyticsWorkspaceId } } enforcementMode: enforcementMode } identity: { type: 'SystemAssigned' } location: deployment().location } // These role assignments are required to allow Policy Assignment to remediate. resource policySetRoleAssignmentLogAnalyticsContributor 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = { name: guid(policyAssignmentManagementGroupId, 'loganalytics', 'Log Analytics Contributor') scope: managementGroup() properties: { roleDefinitionId: '/providers/Microsoft.Authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293' principalId: policySetAssignment.identity.principalId principalType: 'ServicePrincipal' } } resource policySetRoleAssignmentVirtualMachineContributor 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = { name: guid(policyAssignmentManagementGroupId, 'loganalytics', 'Virtual Machine Contributor') scope: managementGroup() properties: { roleDefinitionId: '/providers/Microsoft.Authorization/roleDefinitions/9980e02c-c2be-4d73-94e8-173b1dc7cf3c' principalId: policySetAssignment.identity.principalId principalType: 'ServicePrincipal' } } resource policySetRoleAssignmentMonitoringContributor 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = { name: guid(policyAssignmentManagementGroupId, 'loganalytics', 'Monitoring Contributor') scope: managementGroup() properties: { roleDefinitionId: '/providers/Microsoft.Authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa' principalId: policySetAssignment.identity.principalId principalType: 'ServicePrincipal' } }
- targetScope must be
-
Edit the JSON parameters file to define the input parameters for the Bicep template. This JSON parameters file is used by Azure Resource Manager (ARM) for runtime inputs.
You can use any of the templated parameters to set values based on environment configuration or hard code them as needed.
Sample Template
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "policyDefinitionManagementGroupId": { "value": "{{var-topLevelManagementGroupName}}" }, "policyAssignmentManagementGroupId": { "value": "{{var-policyAssignmentManagementGroupId}}" }, "enforcementMode": { "value": "Default" }, "EXTRA_POLICY_ASSIGNMENT_PARAMETER_NAME_1": { "value": "EXTRA_POLICY_ASSIGNMENT_PARAMETER_VALUE_1" }, "EXTRA_POLICY_ASSIGNMENT_PARAMETER_NAME_2": { "value": "EXTRA_POLICY_ASSIGNMENT_PARAMETER_VALUE_2" } } }
Example: Log Analytics Policy Set Parameters
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "policyDefinitionManagementGroupId": { "value": "{{var-topLevelManagementGroupName}}" }, "policyAssignmentManagementGroupId": { "value": "{{var-policyAssignmentManagementGroupId}}" }, "enforcementMode": { "value": "Default" }, "logAnalyticsWorkspaceId": { "value": "{{var-logging-logAnalyticsWorkspaceId}}" }, "logAnalyticsResourceId": { "value": "{{var-logging-logAnalyticsWorkspaceResourceId}}" } } }
- Edit
/.pipelines/policy.yml
- Navigate to the
CustomPolicyJob
Job definition - Navigate to the
Define Policy Set
Step definition and add the policy definition file name (without extension) to thedeployTemplates
array parameter - Navigate to the
Assign Policy Set
Step definition and add the policy assignment file name (without extension) to thedeployTemplates
array parameter
Execute Azure DevOps Policy pipeline
to deploy. The policy set definition and assignment will be deployed to the top level management group
(i.e. pubsec
).
It takes around 30 minutes for the assignment to be applied to the defined scope. Once it's applied, the evaluation cycle begins for resources within that scope against the newly assigned policy or initiative and depending on the effects used by the policy or initiative, resources are marked as compliant, non-compliant, or exempt. A large policy or initiative evaluated against a large scope of resources can take time. As such, there's no pre-defined expectation of when the evaluation cycle completes. Once it completes, updated compliance results are available in the portal and SDKs. See Azure Docs for more information.
Navigate to Azure Policy Definitions and Azure Policy Assignments to verify that the policy set has been created.
When there are deployment errors:
- Navigate to Management Groups in Azure Portal
- Select the top level management group (i.e.
pubsec
) - Select Deployments
- Review the deployment errors
Steps
Update azurepolicy.config.json
, azurepolicy.parameters.json
and azurepolicy.rules.json
as required.
Execute Azure DevOps Policy pipeline
to automatically deploy the policy definition update.
Navigate to Azure Policy Definitions to verify that the policy has been updated.
It takes around 30 minutes for the update to be applied. Once it's applied, the evaluation cycle begins for resources within that scope against the newly assigned policy or initiative and depending on the effects used by the policy or initiative, resources are marked as compliant, non-compliant, or exempt. A large policy or initiative evaluated against a large scope of resources can take time. As such, there's no pre-defined expectation of when the evaluation cycle completes. Once it completes, updated compliance results are available in the portal and SDKs. See Azure Docs for more information.
When there are deployment errors:
- Navigate to Management Groups in Azure Portal
- Select the top level management group (i.e.
pubsec
) - Select Deployments
- Review the deployment errors
Steps
- Step 1: Update policy set definition & assignment
- Step 2: Verify policy set definition & assignment after update
- Update policy set definition Bicep template & JSON parameters as required.
- Update policy set assignment Bicep template & JSON parameters as required (typically when a new role assignment expected to support a new policy).
Consider when updating a policy set definition & assignment:
- Any new parameter added to the policy set definition must have a
default value
to stay backward compatible with existing assignments. - Ensure that any new role assignments are incorporated in the policy assignment definition.
- Avoid changing the policy set definition name. If this is required, remove the policy set assignment and its role assignments first.
- Avoid changing the policy set role assignment names. If this is required, remove the policy set assignment and its role assignments first.
Execute Azure DevOps Policy pipeline
to deploy the policy set definition & assignment update.
Navigate to Azure Policy Definitions and Azure Policy Assignments to verify that the policy set has been updated.
When there are deployment errors:
- Navigate to Management Groups in Azure Portal
- Select the top level management group (i.e.
pubsec
) - Select Deployments
- Review the deployment errors
Azure DevOps Pipeline does not remove the custom policy definition from Azure. It will only remove the policy definition reference from the custom policy sets that are managed through automation. You must manually delete the policy definition using Azure Policy Definitions in Azure Portal.
Steps
- Navigate to
/policy/custom/definitions/policy
and identify the custom policy definition directory to delete. - Identify all custom policy set definitions that reference the policy (they are referenced using the directory name) and remove the references.
- Delete the custom policy definition directory in
policy/custom/definitions/policy
- Execute
Azure DevOps Policy pipeline
to deploy the updates.
Automation does not remove an existing policy set assignment. Removing the policy set assignment from the Azure DevOps pipeline ensures that it's no longer created. Any existing policy set assignments must be deleted manually.
Steps
- Step 1: Remove custom policy set definition
- Step 2: Remove custom policy set assignment
- Step 3: Remove custom policy set from Azure DevOps Pipeline
- Step 4: Remove custom policy set assignment's IAM assignments
- Navigate to
/policy/custom/definitions/policyset
and delete the policy set definition Bicep template and JSON parameter files.
- Navigate to
/policy/custom/assignments
and delete the policy set assignment Bicep template and JSON parameter files.
- Edit
/.pipelines/policy.yml
- Navigate to the
CustomPolicyJob
Job definition - Navigate to the
Define Policy Set
Step definition and remove the policy definition file name from thedeployTemplates
array parameter - Navigate to the
Assign Policy Set
Step definition and remove the policy assignment file name from thedeployTemplates
array parameter
- Navigate to Azure Policy Assignments in Azure Portal
- Find the policy set assignment
- Click on the
...
beside the policy set assignment and selectDelete assignment
- Navigate to Management Groups in Azure Portal
- Select the top level management group (i.e.
pubsec
) - Select Access control (IAM)
- Select Role Assignments
- Use the
Type
filter to find anyUnknown
role assignments and delete them. This step is required since deleting the policy set assignment does not automatically remove any role assignments. When the policy set assignment is removed, it's managed identity is also removed thus marking these role assignments asUnknown
.
- Select the top level management group (i.e.
You may want to evaluate the compliance in your environment without any automatic remediation, either through DeployIfNotExists
or modify
policies. To support this scenario, all policy set assignments support an enforcementMode
setting. This can be set to either: Default
or DoNotEnforce
:
Default
= enable policy set enforcementDoNotEnforce
= disable policy set enforcement
Please review guidance and expected behaviour of these settings prior to making any modification:
You can switch between these modes per-policy set based on your Azure Policy adoption strategy.
To manage this setting:
- Navigate to policy/custom/assignments
- Open
*.parameters.json
. There is 1 parameters file per policy set assignment - Modify
enforcementMode
parameter with eitherDefault
orDoNotEnforce
- Re-run the
policy-ci
Azure DevOps pipeline to update Azure
Before auto generating a custom Diagnostic Settings policy, we recommend searching for a suitable built-in policy through Azure Policy Definitions.
The Diagnostic Settings policies in this reference implementation were created using scripts from GitHub (JimGBritt/AzurePolicy). The steps are:
- Deploy an instance of the Azure Service (i.e. Azure Bastion)
- Execute
Create-AzDiagPolicy.PS1
- Follow instructions in GitHub - Use the instructions for creating new custom policy definition to copy the generated content.
- Copy the contents into
azurepolicy.parameters.json
andazurepolicy.rules.json
. - Create
azurepolicy.config.json
with policy name and mode.
- Copy the contents into
- Delete the instance created in Step 1.