Skip to content

Blog

Moving Management Groups and Subscriptions

Managing your Azure resources efficiently often involves moving management groups and subscriptions. Here's a brief guide on how to do it:

Moving Management Groups

To move a management group, you need to have the necessary permissions. You must be an owner of the target parent management group and have Management Group Contributor role at the group you want to move.

Here's the step-by-step process:

  1. Navigate to the Azure portal.
  2. Go to Management groups.
  3. Select the management group you want to move.
  4. Click Details.
  5. Under Parent group, click Change.
  6. Choose the new parent group from the list and click Save.

Remember, moving a management group will also move all its child resources including other management groups and subscriptions.

Moving Subscriptions

You can move a subscription from one management group to another or within the same management group. To do this, you must have the Owner or Contributor role at the target management group and Owner role at the subscription level.

Follow these steps:

  1. Go to the Azure portal.
  2. Navigate to Management groups.
  3. Select the management group where the subscription currently resides.
  4. Click on Subscriptions.
  5. Find the subscription you want to move and select ..." (More options).
  6. Click Change parent.
  7. In the pop-up window, select the new parent management group and click Save.

Note

Moving subscriptions could affect the resources if there are policies or permissions applied at the management group level. It's important to understand the implications before making the move. Also, keep in mind that you cannot move the Root management group or rename it.

In conclusion, moving management groups and subscriptions allows for better organization and management of your Azure resources. However, it should be done carefully considering the impact on resources and compliance with assigned policies.

Management Groups

What are Management Groups?

Management Groups are a way to manage access, policies, and compliance for multiple subscriptions. They provide a way to manage access, policies, and compliance for multiple subscriptions. Management groups are containers that help you manage access, policy, and compliance for multiple subscriptions. You organize subscriptions into containers called "management groups" and apply your governance conditions to the management groups. All subscriptions within a management group automatically inherit the conditions applied to the management group.

Management Groups Hierarchy

The management group hierarchy is a level of management groups that represent the different levels of your organization. The hierarchy starts with a single root management group, which represents the Microsoft Entra ID tenant. The root management group is the highest level in the hierarchy. All other management groups are subgroups of the root management group.

Management group design considerations

When designing your management group hierarchy, consider the following:

  • How does your organization differentiate services that are managed or run by particular teams?

  • Are there any specific operations that need to be isolated due to business or regulatory compliance requirements?

  • Management groups can be utilized to consolidate policy and initiative assignments through Azure Policy.

  • A management group hierarchy can accommodate up to six nested levels. The tenant root level and the subscription level are not included in this count.

  • Any principal, be it a user or service principal, within a Microsoft Entra tenant has the authority to establish new management groups. This is due to the fact that Azure role-based access control (RBAC) authorization for managing group activities is not activated by default. For additional details, refer to the guide on safeguarding your resource hierarchy.

  • By default, all newly created subscriptions will be assigned to the tenant root management group.

Management group recommendations

  • Maintain a relatively flat management group hierarchy, ideally with three to four levels maximum. This practice minimizes managerial complexity and overhead.

  • Refrain from mirroring your organizational structure into a deeply nested management group hierarchy. Utilize management groups primarily for policy assignment rather than billing. This strategy aligns with the Azure landing zone conceptual architecture, which applies Azure policies to workloads that need similar security and compliance at the same management group level.

  • Establish management groups under your root-level group representing different types of workloads you will host. These groups should reflect the security, compliance, connectivity, and feature requirements of the workloads. By doing this, you can apply a set of Azure policies at the management group level for all workloads with similar needs.

  • Leverage resource tags for querying and horizontally traversing across the management group hierarchy. Resource tags, enforced or appended via Azure Policy, allow you to group resources for search purposes without relying on a complex management group hierarchy.

  • Set up a top-level sandbox management group. This allows users to immediately experiment with Azure and try out resources not yet permitted in production environments. The sandbox provides isolation from your development, testing, and production settings.

  • Create a platform management group beneath the root management group to support common platform policy and Azure role assignments. This ensures distinct policies can be applied to subscriptions used for your Azure foundation and centralizes billing for common resources in one foundational subscription set.

  • Minimize the number of Azure Policy assignments made at the root management group scope. This reduces the debugging of inherited policies in lower-level management groups.

  • Implement policies to enforce compliance requirements either at the management group or subscription scope to achieve policy-driven governance.

  • Ensure only privileged users have operational access to management groups in the tenant. Enable Azure RBAC authorization in the management group hierarchy settings to fine-tune user privileges. By default, all users are authorized to create their own management groups under the root management group.

  • Set up a default, dedicated management group for new subscriptions. This prevents any subscriptions from being placed under the root management group. This is particularly important if there are users eligible for Microsoft Developer Network (MSDN) or Visual Studio benefits and subscriptions. A sandbox management group could be a suitable candidate for this type of management group. For more information, see Setting - default management group.

  • Avoid creating management groups for production, testing, and development environments. If needed, separate these groups into different subscriptions within the same management group.

Management Group Structure in the Enterprise Scale Landing Zone

This is the common structure for the Management Groups in the Enterprise Scale Landing Zone:

    graph TD
        A[Root Management Group] --> B[Intermediary-Management-Group]
        B --> C[Decommissioned]
        B --> D[Landing Zones]
        B --> E[Platform]
        B --> F[Sandboxes]
        D --> G[Corp]
        D --> H[Online]
        E --> I[Connectivity]
        E --> J[Identity]
        E --> K[Management]
  1. Root Management Group
    • Intermediary-Management-Group
      • Decommissioned: This could be where resources that are being phased out or decommissioned are managed.
      • Sandboxes: This could be an area where developers can test and experiment without affecting production systems.
      • Landing Zones
        • Corp: This could represent corporate resources or applications.
        • Online: This could represent online or customer-facing applications.
      • Platform
        • Connectivity: This could manage resources related to network connectivity.
        • Identity: This could manage resources related to identity and access management.
        • Management: This could manage resources related to overall platform management.

This structure allows for clear segmentation of resources based on their purpose and lifecycle. For example, decommissioned resources are separated from active ones, like Sandbox, and resources within the 'Platform' are further categorized based on their function (Connectivity, Identity, Management). The 'Landing Zones' group appears to separate resources based on their use case or environment (Corp, Online).

The exact interpretation would depend on the specific context and conventions of your organization.

Bad Examples

Example 1: Deeply Nested Hierarchy

graph TD
    A[Root Management Group] --> B[Group 1]
    B --> C[Group 2]
    C --> D[Group 3]
    D --> E[Group 4]
    E --> F[Group 5]
    F --> G[Group 6]

