Deploy SPFx app using pipeline's Workload Identity federation
This article is based on the Azure DevOps Pipeline with Workload Identity Federation Series’ Articles
In October 2023, Azure DevOps introduced a new option for creating Service Connections: Workload Identity federation.
This feature allows pipelines to access Microsoft Entra protected resources (such as Azure, Microsoft Graph, Microsoft 3655) without requiring client secrets or certificates, eliminating the need for certificate or secret rotation.
Configuration
Service connections using workload identity federation authenticate with Microsoft Entra-protected resources using context of a Service Principal in your Azure AD (Microsoft Entra).
The Service Principal must first be authorized to access the necessary resources. It can be done using the usual methods, such as the Azure Portal, Microsoft CLI, PowerShell, or PnP PowerShell.
To navigate to the App Registration page in Azure, click the “Manage Service Principal” link on the Service Connection page. Here, you can find all the necessary details to grant the Service Principal access to APIs.
Depending on the actions you intend to execute, you’ll need to assign different API permissions to different resources.
If you want to use your pipeline to deploy SPFx solution, the minimum required permission level is Sites.Selected
Application permissions for SharePoint API.
In this case, you will also need to grant FullControl
to the AppCatalog site, using the client Id and display name of the Service Principal.
To access the properties of the Service Principal use the “Managed application in local directory” link on the Application Registration page.
Once you obtained the client id and display name, use the Grant-PnPAzureADAppSitePermission
script, or other method of your choice, to grant the service principal necessary permissions:
Grant-PnPAzureADAppSitePermission -AppId $clientId -DisplayName $clientDisplayName -Permissions FullControl
Make sure you always grant the minimum required permissions. For accessing existing resources within a SharePoint site (e.g. publish a change log), consider using new *.SelectedOperations.*
scopes, if possible.
See Overview of Selected permissions in OneDrive and SharePoint.
Deploying SPFx solutions to tenant-level app catalog
Now that your pipeline is using Service Connection with Managed Identity Federation, you are ready to update your deployment scripts and to (finally!) stop using secrets and certificates.
You will need to make a few small changes in your script:
- change your tasks to use AzurePowerShell instead of PowerShell / bash
- obtain Access Token and use it when establishing connections
[!IMPORTANT] When using
Connect-PnPOnline -AccessToken
, PnP PowerShell will not acquire tokens dynamically and if the token expires (typically after 1 hour) cmdlets will fail to work using this method.
deploy-spfx.yaml
variables:
- name: tenantName
value: "contoso" #update with your tenant name
- name: siteName
value: "AppCatalog"
- name: spfxPackage
value: "spfx/spfx-solution.sppkg" #update with a path to your package
steps:
- task: AzurePowerShell@5
name: DeploySPFx
inputs:
azureSubscription: DEV_Connection
azurePowerShellVersion: latestVersion
ScriptType: InlineScript
Inline: |
Write-Host "##[group]Install PS modules"
############## If you are using ubuntu-latest, you may need to uncomment the following lines to avoid the
# 'The term 'Install-Module' is not recognized as a name of a cmdlet, function, script file, or executable program.' error.
# See https://dev.to/kkazala/azure-devops-and-the-term-install-module-is-not-recognized-issue-30ck
##############
# Write-Host "##[command] Get Module PowerShellGet"
# Get-Module -Name PowerShellGet -ListAvailable
# Write-Host "##[command] Get Module PowerShellGet"
# Get-Module -Name Microsoft.PowerShell.PSResourceGet -ListAvailable
Write-Host "##[command] Install PnP.PowerShell"
Install-Module -Name PnP.PowerShell -Scope CurrentUser -SkipPublisherCheck -Force
Write-Host "##[endgroup]"
############## You may use the following section to retrieve details of the account used to execute the pipeline
# You probably won't use it productively :)
##############
# Write-Host "##[group]Who am I"
# $azContext = (Get-AzContext).Account.Id
# $sp = Get-AzADServicePrincipal -ApplicationId $azContext
# Write-Host "##[debug] ServicePrincipal: $($sp.Id)"
# Write-Host "##[endgroup]"
$url = "https://$(tenantName).sharepoint.com"
$path="$(Build.SourcesDirectory)/$(spfxPackage)"
try {
$azAccessToken = Get-AzAccessToken -ResourceUrl $url
$conn = Connect-PnPOnline -Url "$url/sites/$(siteName)" -AccessToken $azAccessToken.Token -ReturnConnection
Write-Host "##[debug] Get-PnPConnection $($conn.Url)
$packageInSite = Add-PnPApp -Path $path -Overwrite -Publish -SkipFeatureDeployment -Connection $conn
}
catch {
Write-Host "##[error]$($_.Exception.Message)"
}
displayName: Deploy spfx
Why the
Get-Module -Name PowerShellGet -ListAvailable
?If you are using ubuntu-latest image, which comes with PowerShell 7.4.3, it will include Microsoft.PowerShell.PSResourceGet installed side-by-side with PowerShellGet v2.2.5 and PackageManagement v1.4.8.1. This somehow lead to
"The term 'Install-Module' is not recognized"
errors appearing randomly. These extraGet-Module
calls appear to solve the issue.
Resources
- Connect-PnPOnline -AccessToken
- Create an Azure Resource Manager service connection that uses workload identity federation
- Azure DevOps and “The term ‘Install-Module’ is not recognized” issue