Create a profile container with Azure Files and Azure Active Directory (preview)
Important
Storing FSLogix profiles on Azure Files for Azure Active Directory (AD)-joined VMs is currently in public preview. This preview version is provided without a service level agreement, and is not recommended for production workloads. Certain features might not be supported or might have constrained capabilities. For more information, see Supplemental Terms of Use for Microsoft Azure Previews.
In this article, you'll learn how to create an Azure Files share to store FSLogix profiles that can be accessed by hybrid user identities authenticated with Azure Active Directory (AD). Azure AD users can now access an Azure file share using Kerberos authentication. This configuration uses Azure AD to issue the necessary Kerberos tickets to access the file share with the industry-standard SMB protocol. Your end-users can access Azure file shares over the internet without requiring a line-of-sight to domain controllers from Hybrid Azure AD-joined and Azure AD-joined VMs.
In this article, you'll learn how to:
- Configure an Azure storage account for authentication using Azure AD.
- Configure the permissions on an Azure Files share.
- Configure your session hosts to store FSLogix user profiles on Azure Files.
Prerequisites
The Azure AD Kerberos functionality is only available on the following operating systems:
- Windows 11 Enterprise single or multi-session.
- Windows 10 Enterprise single or multi-session, versions 2004 or later with the latest cumulative updates installed, especially the KB5007253 - 2021-11 Cumulative Update Preview for Windows 10.
- Windows Server, version 2022 with the latest cumulative updates installed, especially the KB5007254 - 2021-11 Cumulative Update Preview for Microsoft server operating system version 21H2.
The user accounts must be hybrid user identities, which means you'll also need Active Directory Domain Services (AD DS) and Azure AD Connect. You must create these accounts in Active Directory and sync them to Azure AD. The service doesn't currently support environments where users are managed with Azure AD and optionally synced to Azure AD Directory Services.
To assign Azure Role-Based Access Control (RBAC) permissions for the Azure file share to a user group, you must create the group in Active Directory and sync it to Azure AD.
You must disable multi-factor authentication (MFA) on the Azure AD app representing the storage account.
Important
This feature is currently only supported in the Azure Public cloud.
Configure your Azure storage account
Start by creating an Azure Storage account if you don't already have one.
Note
Your Azure Storage account can't authenticate with both Azure AD and a second method like Active Directory Domain Services (AD DS) or Azure AD DS. You can only use one authentication method.
Follow the instructions in the following sections to configure Azure AD authentication, configure the Azure AD service principal, and set the API permission for your storage account.
Configure Azure AD authentication on your Azure Storage account
Install the Azure Storage PowerShell module. This module provides management cmdlets for Azure Storage resources. It's required to create storage accounts, enable Azure AD authentication on the storage account, and retrieve the storage account’s Kerberos keys. To install the module, open PowerShell and run the following command:
Install-Module -Name Az.StorageInstall the Azure AD PowerShell module. This module provides management cmdlets for Azure AD administrative tasks such as user and service principal management. To install this module, open PowerShell, then run the following command:
Install-Module -Name AzureADFor more information, see Install the Azure AD PowerShell module.
Set the required variables for your tenant, subscription, storage account name and resource group name by running the following PowerShell cmdlets, replacing the values with the ones relevant to your environment.
$tenantId = "<MyTenantId>" $subscriptionId = "<MySubscriptionId>" $resourceGroupName = "<MyResourceGroup>" $storageAccountName = "<MyStorageAccount>"Enable Azure AD authentication on your storage account by running the following PowerShell cmdlets:
Connect-AzAccount -Tenant $tenantId -SubscriptionId $subscriptionId $Uri = ('https://management.azure.com/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Storage/storageAccounts/{2}?api-version=2021-04-01' -f $subscriptionId, $resourceGroupName, $storageAccountName); $json = @{properties=@{azureFilesIdentityBasedAuthentication=@{directoryServiceOptions="AADKERB"}}}; $json = $json | ConvertTo-Json -Depth 99 $token = $(Get-AzAccessToken).Token $headers = @{ Authorization="Bearer $token" } try { Invoke-RestMethod -Uri $Uri -ContentType 'application/json' -Method PATCH -Headers $Headers -Body $json; } catch { Write-Host $_.Exception.ToString() Write-Error -Message "Caught exception setting Storage Account directoryServiceOptions=AADKERB: $_" -ErrorAction Stop }Generate the kerb1 storage account key for your storage account by running the following PowerShell command:
New-AzStorageAccountKey -ResourceGroupName $resourceGroupName -Name $storageAccountName -KeyName kerb1 -ErrorAction Stop
Configure the Azure AD service principal and application
To enable Azure AD authentication on a storage account, you need to create an Azure AD application to represent the storage account in Azure AD. This configuration won't be available in the Azure portal during public preview. To create the application using PowerShell, follow these steps:
Set the password (service principal secret) based on the Kerberos key of the storage account. The Kerberos key is a password shared between Azure AD and Azure Storage. Kerberos derives the password's value from the first 32 bytes of the storage account’s kerb1 key. To set the password, run the following cmdlets:
$kerbKey1 = Get-AzStorageAccountKey -ResourceGroupName $resourceGroupName -Name $storageAccountName -ListKerbKey | Where-Object { $_.KeyName -like "kerb1" } $aadPasswordBuffer = [System.Linq.Enumerable]::Take([System.Convert]::FromBase64String($kerbKey1.Value), 32); $password = "kk:" + [System.Convert]::ToBase64String($aadPasswordBuffer);Connect to Azure AD and retrieve the tenant information by running the following cmdlets:
Connect-AzureAD $azureAdTenantDetail = Get-AzureADTenantDetail; $azureAdTenantId = $azureAdTenantDetail.ObjectId $azureAdPrimaryDomain = ($azureAdTenantDetail.VerifiedDomains | Where-Object {$_._Default -eq $true}).NameGenerate the service principal names for the Azure AD service principal by running these cmdlets:
$servicePrincipalNames = New-Object string[] 3 $servicePrincipalNames[0] = 'HTTP/{0}.file.core.windows.net' -f $storageAccountName $servicePrincipalNames[1] = 'CIFS/{0}.file.core.windows.net' -f $storageAccountName $servicePrincipalNames[2] = 'HOST/{0}.file.core.windows.net' -f $storageAccountNameCreate an application for the storage account by running this cmdlet:
$application = New-AzureADApplication -DisplayName $storageAccountName -IdentifierUris $servicePrincipalNames -GroupMembershipClaims "All";Create a service principal for the storage account by running this cmdlet:
$servicePrincipal = New-AzureADServicePrincipal -AccountEnabled $true -AppId $application.AppId -ServicePrincipalType "Application";Set the password for the storage account's service principal by running the following cmdlets.
$Token = ([Microsoft.Open.Azure.AD.CommonLibrary.AzureSession]::AccessTokens['AccessToken']).AccessToken $Uri = ('https://graph.windows.net/{0}/{1}/{2}?api-version=1.6' -f $azureAdPrimaryDomain, 'servicePrincipals', $servicePrincipal.ObjectId) $json = @' { "passwordCredentials": [ { "customKeyIdentifier": null, "endDate": "<STORAGEACCOUNTENDDATE>", "value": "<STORAGEACCOUNTPASSWORD>", "startDate": "<STORAGEACCOUNTSTARTDATE>" }] } '@ $now = [DateTime]::UtcNow $json = $json -replace "<STORAGEACCOUNTSTARTDATE>", $now.AddHours(-12).ToString("s") $json = $json -replace "<STORAGEACCOUNTENDDATE>", $now.AddMonths(6).ToString("s") $json = $json -replace "<STORAGEACCOUNTPASSWORD>", $password $Headers = @{'authorization' = "Bearer $($Token)"} try { Invoke-RestMethod -Uri $Uri -ContentType 'application/json' -Method Patch -Headers $Headers -Body $json Write-Host "Success: Password is set for $storageAccountName" } catch { Write-Host $_.Exception.ToString() Write-Host "StatusCode: " $_.Exception.Response.StatusCode.value Write-Host "StatusDescription: " $_.Exception.Response.StatusDescription }Important
This password expires every six months, so you must update it by following the steps in Update the service principal's password.
Set the API permissions on the newly created application
You can configure the API permissions from the Azure portal by following these steps:
- Open Azure Active Directory.
- Select App registrations on the left pane.
- Select All Applications.
- Select the application with the name matching your storage account.
- Select API permissions in the left pane.
- Select + Add a permission.
- Select Microsoft Graph at the top of the page.
- Select Delegated permissions.
- Select openid and profile under the OpenID permissions group.
- Select User.Read under the User permission group.
- Select Add permissions at the bottom of the page.
- Select Grant admin consent for "DirectoryName".
Disable multi-factor authentication on the storage account
Azure AD Kerberos doesn't support using MFA to access Azure Files shares configured with Azure AD Kerberos. You must exclude the Azure AD app representing your storage account from your MFA conditional access policies if they apply to all apps. The storage account app should have the same name as the storage account in the conditional access exclusion list.
Important
If you don't exclude MFA policies from the storage account app, the FSLogix profiles won't be able to attach. Trying to map the file share using net use will result in an error message that says "System error 1327: Account restrictions are preventing this user from signing in. For example: blank passwords aren't allowed, sign-in times are limited, or a policy restriction has been enforced."
Configure your Azure Files share
To get started, create an Azure Files share under your storage account to store your FSLogix profiles if you haven't already.
Follow the instructions in the following sections to configure the share-level and directory-level permissions on your Azure Files share to provide the right level of access to your users.
Assign share-level permissions
You must grant your users access to the file share before they can use it. There are two ways you can assign share-level permissions: either assign them to specific Azure AD users or user groups, or you can assign them to all authenticated identities as a default share-level permission. To learn more about assigning share-level permissions, see Assign share-level permissions to an identity.
All users that need to have FSLogix profiles stored on the storage account you're using must be assigned the Storage File Data SMB Share Contributor role.
Important
Azure Virtual Desktop currently only supports assigning specific permissions to hybrid users and user groups. Users and user groups must be managed in Active Directory and synced to Azure AD using Azure AD Connect.
Assign directory level access permissions
To prevent users from accessing the user profile of other users, you must also assign directory-level permissions. This section will give you a step-by-step guide for how to configure the permissions.
Important
Without proper directory level permissions in place, a user can delete the user profile or access the personal information of a different user. It's important to make sure users have proper permissions to prevent accidental deletion from happening.
You can set permissions (ACLs) for files and directories using either the icacls command-line utility or Windows Explorer. The system you use to configure the permissions must meet the following requirements:
- The version of Windows meets the supported OS requirements defined in the Prerequisites section.
- Is Azure AD-joined or Hybrid Azure AD-joined to the same Azure AD tenant as the storage account.
- Has line-of-sight to the domain controller.
- Is domain-joined to your Active Directory (Windows Explorer method only).
During the public preview, configuring permissions using Windows Explorer also requires storage account configuration. You can skip this configuration step when using icacls.
To configure your storage account:
On a device that's domain-joined to the Active Directory, install the ActiveDirectory PowerShell module if you haven't already.
Set the required variables for your tenant, subscription, storage account name and resource group name by running the following PowerShell cmdlets, replacing the values with the ones relevant to your environment. You can skip this step if you've already set these values.
$tenantId = "<MyTenantId>" $subscriptionId = "<MySubscriptionId>" $resourceGroupName = "<MyResourceGroup>" $storageAccountName = "<MyStorageAccount>"Set the storage account's ActiveDirectoryProperties to support the Shell experience. Because Azure AD doesn't currently support configuring ACLs in Shell, it must instead rely on Active Directory. To configure Shell, run the following cmdlets in PowerShell:
Connect-AzAccount -Tenant $tenantId -SubscriptionId $subscriptionId $AdModule = Get-Module ActiveDirectory; if ($null -eq $AdModule) { Write-Error "Please install and/or import the ActiveDirectory PowerShell module." -ErrorAction Stop; } $domainInformation = Get-ADDomain $Domain = $domainInformation.DnsRoot $domainGuid = $domainInformation.ObjectGUID.ToString() $domainName = $domainInformation.DnsRoot $domainSid = $domainInformation.DomainSID.Value $forestName = $domainInformation.Forest $netBiosDomainName = $domainInformation.DnsRoot $azureStorageSid = $domainSid + "-123454321"; Write-Verbose "Setting AD properties on $storageAccountName in $resourceGroupName : ` EnableActiveDirectoryDomainServicesForFile=$true, ActiveDirectoryDomainName=$domainName, ` ActiveDirectoryNetBiosDomainName=$netBiosDomainName, ActiveDirectoryForestName=$($domainInformation.Forest) ` ActiveDirectoryDomainGuid=$domainGuid, ActiveDirectoryDomainSid=$domainSid, ` ActiveDirectoryAzureStorageSid=$azureStorageSid" $Uri = ('https://management.azure.com/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Storage/storageAccounts/{2}?api-version=2021-04-01' -f $subscriptionId, $resourceGroupName, $storageAccountName); $json= @{ properties= @{azureFilesIdentityBasedAuthentication= @{directoryServiceOptions="AADKERB"; activeDirectoryProperties=@{domainName="$($domainName)"; netBiosDomainName="$($netBiosDomainName)"; forestName="$($forestName)"; domainGuid="$($domainGuid)"; domainSid="$($domainSid)"; azureStorageSid="$($azureStorageSid)"} } } }; $json = $json | ConvertTo-Json -Depth 99 $token = $(Get-AzAccessToken).Token $headers = @{ Authorization="Bearer $token" } try { Invoke-RestMethod -Uri $Uri -ContentType 'application/json' -Method PATCH -Headers $Headers -Body $json } catch { Write-Host $_.Exception.ToString() Write-Host "Error setting Storage Account AD properties. StatusCode:" $_.Exception.Response.StatusCode.value__ Write-Host "Error setting Storage Account AD properties. StatusDescription:" $_.Exception.Response.StatusDescription Write-Error -Message "Caught exception setting Storage Account AD properties: $_" -ErrorAction Stop }
Enable Azure AD Kerberos functionality by configuring the group policy or registry value in the following list:
- Group policy:
Administrative Templates\System\Kerberos\Allow retrieving the Azure AD Kerberos Ticket Granting Ticket during logon - Registry value:
reg add HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters /v CloudKerberosTicketRetrievalEnabled /t REG_DWORD /d 1
Next, make sure you can retrieve a Kerberos Ticket Granting Ticket (TGT) by following these instructions:
Open a command window.
Run the following command:
dsregcmd /RefreshPrtLock and then unlock your device using the same user account.
In the command window, run the following commands:
klist purge klist get krbtgt klistConfirm you have a Kerberos TGT by looking for an item with a server property of
krbtgt/KERBEROS.MICROSOFTONLINE.COM @ KERBEROS.MICROSOFTONLINE.COM.Verify you can mount the network share by running the following command in your command window:
net use <DriveLetter>: \\<storage-account-name>.file.core.windows.net\<fIle-share-name>
Finally, follow the instructions in Configure directory and file level permissions to finish configuring your permissions with icacls or Windows Explorer. Learn more about the recommended list of permissions for FSLogix profiles at Configure the storage permissions for profile containers.
Configure the session hosts
To access Azure file shares from an Azure AD-joined VM for FSLogix profiles, you must configure the session hosts. To configure session hosts:
Enable the Azure AD Kerberos functionality by configuring the group policy or registry value with the values in the following list. Once you've configured those values, restart your system to make the changes take effect.
- Group policy:
Administrative Templates\System\Kerberos\Allow retrieving the Azure AD Kerberos Ticket Granting Ticket during logon - Registry value:
reg add HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters /v CloudKerberosTicketRetrievalEnabled /t REG_DWORD /d 1
- Group policy:
When you use Azure AD with a roaming profile solution like FSLogix, the credential keys in Credential Manager must belong to the profile that's currently loading. This will let you load your profile on many different VMs instead of being limited to just one. To enable this setting, create a new registry value by running the following command:
reg add HKLM\Software\Policies\Microsoft\AzureADAccount /v LoadCredKeyFromProfile /t REG_DWORD /d 1
Note
The session hosts don't need network line-of-sight to the domain controller.
Configure FSLogix on the session host
This section will show you how to configure a VM with FSLogix. You'll need to follow these instructions every time you configure a session host. There are several options available that ensure the registry keys are set on all session hosts. You can set these options in an image or configure a group policy.
To configure FSLogix:
Update or install FSLogix on your session host, if needed.
Note
If the session host is created using the Azure Virtual Desktop service, FSLogix should already be pre-installed.
Follow the instructions in Configure profile container registry settings to create the Enabled and VHDLocations registry values. Set the value of VHDLocations to
\\<Storage-account-name>.file.core.windows.net\<file-share-name>.
Test your deployment
Once you've installed and configured FSLogix, you can test your deployment by signing in with a user account that's been assigned to an application group on the host pool. The user account you sign in with must have permission to use the file share.
If the user has signed in before, they'll have an existing local profile that the service will use during this session. To avoid creating a local profile, either create a new user account to use for tests or use the configuration methods described in Tutorial: Configure profile container to redirect user profiles to enable the DeleteLocalProfileWhenVHDShouldApply setting.
Finally, test the profile to make sure that it works:
Open the Azure portal and sign in with an administrative account.
From the sidebar, select Storage accounts.
Select the storage account you configured for your session host pool.
From the sidebar, select File shares.
Select the file share you configured to store the profiles.
If everything's set up correctly, you should see a directory with a name that's formatted like this:
<user SID>_<username>.
Update the service principal's password
The service principal's password will expire every six months. To update the password:
Install the Azure Storage and Azure AD PowerShell module. To install the modules, open PowerShell and run the following commands:
Install-Module -Name Az.Storage Install-Module -Name AzureADSet the required variables for your tenant, subscription, storage account name, and resource group name by running the following PowerShell cmdlets, replacing the values with the ones relevant to your environment.
$tenantId = "<MyTenantId>" $subscriptionId = "<MySubscriptionId>" $resourceGroupName = "<MyResourceGroup>" $storageAccountName = "<MyStorageAccount>"Generate a new kerb1 key and password for the service principal by running this command:
Connect-AzAccount -Tenant $tenantId -SubscriptionId $subscriptionId $kerbKeys = New-AzStorageAccountKey -ResourceGroupName $resourceGroupName -Name $storageAccountName -KeyName "kerb1" -ErrorAction Stop | Select-Object -ExpandProperty Keys $kerbKey = $kerbKeys | Where-Object { $_.KeyName -eq "kerb1" } | Select-Object -ExpandProperty Value $azureAdPasswordBuffer = [System.Linq.Enumerable]::Take([System.Convert]::FromBase64String($kerbKey), 32); $password = "kk:" + [System.Convert]::ToBase64String($azureAdPasswordBuffer);Connect to Azure AD and retrieve the tenant information, application, and service principal by running the following cmdlets:
Connect-AzureAD $azureAdTenantDetail = Get-AzureADTenantDetail; $azureAdTenantId = $azureAdTenantDetail.ObjectId $azureAdPrimaryDomain = ($azureAdTenantDetail.VerifiedDomains | Where-Object {$_._Default -eq $true}).Name $application = Get-AzureADApplication -Filter "DisplayName eq '$($storageAccountName)'" -ErrorAction Stop; $servicePrincipal = Get-AzureADServicePrincipal -Filter "AppId eq '$($application.AppId)'" if ($servicePrincipal -eq $null) { Write-Host "Could not find service principal corresponding to application with app id $($application.AppId)" Write-Error -Message "Make sure that both service principal and application exist and are correctly configured" -ErrorAction Stop }Set the password for the storage account's service principal by running the following cmdlets.
$Token = ([Microsoft.Open.Azure.AD.CommonLibrary.AzureSession]::AccessTokens['AccessToken']).AccessToken; $Uri = ('https://graph.windows.net/{0}/{1}/{2}?api-version=1.6' -f $azureAdPrimaryDomain, 'servicePrincipals', $servicePrincipal.ObjectId) $json = @' { "passwordCredentials": [ { "customKeyIdentifier": null, "endDate": "<STORAGEACCOUNTENDDATE>", "value": "<STORAGEACCOUNTPASSWORD>", "startDate": "<STORAGEACCOUNTSTARTDATE>" }] } '@ $now = [DateTime]::UtcNow $json = $json -replace "<STORAGEACCOUNTSTARTDATE>", $now.AddHours(-12).ToString("s") $json = $json -replace "<STORAGEACCOUNTENDDATE>", $now.AddMonths(6).ToString("s") $json = $json -replace "<STORAGEACCOUNTPASSWORD>", $password $Headers = @{'authorization' = "Bearer $($Token)"} try { Invoke-RestMethod -Uri $Uri -ContentType 'application/json' -Method Patch -Headers $Headers -Body $json Write-Host "Success: Password is set for $storageAccountName" } catch { Write-Host $_.Exception.ToString() Write-Host "StatusCode: " $_.Exception.Response.StatusCode.value Write-Host "StatusDescription: " $_.Exception.Response.StatusDescription }
Disable Azure AD authentication on your Azure Storage account
If you need to disable Azure AD authentication on your storage account:
Set the required variables for your tenant, subscription, storage account name and resource group name by running the following PowerShell cmdlets, replacing the values with the ones relevant to your environment.
$tenantId = "<MyTenantId>" $subscriptionId = "<MySubscriptionId>" $resourceGroupName = "<MyResourceGroup>" $storageAccountName = "<MyStorageAccount>"Run the following cmdlets in PowerShell to disable Azure AD authentication on your storage account:
Connect-AzAccount -Tenant $tenantId -SubscriptionId $subscriptionId $Uri = ('https://management.azure.com/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Storage/storageAccounts/{2}?api-version=2021-04-01' -f $subscriptionId, $resourceGroupName, $storageAccountName); $json = @{properties=@{azureFilesIdentityBasedAuthentication=@{directoryServiceOptions="None"}}}; $json = $json | ConvertTo-Json -Depth 99 $token = $(Get-AzAccessToken).Token $headers = @{ Authorization="Bearer $token" } try { Invoke-RestMethod -Uri $Uri -ContentType 'application/json' -Method PATCH -Headers $Headers -Body $json; } catch { Write-Host $_.Exception.ToString() Write-Host "Error setting Storage Account directoryServiceOptions=None. StatusCode:" $_.Exception.Response.StatusCode.value__ Write-Host "Error setting Storage Account directoryServiceOptions=None. StatusDescription:" $_.Exception.Response.StatusDescription Write-Error -Message "Caught exception setting Storage Account directoryServiceOptions=None: $_" -ErrorAction Stop }
Next steps
- To troubleshoot FSLogix, see this troubleshooting guide.
- To configure FSLogix profiles on Azure Files with Azure Active Directory Domain Services, see Create a profile container with Azure Files and Azure AD DS.
- To configure FSLogix profiles on Azure Files with Active Directory Domain Services, see Create a profile container with Azure Files and AD DS.
Tilbakemeldinger
Send inn og vis tilbakemelding for