Why it's bad: This hierarchy is too deep. It becomes difficult to manage and increases complexity. Azure supports up to six levels of nested management groups but it's recommended to keep the hierarchy as flat as possible for simplicity.

Example 2: Unorganized Structure

graph TD
    A[Root Management Group] --> B[Group 1]
    A --> C[Group 2]
    B --> D[Group 3]
    C --> E[Group 4]
    D --> F[Group 5]
    E --> G[Group 6]

Why it's bad: The structure is not well-organized and doesn't follow a logical grouping or hierarchy. This can lead to confusion and difficulty in managing resources and policies.

Example 3: Single Level Hierarchy

graph TD
    A[Root Management Group] --> B[Group 1]
    A --> C[Group 2]
    A --> D[Group 3]
    A --> E[Group 4]
    A --> F[Group 5]
    A --> G[Group 6]

Why it's bad: Although this structure is simple, it lacks the ability to group related subscriptions together under a common management group. This makes it harder to apply consistent policies across related subscriptions.

Example 4: Environment-Based Hierarchy


graph TD
    A[Root Management Group] --> B[Production Management Group]
    A[Root Management Group] --> C[Development Management Group]
    A[Root Management Group] --> D[Testing Management Group]

Why it's bad: This structure separates environments into different management groups, which can lead to duplication of policies and increased complexity. It's better to use subscriptions within the same management group to separate environments and apply policies accordingly.

Good examples

    graph TD
        A[Root Management Group] --> B[Intermediary-Management-Group]
        B --> C[Decommissioned]
        B --> D[Landing Zones]
        B --> E[Platform]
        B --> F[Sandboxes]
        D --> G[Corp]
        D --> H[Online]
        E --> I[Connectivity]
        E --> J[Identity]
        E --> K[Management]

😄

References

  • https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-management-groups
  • https://learn.microsoft.com/en-us/azure/governance/management-groups/overview

How to create assigment Reports for Azure RBAC

Role-Based Access Control (RBAC) is a key feature of Azure that allows you to manage access to Azure resources. With RBAC, you can grant permissions to users, groups, and applications at a certain scope, such as a subscription, resource group, or resource. RBAC uses role assignments to determine what actions a user, group, or application can perform on a resource.

In this article, we will show you how to create reports for role assignments in Azure using PowerShell and the ImportExcel module. We will generate separate Excel files for role assignments at the subscription and management group levels, including information such as the role, principal, scope, and whether the assignment is inherited.

Role assignment report in Excel

This is the PowerShell script that generates the role assignment reports:

<#
.SYNOPSIS
A script to get role assignments for Azure subscriptions and management groups.

.DESCRIPTION
This script gets role assignments for specified or all Azure subscriptions and management groups,
and exports them to Excel files. It uses the ImportExcel module to create the Excel files.

.PARAMETER SubscriptionId
The ID of the Azure subscription. If not provided, the script gets role assignments for all subscriptions.

.PARAMETER ManagementGroupName
The name of the Azure management group. If not provided, the script gets role assignments for all management groups.

.PARAMETER GetSubscriptions
Specifies whether to get role assignments for subscriptions. Default is false.

.PARAMETER GetManagementGroups
Specifies whether to get role assignments for management groups. Default is true.

.EXAMPLE
.\get-azroleassigments.ps1 -SubscriptionId "sub-id"

This example gets role assignments for the specified subscription and management group.

.\get-azroleassigments.ps1 -ManagementGroupName "mg-name" -GetSubscriptions $true -GetManagementGroups $false

This example gets role assignments for the specified management group.

.\get-azroleassigments.ps1  -GetSubscriptions $true -GetManagementGroups $true

This example gets role assignments for all subscriptions and management groups.

.NOTES
You can not provide both SubscriptionId and GetSubscriptions parameters at the same time.
You can not provide both ManagementGroupName and GetManagementGroups parameters at the same time.

#>

# Parameters setup
param (
    [Parameter(Mandatory=$false)]
    [string]$SubscriptionId,

    [Parameter(Mandatory=$false)]
    [string]$ManagementGroupName,

    [Parameter(Mandatory=$false)]
    [bool]$GetSubscriptions = $false,

    [Parameter(Mandatory=$false)]
    [bool]$GetManagementGroups = $true
)

# The rest of your script...

# Parameters setup
param (
    [Parameter(Mandatory=$false)]
    [string]$SubscriptionId,

    [Parameter(Mandatory=$false)]
    [string]$ManagementGroupName,

    [Parameter(Mandatory=$false)]
    [bool]$GetSubscriptions = $false,

    [Parameter(Mandatory=$false)]
    [bool]$GetManagementGroups = $true
)

# Install the ImportExcel module if not already installed
if (!(Get-Module -ListAvailable -Name ImportExcel)) {
    Install-Module -Name ImportExcel -Scope CurrentUser
}

# Define the path to your Excel file for Managing Group role assignments
$managementGroupPath = ".\AzRoleAssignmentMg.xlsx"
# Define the path to your Excel file for Subscription role assignments
$subscriptionPath = ".\AzRoleAssignmentSub.xlsx"

# Initialize an empty array to hold all role assignments
$subscriptionRoleAssignments = @()
$managementGroupRoleAssignments = @()

