How to deploy Azure policy: The DevOps way

In this first part of this series of blogs, you will delve into deploying Azure Policy the “DevOps way”. You’ll start by exploring the Enterprise Azure Policy as Code (also known as EPAC) tool and set up the project structure for future growth. Later, you’ll create an Azure Policy that follows the naming convention on Resource Groups. The result can then be exported to your project and managed by EPAC. The last section will cover basic validation of the files produced by EPAC.

Hang on tight, you’re going to cover a lot of ground and see a ton of coding examples. Let’s get it started.

Azure Policy, a feature in Azure that enforces organizational standards and assesses compliance. Many large organizations implement Azure Policy from top-level management groups.

Every large enterprise has an organizational chart. Wether they call it a division, domain, department, or anything else on the matter, it will probably reflect back in the management groups created in Azure. For example, take a look at the following image when management groups became generally available:

Figure 1: Hierarchy example using Management Groups
Figure 1: Hierarchy example using Management Groups

Rabobank follows the same principle, but of course with a different organizational hierarchy in Azure. Each domain gets one or two subscriptions to deploy its Azure resources. Subscriptions are provided by a large team of Platform Engineers, which also enforce the Azure Policies from the top-level Management Groups.

The question then becomes, can teams within the domain still leverage Azure Policy to enforce their domain standards? Glad you asked! Azure Policy is not limited to Management Groups. You can scope Azure Policy on Subscription-level.

Getting started

Before diving into the nitty-gritty things of Azure Policy, you need to make sure you have the following in-place:

Enterprise Azure Policy as Code

You might already have seen the term being flipped, Enterprise (Azure) Policy as Code (also known as EPAC). Policy as Code is used to define and manage your Azure Policies as Code. Azure Policies are written in JSON format and can be extracted also in such way. Still, you need a tool that can integrate CI/CD capabilities to deploy your Policies, Initiatives (or Policy Sets), Assignments (Policy or Role), and Exemptions. That’s where Microsoft has developed in partnership with S&C4CI, a PowerShell module called EnterprisePolicyAsCode.

To install the PowerShell module, use the following cmdlet:

CSHARP

If you're using still using PowerShellGet v2, use the Install-Module cmdlet

Following the installation of the PowerShell module, set up the basic project layout structure that will hold your policy objects.

CSHARP

When it's finished, some subfolders were created, including a configuration file.

Figure 2: Project structure layout including EPAC subfolders
Figure 2: Project structure layout including EPAC subfolders

The subfolder structure speaks quite for itself. The configuration file that has been created needs to be modified according to your environment. Replace the sections in the example below.

CSHARP

It’s a fair question to ask why not store all policies objects in the src folder, especially if you’re aware of how the public azure-policy repository looks like? Both approaches have their pros and limitations. When managing all your policy objects in big chunks, it’s difficult to integrate it into a DevOps pipeline. It also doesn’t allow you to test each Policy Set definition separately, as you’ll learn later.

You now have set up your project structure. Now you need a policy to work with. Let’s start by creating your own naming convention policy in the sandbox environment.

Create naming convention policy for Azure resources

Microsoft has already provided a ton of details on naming recommendations. Unthinkingly you can adopt these naming recommendations, but you can also throw in your own sauce over it. Take for example the naming pattern for a Resource Group:

rg-<department>-<application>-<environment>

This will end up in something like:

  • rg-marketing-application-dev
  • rg-marketing-application-prd

Knowing this information at hand allows you to create the required policy for it.

  1. Open the Azure Portal
  2. Search for Policy in the search box
  3. Click on Definitions in the Authoring section -> + Policy definition
  4. Select Subscription in Definition location
  5. Create a meaningful name, in this example [Naming-Convension-001] Resource Group is used
  6. Add the description and use the existing category Naming
  7. In the editor field, add the following content
CSHARP
Figure 3: Create Policy Definition in Azure Portal
Figure 3: Create Policy Definition in Azure Portal
Figure 4: Create Policy Set Definition (also known as Initiative)
Figure 4: Create Policy Set Definition (also known as Initiative)

8. Press Save to save the Policy Definition in Azure

You can now create an initiative definition that holds the collection of Policy Definitions. For the sake of the series, you’ll be working with only one Policy Definition. If you already have many Definitions that are tailored around in achieving the same goal, in this case naming conventions, you can add them to the Initiative definition.

  1. Back in the Authoring > Definitions > Click Initiative definition
  2. Select the same Subscription in previous step
  3. Add the following content
