#AzureSpringClean 2021: Azure Policy for Managing Your Subscription

Mar 26, 2021 |

2021-03-26 #AzureSpringClean https://www.azurespringclean.com/#today

I'm honored to have the opportunity to write a quick post for the 2021 #AzureSpringClean event!  Of course, accolades for putting this all together and running the event go to Joe Carlyle and Thomas Thornton.   Feel free to check out the other posts on the schedule for #azurespringclean here.

Don't like to read? Check out the video here!

Azure Policy for Managing Your Subscription

In this post, we'll take a look at Azure policy, and how it can be used to help you manage your subscription.  Specifically, how do you keep your people from doing something you simply don't want them to do?  Perhaps you want to limit your web apps so that someone won't spin up a premium web application, or a very expensive database instance.  Maybe you need to block resources from being deployed outside of your country.  All of this, and more, can be accomplished using policies on your Azure subscription.

Hopefully you had a chance to check out the post my friend and colleague Dwayne Natwick did regarding Azure Policy (Azure Policy for Security and Governance).  With that, you should have gotten a great baseline of what you can do with Azure Policy regarding governance and policy on your subscription.  

Additionally, I hope you had a chance to check out Sam Cogan's post on using policy with Azure Kubernetes (Replacing Kubernetes Pod Security Policies).  In that post, you can learn about how to work with policies and initiatives for managing your Kubernetes implementations.  

This post will be somewhat similar to both of those posts in that we're talking about applying policies, but in this post you will create custom policies for your subscription, instead of using built-in policies.

First, just in case you are fairly new to policy, let's learn about using a built-in policy on our subscription.

Creating your first policy

Back to the problem at hand.  You need to ensure that automated deployments and team members don't create resources that exist outside of the limits you want to set for your subscription.  This can be accomplished with Azure policies.

Of course, you should be the owner of your subscription.  For everyone else, however you want to give them limited ability.  To get started, let's create a policy that you would learn about if you were studying for the AZ-900 exam.

In this first policy, we'll just create a block on any resources being created outside of a region of your choice.  Since I'm in the Central US, I'll use that region.  Feel free to use the region that is closest to you for your allowed region.

Create a policy to restrict the regions for resource deployment

Navigate to your subscription, then use search to find Policy. Once you are on policy, select Assignments on the left-hand menu. In the assignments blade, select Assign Policy

Once you are on the policy assignment, ensure you are on the subscription, then you can choose any exclusions you might want to put in place.  This could be useful to allow a specific resource group to bypass the policy.

Next, you need to determine the policy definition.  Here you can choose the policy definition to apply from the built-in policies, or you can create your own custom policy.  For this policy, we'll use a built-in policy called "Allowed Locations":  

Now enter a description that makes sense, such as "the allowed locations for the subscription."  Leave the enforcement enabled, and then select "Next."

Assign the Policy

On the Parameters tab, select the region (or regions) you want to allow for resource deployment.  Of course, if you were looking to have a redundant region for failover, you would want to also allow that region here.

Then hit the Next button.  Note that on the next page you could create a Managed Identity if you were issuing a policy that would need to deploy or modify resources.  This one does not need a Managed Identity.  Hit the Next button.  

On the next page, you can enter a message to display when the policy prevents something from happening.  In this case you might enter a message such as "Resources can only be deployed in the following region(s): Central US," then hit the Next button, then create the policy with the Create button.

Attempt to create a resource in a disallowed region

Once the policy is created, wait about 10 minutes to ensure the policy is applied, then try to create a resource such as a storage account or a network interface in any region other than the allowed region(s) in your policy.

And when you try to create the resource, you get a validation error which shows the friendly message you created:

With this in mind, you've now learned the first way you can use policy to control your subscription: using an appropriate built-in policy and applying it with the parameters you desire.  

Resources in Violation, and exceptions to violations

As it happens, I currently had a resource that was deployed in my subscription in a disallowed region prior to the policy creation, so when I navigate back, I can see that I have a resource in violation of the applied policy:

This, of course, is super useful when you have a policy and you want to find any resources that are in violation and remediate the issues.  This is most useful for things like security policies or governance policies.  

When I drill in further, I can see the policy that is out of compliance and figure out what I want to do with it from there, such as move to another region.  Additionally, I can create an exemption for this resource if that makes sense:

If you have other resources you could also create exceptions as they make sense.

Furthermore, if you click on View Definition, you can see the JSON that is defining this definition for the subscription.

Reviewing the JSON can be very useful to see the format and various sections of the policy definition, especially if you decide to write your own custom policies.

What is most important is the syntax around the "policyRule".  In this case, the policy rule looks as follows:

Note the key ending in the policy: the effect is to deny when the rule is not matched.  This is how you will write policies that block specific resources or SKUS from being allowed for provisioning to your subscription.

Feel free to use the "Delete Assignment" button to remove the allowed locations policy from your subscription.

Create custom policies that prevent resources by type

With a basic understanding of how policies can lock down the subscription, now let's get a bit bolder.  In this next policy, let's create one that blocks everything except Azure Functions, SQL Servers, Storage Accounts, Application Insights, Log Analytics Workspaces, and App Services from being deployed in our subscriptions. 

In order to do this, we need to first understand what resources these are.  A little trick I like to use is that whenever I need to figure out the resource type that I want to create policy against, I just deploy a resource of the type, and then look at the ARM template to get the information.  For example, a function app actually shows up as:

