What is Azure Policy?
Azure Policy is something that's been on my radar for a little while as it provides a solution to some of our "internal cloud provider" issues. For us it's been problematic to be the delivers of cloud solutions but tending to be on the tail end of deployments and lacking the authority to intervene in some aspects of project delivery.
Microsoft has a docs site on Policy:
https://docs.microsoft.com/en-us/azure/azure-policy/
and I'd like to call out this from the get go:
IT governance creates clarity between business goals and IT projects. Good IT governance involves planning your initiatives and setting priorities on a strategic level. Does your company experience a significant number of IT issues that never seem to get resolved? Implementing policies helps you better manage and prevent them. Implementing policies is where Azure Policy comes in.
and for emphasis: implementing policies is where Azure Policy comes in! The point Microsoft is making here is that the strategic direction and the policies required for Azure should already be in place prior to implementing the tool.
Examples of some of your businesses requirements can vary but a few that come to mind:
- is there a type of VM we never want deployed?
- is there a minimum SQL version we support?
- should some locations be barred for regulatory or cost reasons?
these are all policies both internal IT and business should have agreed to prior to deployment. If you're scrambling post deployment to enact controls or are the sysadmin having to retcon policy in a strategic vacuum be careful not to be overly restrictive to begin with. It's actually best to simply engage in auditing rather than explicitly set restrictions on already deployed resources.
Microsoft keeps it's definition of Policy reasonably terse
Azure Policy is a service in Azure that you use to create, assign and, manage policy definitions
and really that's all we are working with here. Policies define a set of controls to manage what can and can't be done in Azure and monitors compliance of these rules. It's got the usual Azure slick delivery to it as well with both a tech friendly Powershell/REST deployment approach matched with a GUI deployment option and management friendly compliance reporting interface.
Microsoft recommends, and it's damn good advice, you always use initiative definitions rather then policy definitions. This allows you to better manage well scoped policies. In the example below I am focused on cost management and have a single initiative definition called Cost Management for DEV which includes policies for tagging and limiting available VM SKUs.
Costs
Right now, nothing! But we are in preview here so that's not going to be the case for much longer. Microsoft mentions costing in their tutorial on policy:
There are two pricing tiers within Azure Policy – Free and Standard. With the Free tier, you can only enforce policies on future resources, while with Standard, you can also enforce them on existing resources to better understand your compliance state. Because we are in Limited Preview, we have not yet released a pricing model, so you will not receive a bill for selecting Standard
and that is perfectly fine. There is a link after the above statement that Microsoft implies has more information on cost but currently doesn't redirect. Here it is anyway in case that link is eventually fixed:
https://acom-milestone-ignite.azurewebsites.net/pricing/details/azure-policy/
Creating the Policy
At this early point I'd like to note that this is the PowerShell process of deployment and management. There is a full GUI version but for the purposes of my deployment, which is version controlled etc, I need PS.
Probably the best starting point for creating an Azure Policy / Definition / Initiative is the Microsoft Policy Samples:
https://docs.microsoft.com/en-us/azure/azure-policy/json-samples
This is a nifty collection of "beginner" policies you can use directly, edit for your own purposes or simply peruse for future implementation options. For what I am looking for I am going to start with the Billing Policy Tags Initiative:
https://docs.microsoft.com/en-us/azure/azure-policy/scripts/billing-tags-policy-init
and have a collection of forced tags on all resources. The Microsoft JSON looks like this:
{
"properties": {
"displayName": "Billing Tags Policy Initiative",
"description": "Specify cost Center tag and product name tag",
"parameters": {
"costCenterValue": {
"type": "String",
"metadata": {
"displayName": "required value for Cost Center tag"
}
},
"productNameValue": {
"type": "String",
"metadata": {
"displayName": "required value for product Name tag"
}
}
},
"policyDefinitions": [
{
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/1e30110a-5ceb-460c-a204-c1c3969c6d62",
"parameters": {
"tagName": {
"value": "costCenter"
},
"tagValue": {
"value": "[parameters('costCenterValue')]"
}
}
},
{
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/2a0e14a6-b0a6-4fab-991a-187a4f81c498",
"parameters": {
"tagName": {
"value": "costCenter"
},
"tagValue": {
"value": "[parameters('costCenterValue')]"
}
}
},
{
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/1e30110a-5ceb-460c-a204-c1c3969c6d62",
"parameters": {
"tagName": {
"value": "productName"
},
"tagValue": {
"value": "[parameters('productNameValue')]"
}
}
},
{
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/2a0e14a6-b0a6-4fab-991a-187a4f81c498",
"parameters": {
"tagName": {
"value": "productName"
},
"tagValue": {
"value": "[parameters('productNameValue')]"
}
}
}
]
},
"id": "/subscriptions/a48a924d-6007-4c39-a3c0-5466b9012f42/providers/Microsoft.Authorization/policySetDefinitions/billingTagsPolicy",
"type": "Microsoft.Authorization/policySetDefinitions",
"name": "billingTagsPolicy"
}
BUT for my purposes this isn't 100% what I am trying to achieve. I am trying to do the following:
- ensure the tags are there
- DO NOT append existing tags that are already there and match the values provided
- update the objects that have not tags with the tag listed BUT add a dummy value I can scrape later for reporting (a version of non compliance)
Why do this? For what we are trying to achieve in house these policies will be very "high level" and will not be specific to a subscription / resource group. I want the tag there, but I do not necessarily want to specify it's value at this stage. In our case much of the work in Azure is providing the platform for use by other parties within the business so our teams core focus is on security and cost management.
Extending the above to also cover some other tasks as well (such as setting specific VMs as off limit) will also be a useful task in our dev environment. So here is a list of what I want to have specified in our dev environment:
- tags and values (some dummies): Apply tag and its default value
- allowed VMs: Allowed Virtual Machine SKUs
there are other policies of interest but the reality is I don't want to be too restrictive on the first run through. I also don't want to deviate from the Microsoft built-in policies until after the limited preview. I'll write a further article on advanced policy management in the future once we are out of preview.
Microsoft's docs site also has a handy reference for Policy Definition Structure:
https://docs.microsoft.com/en-us/azure/azure-policy/policy-definition
which boils down to this:
- mode
- parameters
- display name
- description
- policy rule
- logical evaluation
- effect
So after all that what does the final policy look like?
{
"properties": {
"displayName": "Cost Management for DEV",
"description": "Adds some default tags if they aren't there and limits VM types",
"parameters": {
"currentEnvironment": {
"type": "String",
"metadata": {
"displayName": "current environment resource exists in"
}
},
"productOwner": {
"type": "String",
"metadata": {
"displayName": "current product owner"
}
},
"imageIds": {
"type": "array",
"metadata": {
"description": "The list of approved VM images",
"displayName": "Approved VM images"
}
}
},
"policyDefinitions": [
{
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/2a0e14a6-b0a6-4fab-991a-187a4f81c498",
"parameters": {
"tagName": {
"value": "ENV"
},
"tagValue": {
"value": "[parameters('currentEnvironment')]"
}
}
},
{
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/2a0e14a6-b0a6-4fab-991a-187a4f81c498",
"parameters": {
"tagName": {
"value": "productOwner"
},
"tagValue": {
"value": "[parameters('productOwner')]"
}
}
}
],
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"not": {
"field": "Microsoft.Compute/imageId",
"in": "[parameters('imageIds')]"
}
}
]
},
"then": {
"effect": "deny"
}
}
},
"id": "/subscriptions/<subscription-id>/providers/Microsoft.Authorization/policySetDefinitions/billingDEV",
"type": "Microsoft.Authorization/policySetDefinitions",
"name": "billingDEV"
}
Deploying Policy
Now that you have yourself a nice new policy initiative ready to test how do you deploy it? Easily!
New-AzureRmPolicySetDefinition -Name "YOURNAMEHERE" -PolicyDefinition C:\YOURFILE.json -Parameter $parameterfileslocation
or grab directly from the relevant source control location. In the above you'll also need to set a parameter file to give a list of all your tags and approved SKUs.
Would you like to know more?
I'll be writing a more in depth article once the product comes out of preview and once I've used it out of dev and in anger. There is a whole section on compliance management and remediation that will need some further investigation on my part. For now though the Microsoft sites listed above are a great starting point and for raw policy info head on over to Github:
https://github.com/Azure/azure-policy
https://docs.microsoft.com/en-us/powershell/module/azurerm.resources/?view=azurermps-5.1.1#policies