Getting started with Azure Policy
Recently as part of a data classification implementation certain aspects were implemented using Azure Policy, since is supports auditing of existing resources and can prevent non-compliant resources from being created in the first instance.
Like most things, the documentation reads well and the samples seem useful, until one has to do something different and go off-piste. There are plenty of VM and tagging samples though not so many for Azure SQL Database. Therefore as Sabin is a data engineering consultancy, all examples given here will be Azure SQL Database focused and not the canonical VM as found in many examples.
What is an Azure Policy?
Without going into the anatomy of an Azure Policy, since much of that is given at Azure Policy overview, Azure Policy definition structure and elsewhere, an Azure Policy can be summarised as a container for a rule and its related metadata. The rule is expressed as if <condition> then <effect> and the condition may be applied to one or more fields. The policy can then be assigned to one or more subscriptions or resource groups to audit existing resources or prevent (deny) resources from being created that fail the rule.
A field can be one of name, full name, kind, type, location, tags or property alias. These are given at Azure Policy, policy rule definition, and lacking detail. This is a shame, since an understanding of fields is fundamental to understanding how to write a rule. Tags and location are self explanatory, however, unless one is familiar with ARM templates the other fields require an expanded explanation.
What is a type?
A type is an Azure Resource Type. Every Azure resource is of a type and often composed of more than one type. The table following gives the type for some well known Azure resources.
Is is best to think of these as top level complex resource types that are made up of or are containers for other resource types. The table following below gives some examples of well known contained types.
As can be seen resource types are not always intuitive, and later I will show how to find the resource type.
What is a name?
If a resource [type] can be named then name is what you would expect it to be. Continuing with the resource types presented above, the table following gives examples of some names that are intuitive.
However, many resource types are defaulted, for example, threat detection, transparent data encryption or firewall rules, and these can have a variety of default names. The table following gives some examples, and though some may seem obvious, they are not consistent.
What is a full name?
Once the resource type and name are understood then full name is easy to grasp as it is essentially a merge of the two as shown in the table following. For the sake of brevity the preceding part /subscriptions/<subscription-guid>/resourceGroups/resources-euw/providers/ is omitted since it is common to all.
What is a kind?
Kind can be a version number or an indicator of being user or system created, and is best illustrated by example as per the table following
What is a property alias?
Property aliases are the means by which properties of a resource type are accessed. Unfortunately, not all properties are currently available for use in an Azure Policy. The properties that are available can be discovered using the Powershell given at Azuer Policy definition structure, aliases. The Azure SQL Database resource types and property aliases that can currently be accessed by Azure Policy are given below.
As can be seen, the transparent data encryption resource type exposes exactly one property alias, status.
Finding field values
Assuming you’re still with me and now understand what each of name, full name, kind, type and property alias are, all that is left is to understand is how to find field values, be it a default name or value to test.
Initially I planned to have Azure Resource Explorer (preview) as the first step. It has however, lost its shine, as I find that it does not always drill down to the required level, stopping short of being complete. As illustrated in the screen shot below only transparent data encryption expands, and with an error.
That said, this is a very useful tool for exploring resources in a subscription and there is much insight to be gained from using it, making it worth a look.
The following approach, albeit clunky, works well
1. Create and modify a test resource
All changes to a resource are recorded by the Azure Activity log, and therefore this is the best place to start. It is easily accessed from the Azure Portal via the search bar as shown below.
As shown below, if threat detection is set off for a logical server the resource type and name can be found in the JSON of the resultant activity log for that action. Note there may be a delay in the log appearing, but be patient, as it will appear.
2. Verify property aliases exposed
More often than not the policy will implement some test against a property of a resource type. Therefore, before proceeding further it is best to confirm the property aliases that are exposed. As previously mentioned the powershell given at Azuer Policy definition structure, aliases enables this discovery as it lists the implemented resource types and available property aliases. As shown below the threat detection resource type has numerous property aliases implemented, some more than once.
If the resource type or alias is not listed then best to request it at Github, Azure Policy issues and then resort to another means such as powershell until it becomes available.
3. Look up the Azure Templates reference
Finally, look up the resource type in the Azure Template reference documentation. As shown below this details all the possible properties, including values. Here we can see that state can be one of, new, enabled or disabled.
Putting it all together.
If you are still with me, I will now work through the example that led me down this rabbit hole.
I wanted to implement an Azure Policy to test that transparent data encryption is enabled for an Azure SQL Database. Azure provides a built-in version as shown below. However I required two versions, an audit and a deny, and furthermore, I wanted to implement the rule entirely through if <condition> rather than resorting to AuditIFNotExists, as there is no Deny equivalent.
The naïve approach (which is exactly what I did) is to move all conditional logic into the if condition. And as illustrated below this fails, since the if condition operates on fields that can be of type. It does not operate on types.
Okay, fumbling along, I tried many variations, not really understanding what I was seeing. And just what is this name current all about. I eventually stopped with the non-functional version shown below and kicked off the following yammer conversation on Azure Policy
Around the same time I stumbled on this deny sql db tde disabled azure policy sample on github, and assisted by the yammer discussion, the penny finally dropped. The condition can only be against a single resource type, and [obviously] it is wrong to check for a resource type being of type database and transparent data encryption at the same time. Copying this sample, I converted the effect to audit and then assigned my Azure Policy to test. Eventually when the audit reported is available, I can see my non-compliant database. I can also see the [system generated] master database is also non-compliant. Oops.
Knowing now that name cannot be tested as transparent data encryption is a default resource type and named current, instead a test can be implemented against fullName for the existence of /master/ in the path. Here is the final policy and resulting non-compliant databases.
Even though Azure Policy is still maturing, it is very powerful. The ability to audit existing resources or prevent resources from being created is extremely useful. It does unfortunately require a good understanding of Azure resources, and probably for those immersed in ARM templates, it is all very easy. The problem is that too many pages of the Azure Documentation push the Azure Portal, and the expectation that one who has swallowed the portal can switch to low level stuff and get it, is a big one that needs a rethink.
I hope this post serves as both a useful introduction to the important elements of Azure Policy, and a means of navigating the Azure Documentation to find the resource type properties that are available to use, their values, and of course the default names these are given.