Figure 5: Create Policy Set Definition (also known as Initiative)
Figure 5: Create Policy Set Definition (also known as Initiative)

4. In the Policies section, make sure you add the Policy Definition

5. Map the initiative parameter in Policy parameters

Figure 6: Create initiative parameter
Figure 6: Create initiative parameter

6. Map the initiative parameter in Policy parameters

Figure 7: Map initiative parameter to Policy parameter
Figure 7: Map initiative parameter to Policy parameter

When you map parameters in your Initiative definition, it provides you with the ability to set different values across your subscriptions. For example, on your development subscription, it might not be needed to follow a strict naming convention, whereas for production it does.

You can now create and assign the Initiative definition to apply your Azure Policy.

Managing Azure Policy through EPAC

It’s now time to extract the policy and utilize EPAC to handle Azure Policy deployments through your environments. To extract the policy that you just created, use the following cmdlet.

CSHARP

This will extract the policy that was created through the Portal, and output everything in JSON format.

Figure 8: Map initiative parameter to Policy parameter
Figure 8: Map initiative parameter to Policy parameter

From here onwards, you can copy the output files into the appropriate folders and let EPAC build a plan for policy deployment. This plan can be deployed for each environment it gets created from. That’s where the pacEnvironment value comes into play in the global-settings.jsonc file.

CSHARP

To test out the process, remove the Policy Definition, Initiative Definition, and Initiative Assignment.

CSHARP

Give it a minute to finish cleaning up. If everything has been removed, run the following to generate a plan for deployment.

CSHARP

As you’ll notice in the output, EPAC has detected 3 new changes in your environment.

Figure 9: New changes detected by EPAC
Figure 9: New changes detected by EPAC

Fire up the Deploy-PolicyPlan cmdlet to let EPAC manage your policy objects.

CSHARP
Figure 10: Deploy changes using EPAC
Figure 10: Deploy changes using EPAC

If you check in the Azure Portal, the policy objects have been deployed by EPAC. Fantastic!

Basic validation testing on policy objects

Before closing the first part of this series, it’s important to implement some basic validation testing on policy objects. As you’ve learned to extract existing policies from Azure, it’s also possible to manually create them. EPAC supports a $schema tag on JSON files introduced in your repository.

CSHARP

This allows the flexibility to develop either through your favorite editor, or extract existing policies created through the Azure Portal. Nevertheless, the method you choose, validating the JSON files that have been created, including their structure, is useful. It’s useful to validate the JSON files that you create and their structure. To do so, you can leverage Pester, the testing framework for PowerShell.

  1. Open the PowerShell terminal
  2. Run the following cmdlets in sequence
CSHARP

3. Open the FileContent.Tests.ps1 file and add the content below to test if the JSON is valid

CSHARP

4. Open PolicyAssignmentStructure.tests.ps1 and add the following to check if the scope count has been set

CSHARP

5. Open _PolicyDefinitionStructure.tests.ps1 and add the following to check if the property elements are correctly set

CSHARP

6. Lastly, do the same for PolicySetDefinitionStructure.tests.ps1

CSHARP

To execute the unit tests, you would run the Invoke-Pester cmdlet. As you’re building the project to contain multiple resource types, it would be useful to test each type separately. That’s why in the above snippets, the -ResourceType parameter can be passed in.

7. Open the Invoke-PesterWrapper.ps1 and add the content shown below to wrap Pester around configuration that can be parsed when calling the function.

CSHARP

To invoke the tests, you can dot-source the script. When it’s loaded, call Invoke-PesterWrapper -ResourceType Naming from the root of your repository.

Figure 11: Run basic validation test against JSON files
Figure 11: Run basic validation test against JSON files

Conclusion

You’ve now managed to set up the basic project structure for your Azure Policies. You’ve had your first glimpse at Enterprise Azure Policy as Code and used it to extract policy objects. These policy objects can now be managed by EPAC. EPAC creates a plan and deploys it throughout your environment. As everything is driven by cmdlets and scripts, you will be able to integrate it in a CICD system later. In the last section, you were introduced to the first basic validation on the policy objects by using Pester.

That’s it for the first part. There’s more to come in the next part!

References

About the author

  • Gijs Reijn
  • Gijs ReijnCloud Engineer
Gijs Reijn is a senior DevOps Engineer at Tribe Global Data Analytics Platform (GDAP). He primarily focusses on Azure DevOps, Azure and loves to automate processes including standardization around it. Outside working hours, he can be found in the early morning working out in the gym nearly every day, writes his own blog to share knowledge with the community and reading upon new ideas. He is also a writer on Medium.