if ($GetManagementGroups) {
    # Check if ManagementGroupName is provided
    if ($ManagementGroupName) {
        # Get role assignments for the specified management group
        $roleAssignments = Get-AzRoleAssignment -Scope "/providers/Microsoft.Management/managementGroups/$ManagementGroupName"

        # Add these role assignments to the management group role assignments array
        $managementGroupRoleAssignments += $roleAssignments

        # Add 'GroupName' and 'IsInherited' properties to each role assignment object
        $roleAssignments | ForEach-Object {
            $_ | Add-Member -NotePropertyName 'GroupDisplayName' -NotePropertyValue (Get-AzManagementGroup -GroupName $ManagementGroupName).DisplayName
            $_ | Add-Member -NotePropertyName 'GroupName' -NotePropertyValue $ManagementGroupName
            # If the Scope of the role assignment is equal to the Id of the management group,
            # then the role assignment is not inherited; otherwise, it is inherited.
            if ($_.Scope -eq "/providers/Microsoft.Management/managementGroups/$ManagementGroupName") {
                $_ | Add-Member -NotePropertyName 'IsInherited' -NotePropertyValue $false
            } else {
                $_ | Add-Member -NotePropertyName 'IsInherited' -NotePropertyValue $true
            }
        }

        # Export the role assignments to a new sheet in the Excel file
        $roleAssignments | Export-Excel -Path $managementGroupPath -WorksheetName (Get-AzManagementGroup -GroupName $ManagementGroupName).DisplayName -AutoSize -AutoFilter
    } else {
        # Get all management groups
        $managementGroups = Get-AzManagementGroup
        # Loop through each management group
        foreach ($mg in $managementGroups) {
            # Get role assignments for the current management group
            $roleAssignments = Get-AzRoleAssignment -Scope "/providers/Microsoft.Management/managementGroups/$($mg.Name)"

            # Add these role assignments to the management group role assignments array
            $managementGroupRoleAssignments += $roleAssignments

            # Add 'GroupName' and 'IsInherited' properties to each role assignment object
            $roleAssignments | ForEach-Object {
                $_ | Add-Member -NotePropertyName 'GroupDisplayName' -NotePropertyValue $mg.DisplayName
                $_ | Add-Member -NotePropertyName 'GroupName' -NotePropertyValue $mg.Name
                # If the Scope of the role assignment is equal to the Id of the management group,
                # then the role assignment is not inherited; otherwise, it is inherited.
                if ($_.Scope -eq $mg.Id) {
                    $_ | Add-Member -NotePropertyName 'IsInherited' -NotePropertyValue $false
                } else {
                    $_ | Add-Member -NotePropertyName 'IsInherited' -NotePropertyValue $true
                }
            }

            # Export the role assignments to a new sheet in the Excel file
            $roleAssignments | Export-Excel -Path $managementGroupPath -WorksheetName $mg.DisplayName -AutoSize -AutoFilter
        }
    }
}

if ($GetSubscriptions) {   
    # Check if SubscriptionId is provided
    if ($SubscriptionId) {
        # Get role assignments for the specified subscription
        $roleAssignments = Get-AzRoleAssignment -Scope "/subscriptions/$SubscriptionId"

        # Add these role assignments to the subscription role assignments array
        $subscriptionRoleAssignments += $roleAssignments

        # Add 'SubscriptionName' and 'IsInherited' properties to each role assignment object
        $roleAssignments | ForEach-Object { 
            $_ | Add-Member -NotePropertyName 'SubscriptionName' -NotePropertyValue (Get-AzSubscription -SubscriptionId $SubscriptionId).Name 
            $_ | Add-Member -NotePropertyName 'IsInherited' -NotePropertyValue $false
        }

        # Export the role assignments to a new sheet in the Excel file
        $roleAssignments | Export-Excel -Path $subscriptionPath -WorksheetName (Get-AzSubscription -SubscriptionId $SubscriptionId).Name -AutoSize -AutoFilter
    } else {
        # Get all subscriptions
        $subscriptions = Get-AzSubscription

        # Loop through each subscription
        foreach ($sub in $subscriptions) {
            # Get role assignments for the current subscription
            $roleAssignments = Get-AzRoleAssignment -Scope "/subscriptions/$($sub.SubscriptionId)"

            # Add these role assignments to the subscription role assignments array
            $subscriptionRoleAssignments += $roleAssignments

            # Add 'SubscriptionName' and 'IsInherited' properties to each role assignment object
            $roleAssignments | ForEach-Object { 
                $_ | Add-Member -NotePropertyName 'SubscriptionName' -NotePropertyValue $sub.Name
                 # If the Scope of the role assignment is equal to the subscription Id,
                 # then the role assignment is not inherited; otherwise, it is inherited.
                if ($_.Scope -eq "/subscriptions/$($sub.SubscriptionId)") {
                    $_ | Add-Member -NotePropertyName 'IsInherited' -NotePropertyValue $false
                } else {
                    $_ | Add-Member -NotePropertyName 'IsInherited' -NotePropertyValue $true
                }
            }

            # Export the role assignments to a new sheet in the Excel file
            $roleAssignments | Export-Excel -Path $subscriptionPath -WorksheetName $sub.Name -AutoSize -AutoFilter
        }
    }
}

This script takes the following parameters:

  • GetSubscriptions: A switch parameter that specifies whether to generate reports for subscriptions. The default value is $false.
  • GetManagementGroups: A switch parameter that specifies whether to generate reports for management groups. The default value is $true.
  • SubscriptionId: The ID of the subscription for which you want to generate the report. If this parameter is not provided, the script will generate reports for all subscriptions.
  • ManagementGroupName: The name of the management group for which you want to generate the report. If this parameter is not provided, the script will generate reports for all management groups.

Role definition report in Excel 1

You can also generate a report for role definitions in Azure using the following PowerShell script:

param(
    [Parameter(Mandatory=$false)]
    [ValidateSet('Console', 'Excel')]
    [string]$OutputType = 'Console',

    [Parameter(Mandatory=$false)]
    [string]$ExcelFilePath = ".\AzRoleDefinition.xlsx"
)

# Install the ImportExcel module if not already installed
if (!(Get-Module -ListAvailable -Name ImportExcel)) {
    Install-Module -Name ImportExcel -Scope CurrentUser
}

# Install the  AzureRM module if not already installed
if (!(Get-Module -ListAvailable -Name  Az)) {
    Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
    Install-Module -Name  Az -Scope CurrentUser
}

# Get all role definitions
$roleDefinitions = Get-AzRoleDefinition | ForEach-Object {
    # Create a custom object with ordered properties
    $customObject = New-Object PSObject -Property @{
        Name = $_.Name
        Id = $_.Id
        IsCustom = $_.IsCustom
        Description = $_.Description
        Actions = ($_.Actions -join ', ').Replace(',', ",`n")
        NotActions = ($_.NotActions -join ', ').Replace(',', ",`n")
        DataActions = ($_.DataActions -join ', ').Replace(',', ",`n")
        NotDataActions = ($_.NotDataActions -join ', ').Replace(',', ",`n")
        AssignableScopes = ($_.AssignableScopes -join ', ').Replace(',', ",`n")
    } | Select-Object Name, Id, IsCustom, Description, Actions, NotActions, DataActions, NotDataActions, AssignableScopes

    return $customObject
}

if ($OutputType -eq 'Console') {
    # Output to console
    $roleDefinitions | Format-Table -AutoSize
} else {
    # Export to Excel
    $roleDefinitions | Export-Excel -Path $ExcelFilePath -WorksheetName 'Role Definitions' -AutoSize -AutoFilter    
}

This script takes the following parameters:

  • OutputType: A string parameter that specifies the output type. The default value is 'Console'. You can also specify 'Excel' to export the report to an Excel file.
  • ExcelFilePath: The path to the Excel file where you want to export the report. The default value is ".\AzRoleDefinition.xlsx".

