Quickstart: Create a policy assignment to identify non-compliant resources by using ARM template
In this quickstart, you use an Azure Resource Manager template (ARM template) to create a policy assignment that validates resource's compliance with an Azure policy. The policy is assigned to a resource group and audits virtual machines that don't use managed disks. After you create the policy assignment, you identify non-compliant virtual machines.
An Azure Resource Manager template is a JavaScript Object Notation (JSON) file that defines the infrastructure and configuration for your project. The template uses declarative syntax. You describe your intended deployment without writing the sequence of programming commands to create the deployment.
If your environment meets the prerequisites and you're familiar with using ARM templates, select the Deploy to Azure button. The template opens in the Azure portal.
When assigning a built-in policy or initiative definition, it's optional to reference a version. Policy assignments of built-in definitions default to the latest version and automatically inherit minor version changes unless otherwise specified.
Prerequisites
- If you don't have an Azure account, create a free account before you begin.
- Azure PowerShell or Azure CLI.
- Visual Studio Code and the Azure Resource Manager (ARM) Tools.
Microsoft.PolicyInsights
must be registered in your Azure subscription. To register a resource provider, you must have permission to register resource providers. That permission is included in the Contributor and Owner roles.- A resource group with at least one virtual machine that doesn't use managed disks.
Review the template
The ARM template creates a policy assignment for a resource group scope and assigns the built-in policy definition Audit VMs that do not use managed disks.
Create the following ARM template as policy-assignment.json.
- Open Visual Studio Code and select File > New Text File.
- Copy and paste the ARM template into Visual Studio Code.
- Select File > Save and use the filename policy-assignment.json.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"policyAssignmentName": {
"type": "string",
"defaultValue": "audit-vm-managed-disks",
"metadata": {
"description": "Policy assignment name used in assignment's resource ID"
}
},
"policyDefinitionID": {
"type": "string",
"defaultValue": "/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d",
"metadata": {
"description": "Policy definition ID"
}
},
"policyDisplayName": {
"type": "string",
"defaultValue": "Audit VM managed disks",
"metadata": {
"description": "Display name for Azure portal"
}
}
},
"resources": [
{
"type": "Microsoft.Authorization/policyAssignments",
"apiVersion": "2023-04-01",
"name": "[parameters('policyAssignmentName')]",
"properties": {
"policyDefinitionId": "[parameters('policyDefinitionID')]",
"description": "Policy assignment to resource group scope created with ARM template",
"displayName": "[parameters('policyDisplayName')]",
"nonComplianceMessages": [
{
"message": "Virtual machines should use managed disks"
}
]
}
}
],
"outputs": {
"assignmentId": {
"type": "string",
"value": "[resourceId('Microsoft.Authorization/policyAssignments', parameters('policyAssignmentName'))]"
}
}
}
The resource type defined in the ARM template is Microsoft.Authorization/policyAssignments.
The template uses three parameters to deploy the policy assignment:
policyAssignmentName
creates the policy assignment named audit-vm-managed-disks.policyDefinitionID
uses the ID of the built-in policy definition. For reference, the commands to get the ID are in the section to deploy the template.policyDisplayName
creates a display name that's visible in Azure portal.
For more information about ARM template files:
- To find more ARM template samples, go to Browse code samples.
- To learn more about template reference's for deployments, go to Azure template reference.
- To learn how to develop ARM templates, go to ARM template documentation.
- To learn about subscription-level deployments, go to Subscription deployments with ARM templates.
Deploy the ARM template
You can deploy the ARM template with Azure PowerShell or Azure CLI.
From a Visual Studio Code terminal session, connect to Azure. If you have more than one subscription, run the commands to set context to your subscription. Replace <subscriptionID>
with your Azure subscription ID.
Connect-AzAccount
# Run these commands if you have multiple subscriptions
Get-AzSubScription
Set-AzContext -Subscription <subscriptionID>
You can verify if Microsoft.PolicyInsights
is registered. If it isn't, you can run a command to register the resource provider.
Get-AzResourceProvider -ProviderNamespace 'Microsoft.PolicyInsights' |
Select-Object -Property ResourceTypes, RegistrationState
Register-AzResourceProvider -ProviderNamespace 'Microsoft.PolicyInsights'
For more information, go to Get-AzResourceProvider and Register-AzResourceProvider.
The following commands display the policyDefinitionID
parameter's value:
(Get-AzPolicyDefinition |
Where-Object { $_.Properties.DisplayName -eq 'Audit VMs that do not use managed disks' }).ResourceId
The following commands deploy the policy definition to your resource group. Replace <resourceGroupName>
with your resource group name:
$rg = Get-AzResourceGroup -Name '<resourceGroupName>'
$deployparms = @{
Name = 'PolicyDeployment'
ResourceGroupName = $rg.ResourceGroupName
TemplateFile = 'policy-assignment.json'
}
New-AzResourceGroupDeployment @deployparms
The $rg
variable stores properties for the resource group. The $deployparms
variable uses splatting to create parameter values and improve readability. The New-AzResourceGroupDeployment
command uses the parameter values defined in the $deployparms
variable.
Name
is the deployment name displayed in the output and in Azure for the resource group's deployments.ResourceGroupName
uses the$rg.ResourceGroupName
property to get the name of your resource group where the policy is assigned.TemplateFile
specifies the ARM template's name and location on your local computer.
You can verify the policy assignment's deployment with the following command:
The command uses the $rg.ResourceId
property to get the resource group's ID.
Get-AzPolicyAssignment -Name 'audit-vm-managed-disks' -Scope $rg.ResourceId
Name : audit-vm-managed-disks
ResourceId : /subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Authorization/policyAssignments/audit-vm-managed-disks
ResourceName : audit-vm-managed-disks
ResourceGroupName : {resourceGroupName}
ResourceType : Microsoft.Authorization/policyAssignments
SubscriptionId : {subscriptionId}
PolicyAssignmentId : /subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Authorization/policyAssignments/audit-vm-managed-disks
Properties : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.Policy.PsPolicyAssignmentProperties
For more information, go to Get-AzPolicyAssignment.
Identify non-compliant resources
After the policy assignment is deployed, virtual machines that are deployed to the resource group are audited for compliance with the managed disk policy.
The compliance state for a new policy assignment takes a few minutes to become active and provide results about the policy's state.
$complianceparms = @{
ResourceGroupName = $rg.ResourceGroupName
PolicyAssignmentName = 'audit-vm-managed-disks'
Filter = 'IsCompliant eq false'
}
Get-AzPolicyState @complianceparms
The $complianceparms
variable creates parameter values used in the Get-AzPolicyState
command.
ResourceGroupName
gets the resource group name from the$rg.ResourceGroupName
property.PolicyAssignmentName
specifies the name used when the policy assignment was created.Filter
uses an expression to find resources that aren't compliant with the policy assignment.
Your results resemble the following example and ComplianceState
shows NonCompliant
:
Timestamp : 2/26/2024 19:02:56
ResourceId : /subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/microsoft.compute/virtualmachines/{vmId}
PolicyAssignmentId : /subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/microsoft.authorization/policyassignments/audit-vm-managed-disks
PolicyDefinitionId : /providers/microsoft.authorization/policydefinitions/06a78e20-9358-41c9-923c-fb736d382a4d
IsCompliant : False
SubscriptionId : {subscriptionId}
ResourceType : Microsoft.Compute/virtualMachines
ResourceLocation : {location}
ResourceGroup : {resourceGroupName}
ResourceTags : tbd
PolicyAssignmentName : audit-vm-managed-disks
PolicyAssignmentOwner : tbd
PolicyAssignmentScope : /subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}
PolicyDefinitionName : 06a78e20-9358-41c9-923c-fb736d382a4d
PolicyDefinitionAction : audit
PolicyDefinitionCategory : tbd
ManagementGroupIds : {managementGroupId}
ComplianceState : NonCompliant
AdditionalProperties : {[complianceReasonCode, ]}
For more information, go to Get-AzPolicyState.
Clean up resources
Remove-AzPolicyAssignment -Name 'audit-vm-managed-disks' -Scope $rg.ResourceId
To sign out of your Azure PowerShell session:
Disconnect-AzAccount
Next steps
In this quickstart, you assigned a policy definition to identify non-compliant resources in your Azure environment.
To learn more about how to assign policies that validate resource compliance, continue to the tutorial.