Skip to main content

September 2, 2026

To Use a Custom Role for Horizon Cloud App Registration

The Contributor role is commonly used to enable the Horizon Cloud app registration process to make API calls in the Microsoft Azure subscription. If you prefer to avoid the use of the Contributor role, you can create a custom role for this purpose. The custom role has certain required and optional permissions that you must be aware of when you create a service principal.

To create a custom role, use a tool such as Azure PowerShell or Azure CLI to create a custom role definition that includes the mandatory permissions listed in this topic. For more information about Azure custom roles, see Azure resource provider operations.

Note that you cannot apply Azure roles to a group and then add the service principle to that group. Instead, you must first add Azure roles directly to your service principle and then add the service principal to the group.

Mandatory Permissions for Azure Custom Role

The following permissions are mandatory for the deployment of Horizon Edge in Microsoft Azure. These Microsoft Azure resource operations must be permitted in the Custom Role when assigning permissions at the Subscription level.

Operation
Microsoft.Authorization/*/read
Microsoft.Compute/*/read
Microsoft.Compute/availabilitySets/*
Microsoft.Compute/disks/*
Microsoft.Compute/galleries/read
Microsoft.Compute/galleries/write
Microsoft.Compute/galleries/delete
Microsoft.Compute/galleries/images/
Microsoft.Compute/galleries/images/versions/
Microsoft.Compute/images/*
Microsoft.Compute/locations/*
Microsoft.Compute/snapshots/*
Microsoft.Compute/virtualMachines/*
Microsoft.Compute/virtualMachineScaleSets/*
Microsoft.ContainerService/managedClusters/delete
Microsoft.ContainerService/managedClusters/read
Microsoft.ContainerService/managedClusters/write
Microsoft.ContainerService/managedClusters/commandResults/read
Microsoft.ContainerService/managedClusters/runcommand/action
Microsoft.ContainerService/managedClusters/upgradeProfiles/read
Microsoft.ManagedIdentity/userAssignedIdentities/*/assign/action
Microsoft.ManagedIdentity/userAssignedIdentities/*/read
Microsoft.MarketplaceOrdering/offertypes/publishers/offers/plans/agreements/read
Microsoft.MarketplaceOrdering/offertypes/publishers/offers/plans/agreements/write
Microsoft.Network/loadBalancers/*
Microsoft.Network/networkInterfaces/*
Microsoft.Network/networkSecurityGroups/*
Microsoft.Network/virtualNetworks/read
Microsoft.Network/virtualNetworks/checkIpAddressAvailability/read
Microsoft.Network/virtualNetworks/subnets/read
Microsoft.Network/virtualNetworks/subnets/write
Microsoft.Network/virtualNetworks/subnets/join/action
Microsoft.Network/virtualNetworks/subnets/joinLoadBalancer/action
Microsoft.Network/virtualNetworks/subnets/joinViaServiceEndpoint/action
Microsoft.Network/virtualNetworks/subnets/effectiveRoutingRules/read
Microsoft.Network/virtualNetworks/subnets/effectiveSecurityUserRules/read
Microsoft.Network/virtualNetworks/subnets/resourceNavigationLinks/read
Microsoft.Network/virtualNetworks/subnets/serviceAssociationLinks/read
Microsoft.Network/virtualNetworks/subnets/virtualMachines/read
Microsoft.Network/virtualNetworks/virtualNetworkPeerings/read
Microsoft.ResourceGraph/*
Microsoft.Resources/deployments/*
Microsoft.Resources/subscriptions/read
Microsoft.Resources/subscriptions/resourceGroups/*
Microsoft.ResourceHealth/availabilityStatuses/read
Microsoft.Storage/*/read
Microsoft.Storage/storageAccounts/*

If you intend to use App Volumes, ensure that you have configured the permissions at the Subscription level. For more information about these permissions, see Azure Private Endpoint for an App Volumes Application Storage Account.

Operation
Microsoft.Network/locations/availablePrivateEndpointTypes/read
Microsoft.Network/privateEndpoints/read
Microsoft.Network/privateEndpoints/write
Microsoft.Network/privateEndpoints/delete
Microsoft.Network/virtualNetworks/read
Microsoft.Network/virtualNetworks/subnets/read
Microsoft.Network/virtualNetworks/subnets/write
Microsoft.Network/virtualNetworks/subnets/join/action
Microsoft.Resources/deployments/*
Microsoft.Resources/subscriptions/read
Microsoft.Resources/subscriptions/resourceGroups/read

Optional Permissions for Azure Custom Role

The following permissions are not mandatory for the deployment of Horizon Edge in Microsoft Azure. However, functionality in the Horizon Universal Console that relies on these optional permissions does not work if you do not include them. The following Microsoft Azure Resource Operations are optional in the Custom Role when assigning permissions at the Subscription level.

Operation
Microsoft.KeyVault//read
Microsoft.KeyVault/vaults/

Microsoft.KeyVault/vaults/secrets/*
Key vault permissions are required for disk encryption of pool VMs.
Microsoft.Network/natGateways/join/actionThis permission is required when the Azure Private Link connectivity type is selected at the time that the Horizon Edge is created, and the management subnet has a NAT gateway associated. The permission is required to create the private endpoint resources.
Microsoft.Network/natGateways/readThis permission is required to validate that the management subnet's NAT gateway is, if present, correctly configured, when the cluster outbound type is selected as NAT gateway for Horizon Edge.
Microsoft.Network/privateEndpoints/write
Microsoft.Network/privateEndpoints/read
Private Endpoint permissions are required to deploy Horizon Edge with Azure Private Link.
Microsoft.Network/publicIPAddresses/*Public IP permission is required to deploy a Horizon Edge instance with Unified Access Gateway instances behind a load balancer with a public IP address. Also, this permission is required to deploy and to add a public IP address to an image.
Microsoft.Network/routeTables/join/actionThis permission is required when the Azure Private Link connectivity type is selected at the time that the Horizon Edge is created, and the management subnet has a route table attached. The permission is required to create the private endpoint resources.
Microsoft.Network/routeTables/readThis permission is required if the cluster outbound type selected for Horizon Edge is User defined routes. It is required to validate the associated route table of the management subnet to ensure that the default route is configured correctly.
Microsoft.CostManagement//read
Microsoft.Billing/
/read
These permissions allow Horizon Cloud to read Azure Cost Management and Billing data for Horizon-created resource groups so it can compute cost and savings metrics for Cost Insights.

Note: When deleting a Microsoft Entra ID joined pool or a VM, the service principal should have permissions to delete the device entry from Microsoft Entra ID.

The permissions are of the following:

Scope: https://graph.microsoft.com/

Permission : Device.ReadWrite.All Read and write devices

Admin Consent : Yes

The permission can be given by navigating to Subscription > Azure Active Directory > App Registrations > Select the App that permission needs to be given > API Permission > Select Microsoft GRAPH > Select Device.ReadWriteAll.

Microsoft Azure Custom Role JSON Example

The following JSON code block illustrates what a custom role definition named Horizon Cloud Custom Role - Titan might look like when it contains the mandatory and optional operations listed above. The ID is the unique ID of the custom role. When you use Azure PowerShell or Azure CLI to create a custom role, the process automatically generates this ID. For the variable my_subscription_ID, substitute the IDs of the subscriptions in which the custom role will be used.

In the assignableScopes section, you can use multiple subscription IDs, "/subscriptions/my_subscription_ID", to allow the custom role to be used across multiple subscriptions.

See the following sample JSON for a role permitting the Horizon Cloud required operations when assigning permissions at the Subscription level.

{
    "id": "uuid",
    "properties": {
        "roleName": "Horizon Cloud Custom Role - Titan",
        "description": "All permissions required for deployment and operation of a Horizon Edge in Azure",
        "assignableScopes": [
              "/subscriptions/my_subscription_ID"
        ],
        "permissions": [
            {
                "actions": [
                    "Microsoft.Authorization/*/read",
                    "Microsoft.Compute/*/read",
                    "Microsoft.Compute/availabilitySets/*",
                    "Microsoft.Compute/disks/*",
                    "Microsoft.Compute/galleries/read",
                    "Microsoft.Compute/galleries/write",
                    "Microsoft.Compute/galleries/delete",
                    "Microsoft.Compute/galleries/images/*",
                    "Microsoft.Compute/galleries/images/versions/*",
                    "Microsoft.Compute/images/*",
                    "Microsoft.Compute/locations/*",
                    "Microsoft.Compute/snapshots/*",
                    "Microsoft.ContainerService/managedClusters/delete",
                    "Microsoft.ContainerService/managedClusters/read",
                    "Microsoft.ContainerService/managedClusters/write",
                    "Microsoft.ContainerService/managedClusters/commandResults/read",
                    "Microsoft.ContainerService/managedClusters/runcommand/action",
                    "Microsoft.ContainerService/managedClusters/upgradeProfiles/read",
                    "Microsoft.ManagedIdentity/userAssignedIdentities/*/assign/action",
                    "Microsoft.ManagedIdentity/userAssignedIdentities/*/read",
                    "Microsoft.Compute/virtualMachines/*",
                    "Microsoft.Compute/virtualMachineScaleSets/*",
                    "Microsoft.MarketplaceOrdering/offertypes/publishers/offers/plans/agreements/read",
                    "Microsoft.MarketplaceOrdering/offertypes/publishers/offers/plans/agreements/write",
                    "Microsoft.Network/loadBalancers/*",
                    "Microsoft.Network/networkInterfaces/*",
                    "Microsoft.Network/networkSecurityGroups/*",
                    "Microsoft.Network/virtualNetworks/read",
                    "Microsoft.Network/virtualNetworks/checkIpAddressAvailability/read",
                    "Microsoft.Network/virtualNetworks/subnets/read",
                    "Microsoft.Network/virtualNetworks/subnets/write",
                    "Microsoft.Network/virtualNetworks/subnets/join/action",
                    "Microsoft.Network/virtualNetworks/subnets/joinLoadBalancer/action",
                    "Microsoft.Network/virtualNetworks/subnets/joinViaServiceEndpoint/action",
                    "Microsoft.Network/virtualNetworks/subnets/effectiveRoutingRules/read",
                    "Microsoft.Network/virtualNetworks/subnets/effectiveSecurityUserRules/read",
                    "Microsoft.Network/virtualNetworks/subnets/resourceNavigationLinks/read",
                    "Microsoft.Network/virtualNetworks/subnets/serviceAssociationLinks/read",
                    "Microsoft.Network/virtualNetworks/subnets/virtualMachines/read",
                    "Microsoft.Network/virtualNetworks/virtualNetworkPeerings/read",
                    "Microsoft.ResourceGraph/*",
                    "Microsoft.Resources/deployments/*",
                    "Microsoft.Resources/subscriptions/read",
                    "Microsoft.Resources/subscriptions/resourceGroups/*",
                    "Microsoft.ResourceHealth/availabilityStatuses/read",
                    "Microsoft.Storage/*/read",
                    "Microsoft.Storage/storageAccounts/*",
                    "Microsoft.KeyVault/*/read",
                    "Microsoft.KeyVault/vaults/*",
                    "Microsoft.KeyVault/vaults/secrets/*",
                    "Microsoft.Network/natGateways/join/action",
                    "Microsoft.Network/natGateways/read",
                    "Microsoft.Network/privateEndpoints/write",
                    "Microsoft.Network/privateEndpoints/read",
                    "Microsoft.Network/publicIPAddresses/*",
                    "Microsoft.Network/routeTables/join/action",
                    "Microsoft.Network/routeTables/read"
                ],
                "notActions": [],
                "dataActions": [],
                "notDataActions": []
            }
        ]
    }
}

Was this page helpful?

Provide feedback for this topic

Was this topic helpful?

Please do not include any personal or confidential information.

Generating link…