In the Excel report, you will see the following columns for each role definition: Name, Id, IsCustom, Description, Actions, NotActions, DataActions, NotDataActions, and AssignableScopes.

Conclusion

In this article, we have shown you how to create reports for role assignments and role definitions in Azure using PowerShell and the ImportExcel module. These reports can help you better understand the permissions assigned to users, groups, and applications in your Azure environment and ensure that they are configured correctly. You can customize the scripts to include additional information or export the reports in different formats to suit your needs.

Azure Network, Hub-and-Spoke Topology

Hub and Spoke is a network topology where a central Hub is connected to multiple Spokes. The Hub acts as a central point of connectivity and control, while the Spokes are isolated networks that connect to the Hub. This topology is common in Azure to simplify the connectivity and management of virtual networks.

graph TD
    HUB(("Central Hub"))
    SPOKE1[Spoke1]
    SPOKE2[Spoke2]
    SPOKE3[Spoke3]
    SPOKEN[Spoke...]
    HUB --- SPOKE1
    HUB --- SPOKE2
    HUB --- SPOKE3
    HUB --- SPOKEN

Key Features of the Hub and Spoke Topology

  1. Centralized Connectivity: The Hub centralizes the connectivity between the Spoke networks. This simplifies the administration and maintenance of the network.

  2. Traffic Control: The Hub acts as a traffic control point between the Spoke networks. This allows for centralized application of security and routing policies.

  3. Scalability: The Hub and Spoke topology is highly scalable and can grow to meet the organization's connectivity needs.

  4. Resilience: The Hub and Spoke topology provides redundancy and resilience in case of network failures.

How to Use the Hub and Spoke Topology in Azure

To implement the Hub and Spoke topology in Azure, follow these steps:

# Step 1: Create a virtual network for the Hub
az network vnet create --name HubVnet --resource-group MyResourceGroup --location eastus --address-prefix

# Step 2: Create virtual networks for the Spokes
az network vnet create --name Spoke1Vnet --resource-group MyResourceGroup --location eastus --address-prefix
az network vnet create --name Spoke2Vnet --resource-group MyResourceGroup --location eastus --address-prefix
az network vnet create --name Spoke3Vnet --resource-group MyResourceGroup --location eastus --address-prefix

# Step 3: Connect the Spokes to the Hub
az network vnet peering create --name Spoke1ToHub --resource-group MyResourceGroup --vnet-name Spoke1Vnet --remote-vnet HubVnet --allow-vnet-access
az network vnet peering create --name Spoke2ToHub --resource-group MyResourceGroup --vnet-name Spoke2Vnet --remote-vnet HubVnet --allow-vnet-access
az network vnet peering create --name Spoke3ToHub --resource-group MyResourceGroup --vnet-name Spoke3Vnet --remote-vnet HubVnet --allow-vnet-access

# Step 4: Configure routing between the Hub and the Spokes
az network vnet peering update --name Spoke1ToHub --resource-group MyResourceGroup --vnet-name Spoke1Vnet --set virtualNetworkGateway:AllowGatewayTransit=true
az network vnet peering update --name Spoke2ToHub --resource-group MyResourceGroup --vnet-name Spoke2Vnet --set virtualNetworkGateway:AllowGatewayTransit=true
az network vnet peering update --name Spoke3ToHub --resource-group MyResourceGroup --vnet-name Spoke3Vnet --set virtualNetworkGateway:AllowGatewayTransit=true

# Step 5: Configure routing in the Hub
az network vnet peering update --name HubToSpoke1 --resource-group MyResourceGroup --vnet-name HubVnet --set virtualNetworkGateway:UseRemoteGateways=true
az network vnet peering update --name HubToSpoke2 --resource-group MyResourceGroup --vnet-name HubVnet --set virtualNetworkGateway:UseRemoteGateways=true
az network vnet peering update --name HubToSpoke3 --resource-group MyResourceGroup --vnet-name HubVnet --set virtualNetworkGateway:UseRemoteGateways=true

Variant of the Hub and Spoke Topology

A variant of the Hub and Spoke topology is the Hub and Spoke with peering between spokes that is generally used to allow direct connectivity between the Spoke networks without going through the Hub. This can be useful in scenarios where direct connectivity between the Spoke networks is required, such as data replication or application communication.

graph TD
    HUB(("Central Hub"))
    SPOKE1[Spoke1]
    SPOKE2[Spoke2]
    SPOKE3[Spoke3]
    SPOKEN[Spoke...]
    HUB --- SPOKE1
    HUB --- SPOKE2
    HUB --- SPOKE3
    HUB --- SPOKEN
    SPOKE1 -.- SPOKE2    
In this case, it would be connecting the Spoke networks to each other via virtual network peering, for example:

# Connect Spoke1 to Spoke2
az network vnet peering create --name Spoke1ToSpoke2 --resource-group MyResourceGroup --vnet-name Spoke1Vnet --remote-vnet Spoke2Vnet --allow-vnet-access

Scalability and Performance

The Hub and Spoke topology in Azure is highly scalable and can handle thousands of virtual networks and subnets. In terms of performance, the Hub and Spoke topology provides efficient and low-latency connectivity between the Spoke networks and the Hub.

Security and Compliance

The Hub and Spoke topology in Azure provides centralized control over network security and compliance. Security and routing policies can be applied centrally at the Hub, ensuring consistency and compliance with the organization's network policies.

Monitoring and Logging

Use Network Watcher to monitor and diagnose network problems in the Hub and Spoke topology. Network Watcher provides the following tools:

  • Monitoring
    • Topology view shows you the resources in your virtual network and the relationships between them.
    • Connection monitor allows you to monitor connectivity and latency between endpoints within and outside of Azure.
  • Network diagnostic tools
    • IP flow verify helps you detect traffic filtering issues at the virtual machine level.
    • NSG diagnostics helps you detect traffic filtering issues at the virtual machine, virtual machine scale set, or application gateway level.
    • Next hop helps you verify traffic routes and detect routing issues.
    • Connection troubleshoot enables a one-time check of connectivity and latency between a virtual machine and the Bastion host, application gateway, or another virtual machine.
    • Packet capture allows you to capture traffic from your virtual machine.
    • VPN troubleshoot runs multiple diagnostic checks on your gateways and VPN connections to help debug issues.
  • Traffic

Virtual network flow logs have recently been released which allows for monitoring network traffic in Azure virtual networks.

Use Cases and Examples

