Using Azure resource manager policy and Azure lock to control your Azure resources
My higher education customer in the Midwest was asking how they could control regional placement of VMs in Azure, how they could restrict VM sizes in Azure, how they could enforce tagging or naming standards for resources, and how they could prevent the accidental deletion of Azure resources. Luckily, we have a solution to these type of scenarios using a combination of Azure resource manager policy and Azure resource lock. I put together a quick FAQ and show some examples on how to use both:
What are Azure resource manager policies and what is the scope of their use?
Azure resource manager policies are used to control what you can and cannot do with resources called resource actions. Some examples of this would be – I want all ARM resources created in my subscription to only be allowed to create VMs in the U.S. datacenters, I want all newly created resource manager resources in my subscription to enforce departmental tagging to allow for chargeback purposes, or I want all my Azure resources to adhere to a naming convention to keep uniform naming standards across the subscription.
As far as policy scope, you can push a resource manager policy to the subscription level, resource group level or resource level.
Will these work with my ASM resources?
No, resource manager policies imply they can only be used with ARM based resources as the classic ASM resources cannot leverage this.
What format is a resource manager policy and what can I use it with?
You have create the RM policy using JSON. It requires one or more conditions/logical operators which define the actions and effect when a policy is met. See here for more on RM Policy using JSON.
Typically you use IF and Then logic and then you can Deny, Append, or Audit as a result of a policy all within your JSON. For example if you want to Deny the ability to create resources outside of these three U.S. Datacenters you would use this JSON:
{ "if" : { "not" : { "field" : "location", "in" : ["centralus" , "westus".”eastus”] } }, "then" : { "effect" : "deny" } } |
When you build your JSON RM policy you have to keep in mind two things:
1) What resources do you want to apply policy to
2) What scope/level do you want to the apply the policy
The current resources available to leverage RM polices are:
Virtual Machines
Storage Accounts
Job Collections
Database Accounts
Redis cache
CDN Profiles
VM Image Publisher
VM ImageOffer
VM ImageSKU
VM Image Version
Redis enableNonSSLPort
Redis shardCount
How can I build a resource manager policy?
To build an RM policy via JSON script you can use the native JSON editor built into Visual Studio 2015 or the JSON editor of your choice:
1) Review JSON RM policy samples here for reference.
2) Open Visual Studio 2015 with Azure SDK 2.9 (as of April) installed
3) Select File > New > File > JSON file
4) Insert the RM policy JSON schema at the beginning in the schema section:
https://schema.management.azure.com/schemas/2015-10-01-preview/policyDefinition.json
This will allow for the intellisense and autocomplete to enable to help ensure of the proper JSON RM policy syntax:
I created a sample JSON which restricts which VM SKU sizes I can choose from to A0, A1, and D1:
{
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"not": {
"field": "Microsoft.Compute/virtualMachines/sku.name",
"in": [ "Standard_A0", "Standard_A1", "Standard_D1" ]
}
}
]
},
"then": {
"effect": "deny"
}
}
5) Save the RM policy JSON file locally
6) Create the RM Policy definition via PowerShell using New-AzureRmPolicyDefintion:
New-AzureRmPolicyDefinition -Name regionPolicyDefinition -Description "Policy to allow resource creation only in certain regions" -Policy "path-to-policy-json-on-disk"
I created a sample RM policy called ‘RestrictVMsizes’ and tied it to the JSON policy I created above:
New-AzureRmPolicyDefinition -Name RestrictVMsizes -Description "Policy to restrict VM sizes to predefined SKUs" -Policy "C:\json\policyblockVmskus.json"
7) Apply the RM Policy via PowerShell using New-AzureRmPolicyAssignment:
Set $policy variable first:
$Policy = Get-AzureRmPolicyDefinition -Name "policyname"
Next assign RM policy and scope with $policy variable:
New-AzureRmPolicyAssignment -Name regionPolicyAssignment -PolicyDefinition $policy -Scope /subscriptions/########-####-####-####-############/resourceGroups/<resource-group-name>
In my example, I wanted to assign ‘RestrictVMSizes’ RM policy to CS-RG-main resource group for scope to restrict VM sizes to A1, A2, and D1:
$Policy = Get-AzureRmPolicyDefinition -Name "RestrictLocation"
New-AzureRmPolicyAssignment -Name regionPolicytoCSRG -PolicyDefinition $policy -Scope /subscriptions/ab123456-78c9-5555-d4ef-a1b2cf3d1234/resourceGroups/cs-rg-main
8) Validate RM policy works by trying to change or violate the policy you set.
In my example, I tried to create a large GS2 VM size using a HUB custom image JSON script I put together here which was not allowed within the ‘CS-RG-Main’ resource group and it did indeed block the creation of that VM:
How can I view RM policies I have created and assigned?
For viewing all the RM policies you have created you would run:
Get-AzureRMpolicydefinition
As you build your RM policy library you can then re-use them against new resources like new resource groups, etc.
For viewing policies you have assigned along with their scope run:
Get-AzureRMpolicyassignment
This will show all your assigned policies and the scope of which the policy is applied for example:
Scope=/subscriptions/abc1234-5678-4567-c8d9-a1b2cf3d9876/resourceGroups/cs-rg-main
How can I remove assigned RM policies?
To remove your RM policy you would run:
Remove-AzureRMPolicyAssignment
In my example, I wanted to remove the ‘RestrictVMsizes’ RM policy assigned to the resource group ‘cs-rg-main’ so I ran:
$ResourceGroup = Get-AzureRmResourceGroup -Name "cs-rg-main"
Remove-AzureRmPolicyAssignment -Name "RestrictVMsizes" -Scope $ResourceGroup.ResourceId –Force
You will receive ‘True’ if it was removed successfully. You can re-run Get-AzureRMPolicyAsssignment to verify it was removed.
How can I lock my Azure resources from accidental deletion?
Another popular question I get is how can I freeze or lock my production/critical Azure resources from accidental deletion? There is way to do this with both ASM and ARM resources using Azure resource lock. You can lock entire subscriptions, lock resources like storage groups or you can lock entire resource groups. See below for an example on how to lock an entire resource group using Azure PowerShell:
For ASM resources:
New-AzureResourceLock -locklevel CanNotDelete -LockNotes 'prevent deletion' -LockName 'ITgrouplockASM' -ResourceGroupName 'CSdept-rg-main' –verbose
For ARM resources:
New-AzureRmResourceLock -locklevel CanNotDelete -LockNotes 'prevent deletion' -LockName 'ITgrouplock' -ResourceGroupName 'Englishdept-rg-main' -verbose
Example:
Execute the PowerShell above and then confirm you want to lock:
The current locklevels are only ‘cannotdelete’ however you can view and edit properties within the resource with a lock enabled.
To view all your locked ARM resources run the following PowerShell:
Get-AzureRMResourceLock
If you try and delete something within that resource group while it is locked you will receive:
To remove your resource lock from your resource group you type the following:
Remove-azurermresourcelock –lockname lockname –resourcegroupname groupname
Removing the resource lock should return the value ‘True’
For more on resource manager policy see here.
For more on resource locking please see here.
Comments
- Anonymous
December 13, 2017
Hello! I am having problems trying to apply the location lockdown policy with a parameter instead of being hardcoded, I tried tons of different ways to pass the parameter string to the policy but it just wont show any location selected when I see the assignment policies.This is how I have set the definition, is there something wrong?:$GeoLockdownPolicy = @"{ "if": { "not": { "field": "location", "in": "[parameters('listOfAllowedLocations')]" } }, "then": { "effect": "deny" }}"@$GeoLockdownParameters = '{ "listOfAllowedLocations": { "type": "Array", "metadata": { "description": "The list of locations that can be specified when deploying resources.", "strongType": "location", "displayName": "Allowed locations" } }}'New-AzureRmPolicyDefinition -Name "Geo-Lockdown" -DisplayName "Geo-Lockdown" -description "This policy enables you to restrict the locations your organization can specify when deploying resources. Use to enforce your geo-compliance requirements." -Policy $GeoLockdownPolicy -Parameter $GeoLockdownParameters -Mode All