Manage Azure Policy GitHub Action
It's recommended to review:
- Azure Policy
- Writing Your First Policy in Azure with Portal
- Writing Your First Initiative in Azure with Portal
Overview
The Manage Azure Policy GitHub Action empowers you to enforce organizational standards and assess compliance at scale using Azure policies. With this action, you can seamlessly integrate policy management into your CI/CD pipelines, ensuring that your Azure resources adhere to the desired policies.
Info
This project does not have received any updates since some time, but it is still a simple option to develop your Azure Policies. As everything cannot be good to say that this deployment method has a major drawback, deletions must be done by hand :S
Key Features
-
Customizable Workflows: GitHub workflows are highly customizable. You have complete control over the sequence in which Azure policies are rolled out. This flexibility enables you to follow safe deployment practices and catch regressions or bugs well before policies are applied to critical resources.
-
Azure Login Integration: The action assumes that you've already authenticated using the Azure Login action. Make sure you've logged in using an Azure service principal with sufficient permissions to write policies on selected scopes. Refer to the full documentation of Azure Login Action for details on permissions.
-
Policy File Structure: Your policy files should be organized in a specific directory structure within your GitHub repository. Here's how it should look:
|- policies/ |- <policy1_name>/ |- policy.json |- assign.<name1>.json |- assign.<name2>.json ... |- <policy2_name>/ |- policy.json |- assign.<name1>.json |- assign.<name2>.json ...
- Each policy resides in a subfolder under the
policies/
directory. - The
policy.json
file contains the policy definition. - Assignment files (e.g.,
assign.<name1>.json
) specify how the policy is applied.
- Each policy resides in a subfolder under the
-
Inputs for the Action:
- Paths: Specify the mandatory path(s) to the directory containing your Azure policy files.
Sample Workflow
Here's an example of how you can apply policies at the Management Group scope using the Manage Azure Policy action:
name: 'Test Policy'
on:
push:
branches:
- "*"
paths:
- 'policies/**'
- 'initiatives/**'
workflow_dispatch:
jobs:
apply-azure-policy:
runs-on: ubuntu-latest
steps:
# Azure Login
- name: Login to Azure
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
allow-no-subscriptions: true
- name: Checkout
uses: actions/checkout@v2
- name: Create or Update Azure Policies
uses: azure/manage-azure-policy@v0
with:
paths: |
policies/**
initiatives/**
assignments: |
assign.*_testRG_*.json
Remember to replace the placeholder values (such as secrets.AZURE_CREDENTIALS
) with your actual configuration, you can follow this instructions to create a service principal and get the credentials: Create a service principal and get the credentials
Example of use for Policy
In this example we define all our policies and initiatives at management group level and assign to resource group, and we have a policy that requires a specific tag and its value.
You need to create a folder structure like this:
|- policies/
|- require-tag-and-its-value/
|- policy.json
|- assign.testRG_testazurepolicy.json
|- initiatives/
|- initiative1/
|- policyset.json
|- assign.testRG_testazurepolicy.json
policies
Info
- The
policy.json
file contains the policy definition, and theassign.<name>.json
file specifies how the policy is applied.
policy.json
Info
- The
id
value specifies where you are going to define the policy.
{
"id": "/providers/Microsoft.Management/managementGroups/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/policyDefinitions/requite-tag-and-its-value",
"type": "Microsoft.Authorization/policyDefinitions",
"name": "requite-tag-and-its-value",
"properties": {
"displayName": "Require a tag and its value",
"policyType": "Custom",
"mode": "Indexed",
"description": "This policy requires a specific tag and its value.",
"metadata": {
"category": "Tags"
},
"parameters": {
"tagName": {
"type": "String",
"metadata": {
"displayName": "Tag Name",
"description": "Name of the tag, such as 'environment'"
}
},
"tagValue": {
"type": "String",
"metadata": {
"displayName": "Tag Value",
"description": "Value of the tag, such as 'production'"
}
}
}
},
"policyRule": {
"if": {
"not": {
"field": "[concat('tags[', parameters('tagName'), ']')]",
"equals": "[parameters('tagValue')]"
}
},
"then": {
"effect": "deny"
}
}
}
assign.testRG_testazurepolicy.json
Info
- Change the
id
andscope
values in theassign.<name>.json
file to match your Azure subscription and resource group. - id specifies where you are going to deploy the assignment.
- id and name are related, name can not be any value, it should be the same as the last part of the id. You can generete a new GUID and use it as name with (1..24 | %{ '{0:x}' -f (Get-Random -Max 16) }) -join ''
- name and id are related.
- The
policyDefinitionId
value should match theid
value in thepolicy.json
file.
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-testazurepolicy/providers/Microsoft.Authorization/policyAssignments/599a2c3a1a3b1f8b8e547b3e",
"type": "Microsoft.Authorization/policyAssignments",
"name": "599a2c3a1a3b1f8b8e547b3e",
"properties": {
"description": "This policy audits the presence of a specific tag and its value.",
"displayName": "Require a tag and its value",
"parameters": {
"tagName": {
"value": "environment"
},
"tagValue": {
"value": "production"
}
},
"nonComplianceMessages": [
{
"message": "This resource is not compliant with the policy. Please apply the required tag and its value."
}
],
"enforcementMode": "Default",
"policyDefinitionId": "/providers/Microsoft.Management/managementGroups/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/policyDefinitions/requite-tag-and-its-value",
"scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-testazurepolicy"
}
}
initiatives
Info
- The
policyset.json
file contains the policy definition, and theassign.<name>.json
file specifies how the initiative is applied.
policyset.json
Info
- The
id
value specifies where you are going to define the initiative. - The
policyDefinitions
array contains the policy definitions that are part of the initiative. - The
parameters
object defines the parameters that can be passed to the policies within the initiative. - The
policyDefinitionId
value should match theid
value in thepolicy.json
file of the policy.
{
"id": "/providers/Microsoft.Management/managementGroups/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/policySetDefinitions/initiative1",
"type": "Microsoft.Authorization/policySetDefinitions",
"name": "initiative1",
"properties": {
"displayName": "Initiative 1",
"description": "This initiative contains a set of policies for testing.",
"metadata": {
"category": "Test"
},
"parameters": {
"tagName": {
"type": "String",
"metadata": {
"displayName": "Tag Name",
"description": "Name of the tag, such as 'environment'"
}
},
"tagValue": {
"type": "String",
"metadata": {
"displayName": "Tag Value",
"description": "Value of the tag, such as 'production'"
}
}
},
"policyDefinitions": [
{
"policyDefinitionId": "/providers/Microsoft.Management/managementGroups/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/policyDefinitions/requite-tag-and-its-value",
"parameters": {
"tagName": {
"value": "[parameters('tagName')]"
},
"tagValue": {
"value": "[parameters('tagValue')]"
},
"effect": {
"value": "Deny"
}
}
}
]
}
}
assign.testRG_testazurepolicyset.json
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-testazurepolicy/providers/Microsoft.Authorization/policyAssignments/ada0f4a34b09cf6ad704cc62",
"type": "Microsoft.Authorization/policyAssignments",
"name": "ada0f4a34b09cf6ad704cc62",
"properties": {
"description": "This initiative audits the presence of a specific tag and its value.",
"displayName": "Require a tag and its value",
"parameters": {
"tagName": {
"value": "environment"
},
"tagValue": {
"value": "production"
}
},
"nonComplianceMessages": [
{
"message": "This resource is not compliant with the policy. Please apply the required tag and its value."
}
],
"enforcementMode": "Default",
"policyDefinitionId": "/providers/Microsoft.Management/managementGroups/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/policySetDefinitions/requite-tag-and-its-value",
"scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-testazurepolicy"
}
}
Conclusion
By incorporating the Manage Azure Policy action into your GitHub workflows, you can seamlessly enforce policies, maintain compliance, and ensure the robustness of your Azure resources, although it has its drawbacks, it is one more step compared to a portal. Later we will see the deployment with a more robust tool: EPAC
Learn more about Azure Policies and explore the action on the GitHub Marketplace.