The Hub and Spoke topology is ideal for organizations that require centralized connectivity and traffic control between multiple virtual networks in Azure. For example, an organization with multiple branches or departments can use the Hub and Spoke topology to securely and efficiently connect their virtual networks in the cloud.

Best Practices and Tips

When implementing the Hub and Spoke topology in Azure, it is recommended to follow these best practices:

  • Security: Apply consistent security policies at the Hub and Spokes to ensure network protection.
  • Resilience: Configure redundancy and resilience in the topology to ensure network availability in case of failures.
  • Monitoring: Use monitoring tools like Azure Monitor to monitor network traffic and detect potential performance issues.

Conclusion

The Hub and Spoke topology is an effective way to simplify the connectivity and management of virtual networks in Azure. It provides centralized control over network connectivity and traffic, making it easier to implement security and routing policies consistently across the network. By following the recommended best practices and tips, organizations can make the most of the Hub and Spoke topology to meet their cloud connectivity needs.

References

Azure Role-Based Access Control (RBAC)

Azure Role-Based Access Control (RBAC) is a system that provides fine-grained access management of resources in Azure. This allows administrators to grant only the amount of access that users need to perform their jobs.

Overview

In Azure RBAC, you can assign roles to user accounts, groups, service principals, and managed identities at different scopes. The scope could be a management group, subscription, resource group, or a single resource.

Here are some key terms you should know:

  • Role: A collection of permissions. For example, the "Virtual Machine Contributor" role allows the user to create and manage virtual machines.
  • Scope: The set of resources that the access applies to.
  • Assignment: The act of granting a role to a security principal at a particular scope.

Built-in Roles

Azure provides several built-in roles that you can assign to users, groups, service principals, and managed identities. Here are a few examples:

  • Owner: Has full access to all resources including the right to delegate access to others.
  • Contributor: Can create and manage all types of Azure resources but can’t grant access to others.
  • Reader: Can view existing Azure resources.
{
  "Name": "Contributor",
  "Id": "b24988ac-6180-42a0-ab88-20f7382dd24c",
  "IsCustom": false,
  "Description": "Lets you manage everything except access to resources.",
  "Actions": [
    "*"
  ],
  "NotActions": [
    "Microsoft.Authorization/*/Delete",
    "Microsoft.Authorization/*/Write",
    "Microsoft.Authorization/elevateAccess/Action"
  ],
  "DataActions": [],
  "NotDataActions": [],
  "AssignableScopes": [
    "/"
  ]
}

Custom Roles

If the built-in roles don't meet your specific needs, you can create your own custom roles. Just like built-in roles, you can assign permissions to custom roles and then assign those roles to users.

{
  "Name": "Custom Role",
  "Id": "00000000-0000-0000-0000-000000000000",
  "IsCustom": true,
  "Description": "Custom role description",
  "Actions": [
    "Microsoft.Compute/virtualMachines/start/action",
    "Microsoft.Compute/virtualMachines/restart/action"
  ],
  "NotActions": [],
  "DataActions": [],
  "NotDataActions": [],
  "AssignableScopes": [
    "/subscriptions/{subscriptionId}"
  ]
}
Custom Roles has the same structure as built-in roles:

  • Name: The name of the custom role.
  • Id: A unique identifier for the custom role.
  • IsCustom: Indicates whether the role is custom or built-in.
  • Description: A description of the custom role.
  • Actions: The list of actions that the role can perform.
  • NotActions: The list of actions that the role cannot perform.
  • DataActions: The list of data actions that the role can perform.
  • NotDataActions: The list of data actions that the role cannot perform.
  • AssignableScopes: The list of scopes where the role can be assigned.

You can check how to create a custom role here and not forget to check limitations here.

Recommendations

Here are some best practices for managing access with Azure RBAC:

  • Use the principle of least privilege: Only grant the permissions that users need to do their jobs.
  • Use built-in roles when possible: Built-in roles are already defined and tested by Microsoft. Only create custom roles when necessary.
  • Regularly review role assignments: Make sure that users have the appropriate level of access for their job. Remove any unnecessary role assignments.

Conclusion

Azure RBAC is a powerful tool for managing access to your Azure resources. By understanding its core concepts and how to apply them, you can ensure that users have the appropriate level of access for their job.

Kusto Query Language (KQL) for Azure Resource Graph

Azure Graph is a powerful tool provided by Microsoft to query data across all your Azure resources. It uses the Kusto Query Language (KQL), a read-only language similar to SQL, designed to query vast amounts of data in Azure services.

Important

Only a subset of KQL is supported in Azure Resource Graph. For more information, see the Azure Resource Graph Supported KQL Language Elements.

What is KQL?

KQL stands for Kusto Query Language. It's a request to process data and return results. The syntax is easy to read and author, making it ideal for data exploration and ad-hoc data mining tasks.

Using KQL with Azure Graph

Azure Graph allows you to use KQL to create complex queries that fetch information from your Azure resources. You can filter, sort, aggregate, and join data from different resources using KQL.

Here's an example of how you might use KQL to query Azure Graph:

Resources
| where type =~ 'microsoft.web/sites'
| project name, location, resourceGroup

This query retrieves all Azure Web Apps (websites) and projects their name, location, and resourceGroup.

Key Characteristics of KQL

  1. Case Sensitivity: Unlike SQL, KQL is case-sensitive. So 'Name' and 'name' would be considered different identifiers.
  2. Schema-Free: Kusto (Azure Data Explorer) doesn't require a fixed schema, allowing storage of diverse types of data.
  3. Extensibility: While KQL has a wide array of functions, you can also create custom functions as per your needs.

Common Operators in KQL

  • | : This operator creates a pipeline where the output of one command becomes the input of another.
  • where : Filters rows based on specified conditions.
  • summarize : Groups rows and calculates aggregate expressions.
  • join : Combines rows from two tables based on a common column.
  • project : Selects specific columns from the input.
  • extend : Adds new columns to the input.
  • order by : Sorts rows based on specified columns.

KQL Query Examples

1. List all Azure resources in a subscription

Resources

2. List all Azure resources in a resource group

Resources
| where resourceGroup == 'myResourceGroup'

3. List all Azure resources of a specific type

Resources
| where type =~ 'Microsoft.Compute/virtualMachines'

Pagination in KQL

KQL supports pagination using the limit and offset operators. You can use these operators to control the number of rows returned and skip a certain number of rows.

Resources
| limit 10
| offset 5

If you exceed payload limits, you can paginate Azure Resource Graph query results with powershell:

