Azure, Powershell, Professional

Testing Azure Policy via PowerShell

Azure Policy is a powerful tool that can be used as effective guardrails to safeguard an environment. In addition it can be leverage to auto remediate anything required a developer may forget about. For some examples on Azure Policy check out my posts “Creating and Deploying Azure Policy via Terraform” or “Dynamically Adding Terraform Policy Assignments…Reusing Infrastructure as code“. Specifically, this post is related to “Terraform, Azure Policy, and Datas OH MY!

Problem Statement

In a nutshell this policy ensures Azure Resource Groups require a delete-by tag and this delete-by tag must be within a certain date range. The follow up to this is a PowerShell script hooked up to an Azure Automation account which will delete resource groups who have past expiration. The dilemma is how can we seed test data to validate the script when Azure Policy will deny it? We could just delete the policy assignment do our testing and re assign it; however, that is a manual process and leaves open the room for error that the policy is never assigned. So that leaves us with the problem statement: How to seed test data that violates a policy?

Requirements

To run this the following Az Modules will need to be installed:

  • Az.Resources

Approach

Breaking down this problem we can outline the steps we should take:

  • Remove the Policy Assignment
  • Create the Resources that would violate the policy
  • Re add the Policy Assignment

To do this successfully we should read in the existing policy assignment and store that information in our script so we reapply the policy with the same information that was originally available.

Store Policy Assignment Information

To store the policy assignment information, we will use the Get-AzPolicyAssignment PowerShell module:

$PolicyAssignmentName = 'sbx - Assign Required Date Diff Validation delete-by'
$PolicyAssignment = Get-AzPolicyAssignment -Name $PolicyAssignmentName
$PolicyDefinition = Get-AzPolicyDefinition -Id $PolicyAssignment.Properties.PolicyDefinitionId

The $PolicyParameterObject is a hashtable of parameters the Policy Assignment expects.

Can see we look up the Policy Assignment by name and store that as well as the Policy Definition ID as this will be used later.

Remove the Policy Assignment

Removing the Policy Assignment is quite easily actually. We just use the Remove-AzPolicyAssignment command.

Remove-AzPolicyAssignment -Name $PolicyAssignmentName 

Create the Resources that Violate the Policy

For this specific example the resources being created will be Resource Groups who have a delete-by tag value which is in the past. To accomplish this and provide a more realistic scenario the Get-Random command will be used.

$RGNamesUSE = "rg-sbx-test01", "rg-sbx-test02", "rg-sbx-test03"
$dateRan = Get-Date
For ($i = 0; $i -le ($RGNamesUSE.length - 1); $i++) {
    $rg = $RGNamesUSE[$i];
    $randomNumber = Get-Random -Maximum 10 -Minimum 1
    $deleteBy = $dateRan.AddDays(-$randomNumber).ToString('yyyy-MM-dd');
    Get-AzResourceGroup -Name $rg -ErrorVariable notPresent -ErrorAction SilentlyContinue

    if ($notPresent) {
        New-AzResourceGroup -Name $rg -Location eastus -Tag @{"delete-by" = $deleteBy}
    }
    else {
        Set-AzResourceGroup -Name $rg -Tag @{"delete-by" = $deleteBy}
    }
}

The random number will be different for each resource group being created and will be used with the .addDays() function to subtract days from the $dateRan which is the starting point.

Re Add the Policy Assignment

Lastly, we need to re add the policy assignment to ensure this doesn’t drift.

$PolicyParameterObject = @{'maxDaysFrom' = '30'; 'minDaysFrom' = '0'; 'tagName' = 'delete-by'; 'tagPolicyEffect' = 'Deny' }
New-AzPolicyAssignment -Name $PolicyAssignmentName -PolicyDefinition $PolicyDefinition -Description $PolicyAssignment.Properties.Description -DisplayName $PolicyAssignment.Properties.DisplayName -Scope $PolicyAssignment.Properties.Scope -NotScope $PolicyAssignment.Properties.NotScopes -PolicyParameterObject $PolicyParameterObject

This is being done with the New-AzPolicyAssignmnt function and passing in the assignment parameters as a hash table and the necessary information which was scraped from the original Policy Assignment that was saved off.

Conclusion

Sometimes when testing automation or the cleaning up of resources automatically it is important to create an automated way to seed test data. This will help improve consistency and help minimize the potential for human error.

Source Code

$PolicyAssignmentName = 'sbx - Assign Required Date Diff Validation delete-by'
$PolicyAssignment = Get-AzPolicyAssignment -Name $PolicyAssignmentName
$PolicyDefinition = Get-AzPolicyDefinition -Id $PolicyAssignment.Properties.PolicyDefinitionId

Remove-AzPolicyAssignment -Name $PolicyAssignmentName 

$RGNamesUSE = "rg-sbx-test01", "rg-sbx-test02", "rg-sbx-test03"
$dateRan = Get-Date
For ($i = 0; $i -le ($RGNamesUSE.length - 1); $i++) {
    $rg = $RGNamesUSE[$i];
    $randomNumber = Get-Random -Maximum 10 -Minimum 1
    $deleteBy = $dateRan.AddDays(-$randomNumber).ToString('yyyy-MM-dd');
    Get-AzResourceGroup -Name $rg -ErrorVariable notPresent -ErrorAction SilentlyContinue

    if ($notPresent) {
        New-AzResourceGroup -Name $rg -Location eastus -Tag @{"delete-by" = $deleteBy}
    }
    else {
        Set-AzResourceGroup -Name $rg -Tag @{"delete-by" = $deleteBy}
    }
}

$PolicyParameterObject = @{'maxDaysFrom' = '30'; 'minDaysFrom' = '0'; 'tagName' = 'delete-by'; 'tagPolicyEffect' = 'Deny' }
New-AzPolicyAssignment -Name $PolicyAssignmentName -PolicyDefinition $PolicyDefinition -Description $PolicyAssignment.Properties.Description -DisplayName $PolicyAssignment.Properties.DisplayName -Scope $PolicyAssignment.Properties.Scope -NotScope $PolicyAssignment.Properties.NotScopes -PolicyParameterObject $PolicyParameterObject