Loading...

Managing Azure Policies through Python SDK

Managing Azure Policies through Python SDK

Managing Azure Policies through Python SDK

 

Azure Policy helps to enforce organizational standards and to assess compliance at-scale. It also helps to bring your resources to compliance through bulk remediation for existing resources and automatic remediation for added resources.

 

Common use cases for Azure Policy include implementing governance for resource consistency, regulatory compliance, security, cost, and management. Policy definitions for these common use cases are already available in your Azure environment as built-ins to help you get started.

Specifically, some useful governance actions you can enforce with Azure Policy include:

  • Ensuring your team deploys Azure resources only to allowed regions.
  • Enforcing the consistent application of taxonomic tags

Requiring resources to send diagnostic logs to a Log Analytics workspace

 

References: https://learn.microsoft.com/en-us/azure/governance/policy/overview

                        https://learn.microsoft.com/en-us/azure/governance/policy/policy-glossary

https://learn.microsoft.com/en-us/azure/developer/python/sdk/azure-sdk-overview

 

We can manage Azure policies through portal, PowerShell, CLI, REST API, Bicep, ARM Templates, Terraform and SDKs.

 

This blog will cover the policy management through Python SDK and we can use any IDE that supports Python SDK for Azure. We are using Visual Studio Code here. (https://azure.microsoft.com/en-in/products/visual-studio-code)

 

Azure Python SDK Authentication Reference : https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication-overview

 

 

Import Libraries

 

 

 

 

import os from azure.identity import ClientSecretCredential from azure.identity import AzureCliCredential from azure.mgmt.authorization import AuthorizationManagementClient from azure.mgmt.resource import PolicyClient, ResourceManagementClient from azure.mgmt.resource.subscriptions import SubscriptionClient from azure.mgmt.policyinsights import PolicyInsightsClient

 

 

 

 

Define and Assign Variables

 

 

 

 

subscription_id = "exyx-exyx4e-4xyx9-axyz9c-45be63c6a8ad" # your subscription ID tenant_id = "xyzxyz-abc-cd-avc-48ebcd07d17c" # Your tenant ID client_id = "123abc-cdd-4f09-ad9f-abcdef" # Your Client ID client_secret = "wiufhuiw24874946497fff" # Your Client Secret POLICY_NAME = "KeyVaultDIAGDINEpolicy" SUBSCRIPTION_ID = "exyx-exyx4e-4xyx9-axyz9c-45be63c6a8ad" GROUP_NAME = "resourceGroupName" MANAGEMENTGROUP_ID= "abcd-123-4e7b-a446-233cvd" POLICY_ASSIGNMENT_NAME = "KVDiagDINEpolicy"

 

 

 

 

Creation of objects

 

 

 

resource_client = ResourceManagementClient( credential=ClientSecretCredential(tenant_id=tenant_id, client_id=client_id, client_secret=client_secret), subscription_id=subscription_id ) policyinsights_client = PolicyInsightsClient( credential=ClientSecretCredential(tenant_id=tenant_id, client_id=client_id, client_secret=client_secret), subscription_id=subscription_id ) policy_client = PolicyClient( credential=ClientSecretCredential(tenant_id=tenant_id, client_id=client_id, client_secret=client_secret), subscription_id=subscription_id )

 

 

 

Creation of Policy Definition at the Subcription Scope 

 

 

 

definitionatsubscription = policy_client.policy_definitions.create_or_update(policy_definition_name=POLICY_NAME, parameters= { "displayName": "KVDiag", "policyType": "Custom", "mode": "Indexed", "parameters": { "effect": { "type": "String", "metadata": { "displayName": "Effect", "description": "Enable or disable the execution of the policy" }, "allowedValues": [ "DeployIfNotExists", "Disabled" ], "defaultValue": "DeployIfNotExists" }, "profileName": { "type": "String", "metadata": { "displayName": "Profile name", "description": "The diagnostic settings profile name" } }, "logAnalytics": { "type": "String", "metadata": { "displayName": "Log Analytics workspace", "description": "Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.", "strongType": "omsWorkspace", "assignPermissions": "true" } }, "azureRegions": { "type": "Array", "metadata": { "displayName": "Allowed Locations", "description": "The list of locations that can be specified when deploying resources", "strongType": "location" } }, "metricsEnabled": { "type": "String", "metadata": { "displayName": "Enable metrics", "description": "Whether to enable metrics stream to the Log Analytics workspace - True or False" }, "allowedValues": [ "True", "False" ], "defaultValue": "True" }, "logsEnabled": { "type": "String", "metadata": { "displayName": "Enable logs", "description": "Whether to enable logs stream to the Log Analytics workspace - True or False" }, "allowedValues": [ "True", "False" ], "defaultValue": "True" } }, "policyRule": { "if": { "allOf": [ { "field": "type", "equals": "Microsoft.KeyVault/vaults" }, { "field": "location", "in": "[parameters('azureRegions')]" } ] }, "then": { "effect": "[parameters('effect')]", "details": { "type": "Microsoft.Insights/diagnosticSettings", "existenceCondition": { "allOf": [ { "field": "Microsoft.Insights/diagnosticSettings/logs.enabled", "equals": "[parameters('logsEnabled')]" }, { "field": "Microsoft.Insights/diagnosticSettings/metrics.enabled", "equals": "[parameters('metricsEnabled')]" }, { "field": "Microsoft.Insights/diagnosticSettings/workspaceId", "equals": "[parameters('logAnalytics')]" } ] }, "roleDefinitionIds": [ "/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa", "/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293" ], "deployment": { "properties": { "mode": "incremental", "template": { "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "resourceName": { "type": "string" }, "location": { "type": "string" }, "logAnalytics": { "type": "string" }, "metricsEnabled": { "type": "string" }, "logsEnabled": { "type": "string" }, "profileName": { "type": "string" } }, "variables": {}, "resources": [ { "type": "Microsoft.KeyVault/vaults/providers/diagnosticSettings", "apiVersion": "2017-05-01-preview", "name": "[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]", "location": "[parameters('location')]", "dependsOn": [], "properties": { "workspaceId": "[parameters('logAnalytics')]", "metrics": [ { "category": "AllMetrics", "enabled": "[parameters('metricsEnabled')]", "retentionPolicy": { "enabled": "false", "days": 0 } } ], "logs": [ { "category": "AuditEvent", "enabled": "[parameters('logsEnabled')]" } ] } } ], "outputs": {} }, "parameters": { "location": { "value": "[field('location')]" }, "resourceName": { "value": "[field('name')]" }, "logAnalytics": { "value": "[parameters('logAnalytics')]" }, "metricsEnabled": { "value": "[parameters('metricsEnabled')]" }, "logsEnabled": { "value": "[parameters('logsEnabled')]" }, "profileName": { "value": "[parameters('profileName')]" } } } } } } }}) print("Created policy definition ID : {}".format(definitionatsubscription.id)) print("Created policy definition Name : {} \n".format(definitionatsubscription.name)) print (" ********* ******** ******** ********** ******** ******* \n")

 

 

 

Creation of Policy Definition at Management Group Scope 

 

 

 

definitionatmanagementgroup = policy_client.policy_definitions.create_or_update_at_management_group(policy_definition_name=POLICY_NAME, parameters= { "displayName": "KVDiag", "policyType": "Custom", "mode": "Indexed", "parameters": { "effect": { "type": "String", "metadata": { "displayName": "Effect", "description": "Enable or disable the execution of the policy" }, "allowedValues": [ "DeployIfNotExists", "Disabled" ], "defaultValue": "DeployIfNotExists" }, "profileName": { "type": "String", "metadata": { "displayName": "Profile name", "description": "The diagnostic settings profile name" } }, "logAnalytics": { "type": "String", "metadata": { "displayName": "Log Analytics workspace", "description": "Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.", "strongType": "omsWorkspace", "assignPermissions": "true" } }, "azureRegions": { "type": "Array", "metadata": { "displayName": "Allowed Locations", "description": "The list of locations that can be specified when deploying resources", "strongType": "location" } }, "metricsEnabled": { "type": "String", "metadata": { "displayName": "Enable metrics", "description": "Whether to enable metrics stream to the Log Analytics workspace - True or False" }, "allowedValues": [ "True", "False" ], "defaultValue": "True" }, "logsEnabled": { "type": "String", "metadata": { "displayName": "Enable logs", "description": "Whether to enable logs stream to the Log Analytics workspace - True or False" }, "allowedValues": [ "True", "False" ], "defaultValue": "True" } }, "policyRule": { "if": { "allOf": [ { "field": "type", "equals": "Microsoft.KeyVault/vaults" }, { "field": "location", "in": "[parameters('azureRegions')]" } ] }, "then": { "effect": "[parameters('effect')]", "details": { "type": "Microsoft.Insights/diagnosticSettings", "existenceCondition": { "allOf": [ { "field": "Microsoft.Insights/diagnosticSettings/logs.enabled", "equals": "[parameters('logsEnabled')]" }, { "field": "Microsoft.Insights/diagnosticSettings/metrics.enabled", "equals": "[parameters('metricsEnabled')]" }, { "field": "Microsoft.Insights/diagnosticSettings/workspaceId", "equals": "[parameters('logAnalytics')]" } ] }, "roleDefinitionIds": [ "/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa", "/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293" ], "deployment": { "properties": { "mode": "incremental", "template": { "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "resourceName": { "type": "string" }, "location": { "type": "string" }, "logAnalytics": { "type": "string" }, "metricsEnabled": { "type": "string" }, "logsEnabled": { "type": "string" }, "profileName": { "type": "string" } }, "variables": {}, "resources": [ { "type": "Microsoft.KeyVault/vaults/providers/diagnosticSettings", "apiVersion": "2017-05-01-preview", "name": "[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]", "location": "[parameters('location')]", "dependsOn": [], "properties": { "workspaceId": "[parameters('logAnalytics')]", "metrics": [ { "category": "AllMetrics", "enabled": "[parameters('metricsEnabled')]", "retentionPolicy": { "enabled": "false", "days": 0 } } ], "logs": [ { "category": "AuditEvent", "enabled": "[parameters('logsEnabled')]" } ] } } ], "outputs": {} }, "parameters": { "location": { "value": "[field('location')]" }, "resourceName": { "value": "[field('name')]" }, "logAnalytics": { "value": "[parameters('logAnalytics')]" }, "metricsEnabled": { "value": "[parameters('metricsEnabled')]" }, "logsEnabled": { "value": "[parameters('logsEnabled')]" }, "profileName": { "value": "[parameters('profileName')]" } } } } } } }},management_group_id= 'abcd-233df-4e7b-a446-2333xcvc' ) print("Created policy definition ID : {}".format(definitionatmanagementgroup.id)) print("Created policy definition Name : {} \n".format(definitionatmanagementgroup.name)) print (" ********* ******** ******** ********** ******** ******* \n")

 

 

 

Defining Scopes for Policy Assignment 

 

 

 

scopeRG = '/subscriptions/{}/resourceGroups/{}'.format( SUBSCRIPTION_ID, GROUP_NAME ) scopeSubscription = '/subscriptions/{}'.format( SUBSCRIPTION_ID ) scopeMG = '/providers/Microsoft.Management/managementGroups/{}'.format( MANAGEMENTGROUP_ID )

 

 

 

Creating Policy Assignments at different Scope - Resource Group, Subscription and Management Group

 

 

 

assignmentatRG = policy_client.policy_assignments.create( scopeRG, POLICY_ASSIGNMENT_NAME + " at RG", { 'policy_definition_id': definitionatmanagementgroup.id, "identity": {"type": "SystemAssigned"}, "location" :"eastus", 'parameters' : { "profileName": { "value": "KV_DIAG_Settings1" }, "logAnalytics": { "value": "/subscriptions/e818bd2d-e44e-4a99-a89c-45be63c6a8ad/resourcegroups/psdonotdeletessimportant/providers/microsoft.operationalinsights/workspaces/lnos-demo-1-log-sb" }, "azureRegions": { "value": ["westus"] } }, } ) print("Createed policy assignment: {}".format(assignmentatRG.id)) print("Created policy assignment: {}\n".format(assignmentatRG.name)) print (" ********* ******** ******** ********** ******** ******* \n") assignmentatsubscription = policy_client.policy_assignments.create( scopeSubscription, POLICY_ASSIGNMENT_NAME + "at Subscription", { 'policy_definition_id': definitionatsubscription.id, "identity": {"type": "SystemAssigned"}, "location" :"eastus", 'parameters' : { "profileName": { "value": "KV_DIAG_Settings2" }, "logAnalytics": { "value": "/subscriptions/e818bd2d-e44e-4a99-a89c-45be63c6a8ad/resourcegroups/psdonotdeletessimportant/providers/microsoft.operationalinsights/workspaces/lnos-demo-1-log-sb" }, "azureRegions": { "value": ["westus"] } } } ) print("Created policy assignment: {}".format(assignmentatsubscription.id)) print("Created policy assignment: {} \n".format(assignmentatsubscription.name)) print (" ********* ******** ******** ********** ******** ******* \n") assignmentatmanagementgroup = policy_client.policy_assignments.create( scopeMG, POLICY_ASSIGNMENT_NAME + "at MG", { 'policy_definition_id': definitionatmanagementgroup.id, "identity": {"type": "SystemAssigned"}, "location" :"eastus", 'parameters' : { "profileName": { "value": "KV_DIAG_Settings3" }, "logAnalytics": { "value": "/subscriptions/e818bd2d-e44e-4a99-a89c-45be63c6a8ad/resourcegroups/psdonotdeletessimportant/providers/microsoft.operationalinsights/workspaces/lnos-demo-1-log-sb" }, "azureRegions": { "value": ["westus"] } } } ) print("Created policy assignment: {}".format(assignmentatmanagementgroup.id)) print("Created policy assignment: {}\n".format(assignmentatmanagementgroup.name)) print (" ********* ******** ******** ********** ******** ******* \n")

 

 

Trigger manual policy evaluation and get the resource compliance/non-compliance count : 

Refernce Article : https://learn.microsoft.com/en-us/powershell/module/az.policyinsights/start-azpolicycompliancescan?view=azps-10.4.1

 

 

triggerevaluation = policyinsights_client.policy_states.begin_trigger_subscription_evaluation( subscription_id='abc1233-e44e-4a99-a89c-123dfg') print("Manual policy evaluation triggered :\n{}".format(triggerevaluation.status)) policyevaluationresult = policyinsights_client.policy_states.list_query_results_for_subscription_level_policy_assignment( subscription_id='abc123-e44e-4a99-a89c-12333df', policy_states_resource="latest", policy_assignment_name= '621dc2655dd74ed68a37286d' ) for item in policyevaluationresult: print(' Resource ID : '+ item.resource_id) print(' Policy Assignment ID : '+item.policy_assignment_id) print(' Policy Assignment Scope : '+item.policy_assignment_scope) print(' Compliance State : '+item.compliance_state) print('\n') if item.compliance_state == 'Compliant': Compliant= int(Compliant +1) elif item.compliance_state == 'NonCompliant': NonCompliant = int(NonCompliant +1) else: 1==1 print('Number of Resources') print('Compliant :' + str(Compliant)) print('NonCompliant :' + str(NonCompliant))

 

 

Creation of Remediation Task at different Scopes:

 

 

remediation = policyinsights_client.remediations.create_or_update_at_management_group("1233-dfdf-4e7b-a446-223233", "mymgremediation" , { "policy_assignment_id": "/providers/microsoft.management/managementgroups/6cf4d5f3-dfdf-4e7b-a446-48ebcd07d17c/providers/microsoft.authorization/policyassignments/logagents", ## "policy_definition_reference_id" : "4037797753452518688" ## (optional) Needed when we need to remediate the non-compliant resources of policy initiative assignment }) print("Create remediation:\n{}".format(remediation)) remediationRG = policyinsights_client.remediations.create_or_update_at_resource_group( "myremediationatRG", "aro-rererer", { "policy_assignment_id": "/providers/microsoft.management/managementgroups/12345-dfdf-4e7b-a446-48ebcd07d17c/providers/microsoft.authorization/policyassignments/logagents", "resource_discovery_mode" : 'ExistingNonCompliant' ## ReEvaluateCompliance - Re-evaluate the compliance state of resources and then remediate the resources found to be non-compliant. ##ExistingNonCompliant - Remediate resources that are already known to be non-compliant. }) print("Create remediation:\n{}".format(remediationRG)) remediationsubscription = policyinsights_client.remediations.create_or_update_at_subscription( "mymgremediationatsubsc" , { "policy_assignment_id": "/providers/microsoft.management/managementgroups/12333-dfdf-4e7b-a446-48ebcd07d17c/providers/microsoft.authorization/policyassignments/logagents", "resource_discovery_mode" : 'ReEvaluateCompliance' ## ReEvaluateCompliance - Re-evaluate the compliance state of resources and then remediate the resources found to be non-compliant. ##ExistingNonCompliant - Remediate resources that are already known to be non-compliant. ## "policy_definition_reference_id" : "4037797753452518688" }) print("Create remediation:\n{}".format(remediationsubscription)) Note - resource_discovery_mode is only for the policy assignments at the subscription and the resource group scope.

 

 

 

Published on:

Learn more
Azure PaaS Blog articles
Azure PaaS Blog articles

Azure PaaS Blog articles

Share post:

Related posts

Azure Storage - TLS 1.0 and 1.1 retirement

Overview TLS 1.0 and 1.1 retirement on Azure Storage was previously announced for Nov 1st, 2024, and it was postponed recently to 1 year later...

1 year ago

Efficient Management of Append and Page Blobs Using Azure Storage Actions

  Overview In Azure Storage, Blob Lifecycle Management (BLM) allows you to automate the management of your data based on rules defined by...

1 year ago

[Azure AI Search] Internal Server Error when creating CMK encrypted objects

Scenario Customers follow the Microsoft doc to create CMK encrypted objects (data source, index etc.), but get the 500 Internal Serv...

1 year ago

Optimizing Azure Table Storage: Automated Data Cleanup using a PowerShell script with Azure Automate

Scenario This blog’s aim is to manage Table Storage data efficiently. Imagine you have a large Azure Table Storage that accumulates logs from ...

1 year ago

Optimizing Azure Table Storage: Automated Data Clean-up using a PowerShell script with Azure Automat

Scenario This blog’s aim is to manage Table Storage data efficiently. Imagine you have a large Azure Table Storage that accumulates logs from ...

1 year ago

Restoring Soft-Deleted Blobs with multithreading in Azure Storage Using C#

Blob soft delete is an essential feature that safeguards your data against accidental deletions or overwrites. By retaining deleted data for a...

1 year ago

Performing simple Azure Table Storage REST API operations using curl command.

The blog provides guidance to perform simple Table Storage REST API operations such as Create table, Delete Table, Insert entity, Delete entit...

1 year ago

Bulk delete all the old jobs from the batch account

Deleting a Job also deletes all Tasks that are part of that Job, and all Job statistics. This also overrides the retention period for Task dat...

1 year ago

Utilizing Azure Storage and Runbooks for scheduled automated backups of Azure SQL Databases

In this article, we are going to provide detailed steps to create a scheduled Azure SQL Database backup to storage account using automation. T...

2 years ago

[Azure Service Bus] JMS messages getting dead-lettered

The article discusses a problem where numerous messages end up in the dead letter queue (DLQ) when the JMS service bus consumer connects to th...

2 years ago

Newsletter

Get the latest Dynamics 365 and Power Platform content in your inbox

A curated digest of community blogs, product news, videos, and podcasts — delivered without the noise.

Weekly updates Unsubscribe anytime Fresh community picks
We use your email only for the newsletter and you can unsubscribe at any time.
By subscribing, you agree to the privacy policy.