$kqlQuery = "policyResources | where type =~'Microsoft.Authorization/PolicySetDefinitions' or type =~'Microsoft.Authorization/PolicyDefinitions' | project definitionId = tolower(id), category = tostring(properties.metadata.category), definitionType = iff(type =~ 'Microsoft.Authorization/PolicysetDefinitions', 'initiative', 'policy'),PolicyDefinition=properties"

$batchSize = 5
$skipResult = 0

[System.Collections.Generic.List[string]]$kqlResult

while ($true) {

  if ($skipResult -gt 0) {
    $graphResult = Search-AzGraph -Query $kqlQuery -First $batchSize -SkipToken $graphResult.SkipToken
  }
  else {
    $graphResult = Search-AzGraph -Query $kqlQuery -First $batchSize
  }

  $kqlResult += $graphResult.data

  if ($graphResult.data.Count -lt $batchSize) {
    break;
  }
  $skipResult += $skipResult + $batchSize
}

Best Practices for Writing KQL Queries

  1. Use project to Select Columns: Only select the columns you need to reduce the amount of data returned.
  2. Use where to Filter Rows: Apply filters to reduce the number of rows processed.
  3. Use summarize to Aggregate Data: Aggregate data to reduce the number of rows returned.
  4. Use join to Combine Data: Combine data from different tables using the join operator.
  5. Use order by to Sort Data: Sort data based on specific columns to make it easier to read.

Limitations of KQL

  1. No DDL Operations: KQL doesn't support Data Definition Language (DDL) operations like creating tables or indexes.
  2. No DML Operations: KQL doesn't support Data Manipulation Language (DML) operations like inserting, updating, or deleting data.
  3. Limited Data Types: KQL has a limited set of data types compared to SQL.
  4. No Transactions: KQL doesn't support transactions, so you can't group multiple operations into a single transaction.

Conclusion

KQL is a potent tool for querying large datasets in Azure. Its SQL-like syntax makes it accessible for anyone familiar with SQL, and its rich set of features makes it a flexible solution for a variety of data processing needs. Practice writing KQL queries to uncover valuable insights from your Azure resources!

References

Azure role assignment conditions

First of all, let's understand what is ABAc (Attribute-Based Access Control) and how it can be used in Azure.

What is ABAC?

Attribute-Based Access Control (ABAC) is an access control model that uses attributes to determine access rights. In ABAC, access decisions are based on the attributes of the user, the resource, and the environment. This allows for fine-grained access control based on a wide range of attributes, such as user roles, resource types, and time of day.

ABAC is a flexible and scalable access control model that can be used to enforce complex access policies. It allows organizations to define access control rules based on a wide range of attributes and to adapt those rules as their needs change.

ABAC is build on Azure RBAC.

What is Azure role assignment conditions?

Azure role assignment conditions allow you to define conditions that must be met for a role assignment to be effective.

How to configure Azure role assignment conditions?

To configure Azure role assignment conditions, configure the role assignment as usual, and then click on the "Conditions" tab. Here you can define the conditions that must be met for the role assignment to be effective.

alt text

Options for configuring Conditions:

  • Allow user to only assign selected roles to selected principals (fewer privileges)
  • Allow user to assign all roles except privileged administrator roles Owner, UAA, RBAC (Recommended)
  • Allow user to assign all roles (highly privileged)

The first one is the most restrictive, for example, allowing the user to only assign selected roles to selected principals. This is useful when you want to limit the privileges of a user to only a subset of roles and principals.

These are the options available for "Allow user to only assign selected roles to selected principals (fewer privileges)":

alt text

  • Constrain roles:
    • Allow user to only assign roles you select
  • Constrain roles and principal types:
    • Allow user to only assign roles you select
    • Allow user to only assign these roles to principal types you select (users, groups, or service principals)
  • Constrain roles and principals
    • Allow user to only assign roles you select
    • Allow user to only assign these roles to principals you select
    • Allow all except specific roles
    • Allow user to assign all roles except the roles you select

Conclusion

Azure role assignment conditions provide a flexible and powerful way to control access to Azure resources. By defining conditions that must be met for a role assignment to be effective, you can enforce fine-grained access control policies that meet the specific needs of your organization. This allows you to limit the privileges of users, assign roles to specific principals, and control access to sensitive resources. Azure role assignment conditions are a valuable tool for organizations that need to enforce strict access control policies and protect their critical resources.

References

Using Enterprise Azure Policy as Code (EPAC)

In this blog post, we will show how to use Enterprise Azure Policy as Code (EPAC) to manage your Azure environment.

Use case

  • Determine desired state strategy.
  • We have some existing Azure Policies that we want to manage as code.
  • For simplicity, we will suppose that we have a unique Centralized Team that manages the policies.
  • We will use a Git repository to store the policies and the CI/CD process to deploy them.
  • We doesn't have any exclude resources in the environment.
  • How to handle Defender for Cloud Policy Assignments:
  • We will use Defender for Cloud to manage the Policy Assignments for Defender Plans when a plan is enabled.
  • EPAC will manage Defender for Cloud Security Policy Assignments at the management group level. This is the default behavior.
  • Design your CI/CD process:
  • We will use Release Flow

Management Groups for Enterprise Scale Landing Zone

This is the common structure for the Management Groups in the Enterprise Scale Landing Zone, now Accelerator Landing Zone:

    graph TD
        A[Root Management Group] --> B[Intermediary-Management-Group]
        B --> C[Decommissioned]
        B --> D[Landing Zones]
        B --> E[Platform]
        B --> F[Sandboxes]
        D --> G[Corp]
        D --> H[Online]
        E --> I[Connectivity]
        E --> J[Identity]
        E --> K[Management]

For this use case, we will use the Landing Zones Management Group for duplicate and old Management Group hierarchy (manage-azure-policy):

  graph TD
      A[Root Management Group] --> B[epac-dev]
      B --> C[dev-decommissioned]
      B --> D[dev-landingzones]
      B --> E[dev-platform]
      B --> F[dev-sandbox]
      D --> G[dev-corp]
      D --> H[dev-online]
      E --> I[dev-connectivity]
      E --> J[dev-identity]
      E --> K[dev-management]
      A[Root Management Group] --> L[epac-prod]
      L --> M[prod-decommissioned]
      L --> N[prod-landingzones]
      L --> O[prod-platform]
      L --> P[prod-sandbox]
      N --> Q[prod-corp]
      N --> R[prod-online]
      O --> S[prod-connectivity]
      O --> T[prod-identity]
      O --> U[prod-management]
      A[Root Management Group] --> V[manage-azure-policy]

      classDef dev fill:#f90,stroke:#333,stroke-width:2px;
      classDef prod fill:#f9f,stroke:#333,stroke-width:2px;
      class dev A,B,C,D,E,F,G,H,I,J,K;
      class prod L,M,N,O,P,Q,R,S,T,U;   