"type": "Microsoft.Web/sites",

There are a number of resource types available, and you can find a full list of them here.  As you can see, there are far too many to list, which also makes it difficult to sometimes find the right provider to allow on your subscription.  This is why I like to use a pre-deployed instance to quickly find the right provider(s).

With the right provider(s), the policy can be created.

Create a new custom policy to allow Azure Functions and App Services

To get started, let's just begin with one of the built-in policies.  Following the same procedure as before, create a new policy that uses a built-in definition.  This time, use the built-in policy for Allowed Resources.

Note that there is a limitation on this policy that states in order to use this across all resources the mode needs to be switched to "All."

Also, in addition to Microsoft.Web/* for the functions and app services, SQL Server has the provider type Microsoft.Sql/*, Microsoft.Storage/* for storage, Microsoft.Insights/* and Microsoft.OperationalInsights/* for application insights and log analytics workspaces.  Additionally, in order to be able to rewrite and add new policies, Microsoft.Authorization/* is added to the definition. 

Note that if you don't include Microsoft/Authorization/*, you will need to un-assign the policy in order to make any modifications to policy (which is extremely useful if you are really locking down a subscription - because then only the people at the highest level who can modify policy assignments can make any sort of policy change).

You can see that there are too many resources to sort through and a lot of them might not be what you are looking for.  Let's abandon the pre-built and build our own.  Hit cancel so that we can start over and  create a new custom policy.

Before diving into a custom policy, read this...

Before diving into writing policy, it's important to understand the syntax and expectations of what is available to use the to correctly build policy with JSON files.  This is a good place to read about the way to format the JSON files for creating custom Azure policies. Of particular interest is the section on the available logical operators.  From the link above:

 Then combine this information  with the next piece of information, also from the previous link above in the msdocs:

With all of this in mind, we can infer that creating a custom policy allows us to follow a syntax where we can do an if condition where we use a not and an anyof operator to include good resources, and then use the else (then) condition to deny everything else.  Also note that the like and notlike conditions allow for using a wildcard.  Finally, if we look at this sample policy to Enforce Virtual Network Filtering on Cosmos DB accounts, we can see a really great default template, and we can just modify it for our purposes of selecting our targets and excluding them with the "not" operator, and then just denying everything else.

Create our custom definition

On the Policy blade, select Definitions.  Then use the button to create a new policy definition.

Note that you could import policy definitions from GitHub, or you can use an existing policy as a base.

For the definition location, select the correct subscription.  Name the policy "Our Allowed Resources", and give it a sensible description.

Select the "Create new" for Category and give the category a name like Custom Policies.

Navigate to This Azure Policy, then copy and paste the JSON into the policy rule.

Save the rule and wait a few minutes for it to be created.  After a couple of minutes, go back to assignments and then Assign the policy.  The policy should be available under the "Custom" type.

There are no parameters so you can just review and create, or you can add a custom message as in the first policy.  

After you have created the policy, wait about 10 minutes and then try to deploy something that was not listed, such as a Virtual Network or a Logic App.  You should receive a validation error:

When you get an error, you can use the Raw Error tab to show more detail about the policy and what caused the issue.

Of course one final thing you should do is deploy a function app and/or an app service, and a SQL server, and you should ensure that you can also create with application insights to ensure that your policy allows the resources you need.

Note that as your solution deploys, you can see the specific resource providers that are needed (so if it fails, note that one that fails and add it to your policy):

The policy as created is allowing function apps to be created as expected:

Create custom policies to prevent resources from being provisioned with a disallowed SKU

To complete this exercise in learning about using policy to limit resource deployment in a subscription, we'll create a new policy that disallows any server farms not in "F1 - Free", "D1 - Shared", "S1 - Standard", or "Y1 - Consumption [for function apps]".

Begin by creating a new custom policy following the same process that you did in the previous example.  This time, name the policy "Our allowed Server Farm SKUs" and give it a sensible description.  Use this azure policy definition to create the policy.  [NOTE: This image is in the edit policy view after I'd already assigned it, so the custom policies category is available and the SKUs are split on lines, which is not exactly how yours will look when you are first assigning]

Once the policy is successfully created, assign it so that the SKU limitations will be put in place.  Use a non-compliance message like "The selected server farm SKU is not allowed on this azure subscription, Try using F1 - D1 - S1 - or Y1"

Once the policy is assigned, you should see both in your list of assigned policies

Once again, wait about 10 minutes, and then ensure that you cannot deploy an app service plan that is not one of the four types listed in the policy.  Ensure you can still deploy an app service plan in the F1 tier and also a consumption plan for a function app in the consumption tier.

Premium is disallowed by policy

Free is allowed as expected

Additionally, I can still do function apps on the consumption plan as expected:

With all of this in place, you've now learned how to easily start using policy to modify the allowed resources and SKUs for resources on your azure subscription using custom policies.

Let me know what you think of this content, and if you like it, please feel free to share it!


Additional Resources:

MSDocs: Resource Providers

MSDocs: Overview of Azure Policy

MSDocs: Create And Manage Policy Tutorial

MSDocs: Policy Definition Structure

MSDocs: Initiative Definition Structure

MSDocs: Create a policy assignment with .Net Core

MSLearn: Build a cloud governance strategy on Azure

MSLearn: Control and organize Azure resources with Azure Resource Manager

MGS: The video that walks through this post


Categories: : Azure, Policy, Administration