Support for Azure Resource Manager (ARM) is encapsulated in a component known as the ARM Plugin and it is a standard feature of CVAD. To provision and/or power manage machines in Azure, the ARM Plugin must be granted access to your Azure subscription via a service principal that has been assigned permissions over a scope of Azure resources. A service principal serves the same basic purpose as a user account: it provides the ARM Plugin with an Azure Active Directory identity; credentials for authentication and permissions on Azure resources. Just like user accounts, service principals are configured using Role-Based Access Control (RBAC).
Access to Azure resources is granted by assigning an RBAC role to a service principal at a certain scope where the scope can be a subscription, a resource group, or a specific resource. Resources are arranged in a containment hierarchy and the permissions defined by the role apply to all resources below the scope where it is applied. For example, a role applied on a subscription is applied to all resources in the subscription and a role applied to a resource group is applied to all resources contained in the resource group.
A detailed description of access control in Azure can be found here. Azure has a large selection of built-in roles and additionally supports the definition of custom roles.
For the role assigned to your service principal, we recommend two options:
For the scope that your service principal can access, we recommend two options:
This article will explore different types of service principals based on the role assigned to them and the scope they can access. It describes their advantages and disadvantages as well as how to create them in PowerShell. It also provides guidelines to help you choose the proper service principal type.
If you want to assign a built-in role to your service principal, Contributor is the best choice. The contributor role has all the permissions required by the ARM plugin and doesn't block you from getting future features. More details about the Contributor role can be found here.
We don't recommend using other built-in roles for the following reasons:
However, the Contributor role still has more permissions than the ARM plugin needs.
If you want to control the permissions assigned to your service principal, a custom role is a choice. This article shows how to create custom roles in PowerShell or portal. When you create a custom role, you can specify the control plane actions that the role allows to be performed. A custom role with general permissions required by the ARM plugin can work normally like the Contributor role. Citrix has listed the minimum set of permissions required by the ARM plugin here and the minimum set will be updated when there are new required permissions.
Note: A custom role defined with the minimum set of permissions will likely block new features that require new permissions. Please refer to the link for the latest permission requirement.
For example, you can create a new custom role "Citrix-Custom-Contributor" by first defining it in JSON :
{ "Name": "Citrix-Custom-Contributor", "Description": "Minimum set of permissions needed by ARM plugin", "AssignableScopes": [ "/subscriptions/<YOUR-SUBSCRIPTION-ID>" ], "Actions": [ "Microsoft.Compute/diskEncryptionSets/read", "Microsoft.Compute/disks/beginGetAccess/action", "Microsoft.Compute/disks/delete", "Microsoft.Compute/disks/endGetAccess/action", "Microsoft.Compute/disks/read", "Microsoft.Compute/disks/write", "Microsoft.Compute/galleries/delete", "Microsoft.Compute/galleries/images/delete", "Microsoft.Compute/galleries/images/read", "Microsoft.Compute/galleries/images/versions/delete", "Microsoft.Compute/galleries/images/versions/read", "Microsoft.Compute/galleries/images/versions/write", "Microsoft.Compute/galleries/images/write", "Microsoft.Compute/galleries/read", "Microsoft.Compute/galleries/write", "Microsoft.Compute/hostGroups/hosts/read", "Microsoft.Compute/hostGroups/read", "Microsoft.Compute/hostGroups/write", "Microsoft.Compute/snapshots/beginGetAccess/action", "Microsoft.Compute/snapshots/delete", "Microsoft.Compute/snapshots/endGetAccess/action", "Microsoft.Compute/snapshots/read", "Microsoft.Compute/snapshots/write", "Microsoft.Compute/virtualMachines/deallocate/action", "Microsoft.Compute/virtualMachines/delete", "Microsoft.Compute/virtualMachines/read", "Microsoft.Compute/virtualMachines/restart/action", "Microsoft.Compute/virtualMachines/start/action", "Microsoft.Compute/virtualMachines/write", "Microsoft.Network/networkInterfaces/delete", "Microsoft.Network/networkInterfaces/join/action", "Microsoft.Network/networkInterfaces/read", "Microsoft.Network/networkInterfaces/write", "Microsoft.Network/networkSecurityGroups/delete", "Microsoft.Network/networkSecurityGroups/join/action", "Microsoft.Network/networkSecurityGroups/read", "Microsoft.Network/networkSecurityGroups/write", "Microsoft.Network/virtualNetworks/subnets/read", "Microsoft.Network/virtualNetworks/read", "Microsoft.Network/virtualNetworks/subnets/join/action", "Microsoft.Resources/deployments/operationstatuses/read", "Microsoft.Resources/deployments/read", "Microsoft.Resources/deployments/validate/action", "Microsoft.Resources/deployments/write", "Microsoft.Resources/deployments/delete", "Microsoft.Resources/subscriptions/resourceGroups/read", "Microsoft.Resources/subscriptions/resourceGroups/write", "Microsoft.Resources/subscriptions/resourceGroups/delete", "Microsoft.Storage/storageAccounts/delete", "Microsoft.Storage/storageAccounts/listKeys/action", "Microsoft.Storage/storageAccounts/read", "Microsoft.Storage/storageAccounts/write", "Microsoft.Resources/templateSpecs/read", "Microsoft.Resources/templateSpecs/versions/read" ], "NotActions": [], "DataActions": [], "NotDataActions": [] }
Save the JSON as Citrix-custom-contributor.json and create the custom role in PowerShell:
New-AzRoleDefinition -InputFile Citrix-custom-contributor.json
When you assign a role to your service principal over subscription scope, the service principal has access to resources in the full subscription. Only with subscription scope, the service principal can create resource groups so that you don't need to prepare resource groups for your catalogs. Besides, the service principal can directly access all the resources required for the ARM plugin such as master image, virtual network, etc. The disadvantage is that the ARM Plugin may have permissions to resources in the subscription that are owned by unrelated services.
Service principal with resource group scope gives the ARM plugin access to resources in resource groups specified by you. However, you need to prepare one resource group into which machines are to be provisioned for each catalog. The scope should include resource groups that the ARM plugin will create catalogs' objects into and resource groups containing resources used to provision catalogs, such as master image, virtual network, etc.
After creating a service principal with resource group scope and an Azure hosting connection,
<CustomProperties xmlns="http://schemas.citrix.com/2014/xd/machinecreation" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Property xsi:type="StringProperty" Name="StorageAccountType" Value="Standard_LRS" /> <Property xsi:type="StringProperty" Name="ResourceGroups" Value="xd-sales-1" /> </CustomProperties>
A service principal assigned a Contributor role at subscription scope has full access to manage all resources in the subscription. You don't need to add any permission to get future features. Besides, Citrix Studio supports creating a service principal with a Contributor role at subscription scope. However, the Contributor role means the service principal has more permissions than it needs and subscription scope means the service principal can access unrelated resources.
Considering using a service principal with a Contributor role at subscription scope if:
If you select the "Create New" option in the hosting connection creation wizard, Citrix Studio will create a service principal with the Contributor role at subscription scope. Besides, you can create the service principal with the same role and scope with the following PowerShell script:
// Replace the variables with your own application name and subscription id. $applicationName = "Subscription-Contributor-App" $subscriptionId = "4adecfb9-0a3c-4d6a-8589-3c6fd6b9xxxx" Get-AzSubscription -SubscriptionId $subscriptionId | Select-AzSubscription $AzureADApplication = New-AzADApplication -DisplayName $ApplicationName New-AzADServicePrincipal -ApplicationId $AzureADApplication.AppId New-AzRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $AzureADApplication.App
A service principal assigned the Contributor role at resource group scope has full access to manage all resources in the specified resource groups. Other resource groups are inaccessible to the service principal. You don't need to add any permission to get future features. However, you need to supply resource groups used for provisioning catalogs and assign a Contributor role to each resource group. You need to change the scope if you have a new resource group for a new machine catalog.
Considering using a service principal with a Contributor role at resource group scope if:
your Azure subscription is hosting multiple unrelated services.
your company has security standards that require access control at a fine-grained level.
Here's an example to create a service principal with a Contributor role at resource group scope in PowerShell.
// Replace the variables with your own application name, subscription id and resource groups. $applicationName = "ResourceGroup-Contributor-App" $subscriptionId = "4adecfb9-0a3c-4d6a-8589-3c6fd6b9xxxx" $resourceGroups = @("image-resourcegroup","network-resourcegroup","sales-machine-resourcegroup") Get-AzSubscription -SubscriptionId $subscriptionId | Select-AzSubscription $AzureADApplication = New-AzADApplication -DisplayName $ApplicationName New-AzADServicePrincipal -ApplicationId $AzureADApplication.AppId foreach($rg in $resourceGroups){ New-AzRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $AzureADApplication.AppId –scope "/subscriptions/$SubscriptionId/resourcegroups/$rg" }
A service principal assigned a custom role at subscription scope has specified permissions in the subscription. You can control the permissions easily by changing the role definition in the Azure portal. However, the permissions you assigned to the service principal also apply to resources owned by unrelated services. And you also need to add permissions to the custom role for future features.
Considering using a service principal with a custom role at subscription scope if:
Here's an example to create a service principal with the previous custom role Citrix-Custom-Contributor at subscription scope in PowerShell:
Note: You should create your custom role in advance before running the following PowerShell cmdlets. Refer to the Custom Role section .
// Replace the variables with your own application name, subscription id and custom role name. $applicationName = "Subscription-CustomContributor-App" $subscriptionId = "4adecfb9-0a3c-4d6a-8589-3c6fd6b9xxxx" $customRoleName= "Citrix-Custom-Contributor" Get-AzSubscription -SubscriptionId $subscriptionId | Select-AzSubscription $AzureADApplication = New-AzADApplication -DisplayName $ApplicationName New-AzADServicePrincipal -ApplicationId $AzureADApplication.AppId New-AzRoleAssignment -RoleDefinitionName $customRoleName -ServicePrincipalName $AzureADApplication.AppId –scope "/subscriptions/$SubscriptionId"
A service principal assigned a custom role at resource group scope has specified permissions in the specified resource groups. You can grant the minimum set of permissions to the service principal in the resource groups dedicated to the ARM plugin. However, you need to manage resource groups included in the scope and add permissions to the custom role for future features.
Considering using a service principal with a custom role at resource group scope if:
Here's an example to create a service principal with the previous custom role Citrix-Custom-Contributor at resource group scope in PowerShell:
Note: You should create your custom role in advance before running the following PowerShell cmdlets. Refer to the Custom Role section.
// Replace the variables with your own application name, subscription id, resource groups and custom role name. $applicationName = "ResourceGroup-CustomContributor-App" $subscriptionId = "4adecfb9-0a3c-4d6a-8589-3c6fd6b9xxxx" $resourceGroups = @("image-resourcegroup","network-resourcegroup","sales-machine-resourcegroup") $customRoleName= "Citrix-Custom-Contributor" Get-AzSubscription -SubscriptionId $subscriptionId | Select-AzSubscription $AzureADApplication = New-AzADApplication -DisplayName $ApplicationName New-AzADServicePrincipal -ApplicationId $AzureADApplication.AppId foreach($rg in $resourceGroups){ New-AzRoleAssignment -RoleDefinitionName $customRoleName -ServicePrincipalName $AzureADApplication.AppId –scope "/subscriptions/$SubscriptionId/resourcegroups/$rg" }
Note: Citrix Studio supports creating a new hosting connection with an existing service principal regardless of the role and scope associated with the service principal. More details can be found here.