Note

You could also use two different tenants for the different environments, but this is not the case for this use case.

You can create this Management Groups hierarcly using the Azure CLI with the following commands:

az account management-group create --name "MyManagementGroup"
az account management-group move --name "ChildGroup" --new-parent "NewParentGroup"

For the use case, we will use the following commands:

az account management-group create --name "epac-dev"
az account management-group create --name "dev-decommissioned" --parent "epac-dev"
az account management-group create --name "dev-landingzones" --parent "epac-dev"
az account management-group create --name "dev-platform" --parent "epac-dev"
az account management-group create --name "dev-sandbox" --parent "dev-landingzones"
az account management-group create --name "dev-corp" --parent "dev-landingzones"
az account management-group create --name "dev-online" --parent "dev-landingzones"
az account management-group create --name "dev-connectivity" --parent "dev-platform"
az account management-group create --name "dev-identity" --parent "dev-platform"
az account management-group create --name "dev-management" --parent "dev-platform"
az account management-group create --name "epac-prod"
az account management-group create --name "prod-decommissioned" --parent "epac-prod"
az account management-group create --name "prod-landingzones" --parent "epac-prod"
az account management-group create --name "prod-platform" --parent "epac-prod"
az account management-group create --name "prod-sandbox" --parent "prod-landingzones"
az account management-group create --name "prod-corp" --parent "prod-landingzones"
az account management-group create --name "prod-online" --parent "prod-landingzones"
az account management-group create --name "prod-connectivity" --parent "prod-platform"
az account management-group create --name "prod-identity" --parent "prod-platform"
az account management-group create --name "prod-management" --parent "prod-platform"

Installation

To install EPAC, follow these steps:

    Install-Module Az -Scope CurrentUser
    Install-Module EnterprisePolicyAsCode -Scope CurrentUser

Create an empty repository in github and clone it

Create a repository in github and clone it

    git clone https://github.com/user/demo-EPAC.git

Create a branch for the feature/firstcommit

    git checkout -b feature/firstcommit

Note

From this moment on, we will execute all commands within the repository directory.

Create Definitions

New-EPACDefinitionFolder -DefinitionsRootFolder Definitions

This command creates a folder structure for the definitions. The Definitions folder Structure is as follows:

  • Define the Azure environment(s) in file global-settings.jsonc
  • Create custom Policies (optional) in folder policyDefinitions
  • Create custom Policy Sets (optional) in folder policySetDefinitions
  • efine the Policy Assignments in folder policyAssignments
  • Define the Policy Exemptions (optional) in folder policyExemptions
  • Define Documentation in folder policyDocumentations]

Configure global-settings.jsonc

global-settings.jsonc is the file where you define the Azure environment(s) that you want to manage with EPAC. The file should be located in the Definitions folder. Here is an example of the content of the file:

{
    "$schema": "https://raw.githubusercontent.com/Azure/enterprise-azure-policy-as-code/main/Schemas/global-settings-schema.json",
    "pacOwnerId": "ff2ce5e1-da8a-4cfb-883b-aee9fbfb85d6",
    "pacEnvironments": [
        {
            "pacSelector": "epac-dev",
            "cloud": "AzureCloud",
            "tenantId": "e18e4e7e-d0cc-40af-9907-84923ca55499",
            "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/epac-dev",
            "desiredState": {
                "strategy": "full",
                "keepDfcSecurityAssignments": false
            },
            "managedIdentityLocation": "france"
        },
        {
            "pacSelector": "tenant",
            "cloud": "AzureCloud",
            "tenantId": "e18e4e7e-d0cc-40af-9907-84923ca55499",
            "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/epac-prod",
            "desiredState": {
                "strategy": "full",
                "keepDfcSecurityAssignments": false
            },
            "managedIdentityLocation": "france",
            "globalNotScopes": [
                "/providers/Microsoft.Management/managementGroups/mg-Epac-Dev",
                "/providers/Microsoft.Management/managementGroups/manage-azure-policy"
            ]
        },
        {
            "pacSelector": "manage-azure-policy",
            "cloud": "AzureCloud",
            "tenantId": "e18e4e7e-d0cc-40af-9907-84923ca55499",
            "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/manage-azure-policy",
            "desiredState": {
                "strategy": "full",
                "keepDfcSecurityAssignments": false
            },
            "managedIdentityLocation": "france"
        }
    ]

}

Info

The pacOwner helps to identify who or what owns an Assignment or Policy definition deployment and needs to be unique to your EPAC environment. The pacOwnerId is used to identity policy resources that are deployed by your EPAC repository, or another EPAC isntance, legacy or another solution entirely.

You can generate a new id with New-Guid

Extracting existing Policy Resources

Export-AzPolicyResources

This command extracts all existing Policy Resources in the Azure environment(s) defined in the global-settings.jsonc file. The extracted resources are saved in the Output/Definitions folder.

You needs review the extracted resources and move them to the correct folder in the Definitions folder.

Syncing ALZ Definitions

Sync-ALZPolicies -DefinitionsRootFolder .\Definitions -CloudEnvironment AzureCloud # Also accepts AzureUSGovernment or AzureChinaCloud

You can sync the ALZ Definitions manually or use a GitHub action creating .github\workflows\alz-sync.yaml in your repository with the following content:

name: Sync ALZ Policy Objects

env:
  REVIEWER: anwather # Change this to your GitHub username
  DefinitionsRootFolder: Definitions # Change this to the folder where your policy definitions are stored

on:
  workflow_dispatch

jobs:
    sync:
        runs-on: ubuntu-latest
        steps:
        - name: Checkout
          uses: actions/checkout@v4
        - shell: pwsh
          name: Install Required Modules
          run: |
            Install-Module EnterprisePolicyAsCode -Force
            Sync-ALZPolicies -DefinitionsRootFolder $env:DefinitionsRootFolder
            $branchName = "caf-sync-$(Get-Date -Format yyyy-MM-dd-HH-mm)"
            git config user.name "GitHub Actions Bot"
            git config user.email "<>"
            git checkout -b $branchName
            git add .
            git commit -m "Updated ALZ policy objects"
            git push --set-upstream origin $branchName
            gh pr create -B main -H $branchName --title "Verify Synced Policies - $branchName" -b "Checkout this PR branch and validate changes before merging." --reviewer $env:REVIEWER
        env:
            GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

CI/CD with Github Flow

We will use the Github Flow to manage the CI/CD process. We will create a Github Actions to deploy the policies to the Azure environment(s) defined in the global-settings.jsonc file.

Github Flow

We can open a second terminal and execute the following command to create the Github Actions in one upper level folder of our repository. This command will create the Github Actions in the .github\workflows folder of the repository. :

git clone https://github.com/Azure/enterprise-azure-policy-as-code
cd enterprise-azure-policy-as-code
New-PipelinesFromStarterKit -StarterKitFolder .\StarterKit -PipelinesFolder ..\global-azure-2024-demo-EPAC\.github\workflows -PipelineType GitHubActions -BranchingFlow github -ScriptType Module 

Now, we need to create some environments with secrets in the repository to use in the Github Actions. We need to create the following environments:

Environment Purpose App Registration (SPN)
EPAC-DEV Plan and deploy to epac-dev ci-cd-epac-dev-owner
TENANT-PLAN Build deployment plan for tenant ci-cd-root-policy-reader
TENANT-DEPLOY-POLICY Deploy Policy resources for tenant ci-cd-root-policy-contributor
TENANT-DEPLOY-ROLES Deploy Roles for tenant ci-cd-root-user-assignments
TENANT-REMEDIATE-POLICY Remediate Policy resources for tenant ci-cd-root-policy-contributor

You need to Configure a federated identity credential on an app too.

First Commit

Now we can commit the changes to the repository and make a pull request to the main branch.

References

Cambio de nombres de los niveles de servicio de Microsoft Defender para Cloud

No es nuevo pero me gustaría recordar que Microsoft ha cambiado los nombres de los niveles de servicio de Microsoft Defender para Cloud. A continuación, se muestra una tabla con los nombres anteriores y los nuevos nombres de los niveles de servicio de Microsoft Defender para Cloud:

Nombre ANTERIOR del nivel de servicio 2 Nombre NUEVO del nivel de servicio 2 Nivel de servicio: nivel de servicio 4 (sin cambios)
Advanced Data Security Microsoft Defender for Cloud Defender para SQL
Advanced Threat Protection Microsoft Defender for Cloud Defender para registros de contenedor
Advanced Threat Protection Microsoft Defender for Cloud Defender para DNS
Advanced Threat Protection Microsoft Defender for Cloud Defender para Key Vault
Advanced Threat Protection Microsoft Defender for Cloud Defender para Kubernetes
Advanced Threat Protection Microsoft Defender for Cloud Defender para MySQL
Advanced Threat Protection Microsoft Defender for Cloud Defender para PostgreSQL
Advanced Threat Protection Microsoft Defender for Cloud Defender para Resource Manager
Advanced Threat Protection Microsoft Defender for Cloud Defender para Storage
Azure Defender Microsoft Defender for Cloud Administración de superficie expuesta a ataques externos de Defender
Azure Defender Microsoft Defender for Cloud Defender para Azure Cosmos DB
Azure Defender Microsoft Defender for Cloud Defender para contenedores
Azure Defender Microsoft Defender for Cloud Defender for MariaDB
Security Center Microsoft Defender for Cloud Defender para App Service
Security Center Microsoft Defender for Cloud Defender para servidores
Security Center Microsoft Defender for Cloud Administración de la posición de seguridad en la nube de Defender

Azure Policy useful queries

Policy assignments and information about each of its respective definitions

// Policy assignments and information about each of its respective definitions
// Gets policy assignments in your environment with the respective assignment name,definition associated, category of definition (if applicable), as well as whether the definition type is an initiative or a single policy.

policyResources
| where type =~'Microsoft.Authorization/PolicyAssignments'
| project policyAssignmentId = tolower(tostring(id)), policyAssignmentDisplayName = tostring(properties.displayName), policyAssignmentDefinitionId = tolower(properties.policyDefinitionId)
| join kind=leftouter(
 policyResources
 | where type =~'Microsoft.Authorization/PolicySetDefinitions' or type =~'Microsoft.Authorization/PolicyDefinitions'
 | project definitionId = tolower(id), category = tostring(properties.metadata.category), definitionType = iff(type =~ 'Microsoft.Authorization/PolicysetDefinitions', 'initiative', 'policy')
) on $left.policyAssignmentDefinitionId == $right.definitionId

List SubscriptionId and SubscriptionName

ResourceContainers
| where type =~ 'microsoft.resources/subscriptions'
| project subscriptionId, subscriptionName=name

List ManagementGroupId and ManagementGroupName

ResourceContainers
| where type =~ 'microsoft.management/managementgroups'
| project mgname = name, displayName = properties.displayName

Policy assignments and information about each of its respective definitions displaying the scope of the assignment, the subscription display name, the management group id, the resource group name, the definition type, the assignment name, the category of the definition, and the policy assignment ID.

policyResources
| where type =~'Microsoft.Authorization/PolicyAssignments'
| project policyAssignmentId = tolower(tostring(id)), policyAssignmentDisplayName = tostring(properties.displayName), policyAssignmentDefinitionId = tolower(properties.policyDefinitionId), subscriptionId = tostring(subscriptionId),resourceGroup=tostring(resourceGroup), AssignmentDefinition=properties
| join kind=leftouter(
    policyResources
    | where type =~'Microsoft.Authorization/PolicySetDefinitions' or type =~'Microsoft.Authorization/PolicyDefinitions'
    | project definitionId = tolower(id), category = tostring(properties.metadata.category), definitionType = iff(type =~ 'Microsoft.Authorization/PolicysetDefinitions', 'initiative', 'policy'),PolicyDefinition=properties
) on $left.policyAssignmentDefinitionId == $right.definitionId
| extend scope = iff(policyAssignmentId contains '/subscriptions/', 'Subscription', iff(policyAssignmentId contains '/providers/microsoft.management/managementgroups', 'Management Group', 'Resource Group'))
| join kind=leftouter (ResourceContainers
| where type =~ 'microsoft.resources/subscriptions'
| project subscriptionId, subscriptionName=name) on $left.subscriptionId == $right.subscriptionId
| extend SubscriptionDisplayName = iff(isnotempty(subscriptionId), subscriptionName, '')
| extend ManagementGroupName = iff(policyAssignmentId contains '/providers/microsoft.management/', split(policyAssignmentId, '/')[4],'')
| extend resourceGroupDisplayName = iff(isnotempty(resourceGroup), resourceGroup, '')
| project ManagementGroupName,SubscriptionDisplayName,resourceGroupDisplayName, scope,definitionType,policyAssignmentDisplayName, category,policyAssignmentId, AssignmentDefinition, PolicyDefinition
  • Add Management Group Display Name