Deployment error - client does not have authorization to perform action
Closed this issue · 24 comments
@leaubl - This error message likely means that the account being used to run the script does not have the necessary privileges needed from an Azure AD perspective to initialise the Service Principal. The Service Principal is used during the deployment process to create the Azure Purview account.
After MS Support’s advice and assistance to find out the Service Principal of object id '5627f484-079f-475d-bcd0-784b3039c1b1', grant the Service Principal Contributor role at Subscription level and rerun the deployment, purview account is created.
However, the deployment did not create the below Azure Resources as stated. Please advise how to proceed from here. Thanks!
@leaubl - If you navigate to the target Resource Group and click Deployments, what does the error message say?
@leaubl - I suspect the Service Principal is not being created properly, likely due to lack of permissions. Can you try copying the code snippet below, replace YOUR_SUBSCRIPTION_ID and YOUR_RESOURCE_GROUP_NAME with your values, and paste the updated code snippet into Cloud Shell. See what error message comes back.
function createServicePrincipal([string]$subscriptionId, [string]$resourceGroupName, [string]$suffix) {
$scope = "/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}"
$sp = New-AzADServicePrincipal -DisplayName "pvDemoServicePrincipal-${suffix}" -Role "Owner" -Scope $scope
Return $sp
}
$suffix = -join ((48..57) + (97..122) | Get-Random -Count 5 | ForEach-Object {[char]$_})
$subscriptionId = "YOUR_SUBSCRIPTION_ID"
$resourceGroupName = "YOUR_RESOURCE_GROUP_NAME"
$sp = createServicePrincipal $subscriptionId $resourceGroupName $suffix
hi Taygan,
Any update, please. Thanks.
@leaubl - The snippet you posted looks OK, the issue must be further down the script. We can copy/paste snippets from the PowerShell script to help narrow in on where the problem lies.
- Open Cloud Shell, and copy/paste the function code.
function getUserPrincipalId() {
$principalId = $null
Do {
$emailAddress = Read-Host -Prompt "Please enter your Azure AD email address"
$principalId = (Get-AzAdUser -Mail $emailAddress).id
if ($null -eq $principalId) { $principalId = (Get-AzAdUser -UserPrincipalName $emailAddress).Id }
if ($null -eq $principalId) { Write-Host "Unable to find a user within the Azure AD with email address: ${emailAddress}. Please try again." }
} until($null -ne $principalId)
Return $principalId
}
function selectLocation() {
$locationList='australiaeast', 'brazilsouth', 'canadacentral', 'centralindia', 'eastus', 'eastus2', 'southcentralus', 'southeastasia', 'uksouth', 'westeurope'
$location = Get-Random -InputObject $locationList
Return $location
}
function createServicePrincipal([string]$subscriptionId, [string]$resourceGroupName, [string]$suffix) {
$scope = "/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}"
$sp = New-AzADServicePrincipal -DisplayName "pvDemoServicePrincipal-${suffix}" -Role "Owner" -Scope $scope
Return $sp
}
function getAccessToken([string]$tenantId, [string]$clientId, [string]$clientSecret, [string]$resource) {
$requestAccessTokenUri = "https://login.microsoftonline.com/${tenantId}/oauth2/token"
$body = "grant_type=client_credentials&client_id=${clientId}&client_secret=${clientSecret}&resource=${resource}"
$accessToken = $null
try {
$token = Invoke-RestMethod -Method Post -Uri $requestAccessTokenUri -Body $body -ContentType 'application/x-www-form-urlencoded'
$accessToken = $token.access_token
Write-Host "Access token generated successfully!"
} catch {
Start-Sleep 1
Write-Host "Pending access token..."
}
Return $accessToken
}
function deployTemplate([string]$accessToken, [string]$templateLink, [string]$resourceGroupName, [hashtable]$parameters) {
$randomId = -join ((65..90) + (97..122) | Get-Random -Count 5 | ForEach-Object {[char]$_})
$deploymentName = "deployment-${randomId}"
$scope = "/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}"
$deploymentUri = "https://management.azure.com${scope}/providers/Microsoft.Resources/deployments/${deploymentName}?api-version=2021-04-01"
$deploymentBody = @{
"properties" = @{
"templateLink" = @{
"uri" = $templateLink
}
"parameters" = $parameters
"mode" = "Incremental"
}
}
$params = @{
ContentType = "application/json"
Headers = @{"Authorization"="Bearer ${accessToken}"}
Body = ($deploymentBody | ConvertTo-Json -Depth 9)
Method = "PUT"
URI = $deploymentUri
}
$job = Invoke-RestMethod @params
Return $job
}
function getDeployment([string]$accessToken, [string]$subscriptionId, [string]$resourceGroupName, [string]$deploymentName) {
$params = @{
ContentType = "application/json"
Headers = @{"Authorization"="Bearer ${accessToken}"}
Method = "GET"
URI = "https://management.azure.com/subscriptions/${subscriptionId}/resourcegroups/${resourceGroupName}/providers/Microsoft.Resources/deployments/${deploymentName}?api-version=2021-04-01"
}
$response = Invoke-RestMethod @params
Return $response
}
- Once the functions have been copied, copy/paste one section at a time until an error occurs.
Section 1
# Variables
$tenantId = (Get-AzContext).Tenant.Id
$subscriptionId = (Get-AzContext).Subscription.Id
$principalId = getUserPrincipalId
$suffix = -join ((48..57) + (97..122) | Get-Random -Count 5 | ForEach-Object {[char]$_})
$location = selectLocation
# Create Resource Group
$resourceGroup = New-AzResourceGroup -Name "pvdemo-rg-${suffix}" -Location $location
$resourceGroupName = $resourceGroup.ResourceGroupName
# Create Service Principal
$sp = createServicePrincipal $subscriptionId $resourceGroupName $suffix
$clientId = $sp.AppId
$clientSecret = $sp.PasswordCredentials.SecretText
Section 2
$accessToken = $null
While ($null -eq $accessToken) {
$accessToken = getAccessToken $tenantId $clientId $clientSecret "https://management.core.windows.net/"
}
Section 3
# Create Azure Purview Account (as Service Principal)
$templateLink = "https://raw.githubusercontent.com/tayganr/purviewdemo/main/templates/json/purviewdeploy.json"
$parameters = @{ suffix = @{ value = $suffix } }
$deployment = deployTemplate $accessToken $templateLink $resourceGroupName $parameters
$deploymentName = $deployment.name
Section 4
$progress = ('.', '..', '...')
$provisioningState = ""
While ($provisioningState -ne "Succeeded") {
Foreach ($x in $progress) {
Clear-Host
Write-Host "Deployment 1 of 2 is in progress, this will take approximately 5 minutes"
Write-Host "Running${x}"
Start-Sleep 1
}
$provisioningState = (getDeployment $accessToken $subscriptionId $resourceGroupName $deploymentName).properties.provisioningState
}
Section 5
# Deploy Template
$templateUri = "https://raw.githubusercontent.com/tayganr/purviewdemo/main/templates/json/azuredeploy.json"
$secureSecret = ConvertTo-SecureString -AsPlainText $sp.PasswordCredentials.SecretText
$job = New-AzResourceGroupDeployment `
-Name "pvDemoTemplate-${suffix}" `
-ResourceGroupName $resourceGroupName `
-TemplateUri $templateUri `
-azureActiveDirectoryObjectID $principalId `
-servicePrincipalClientID $clientId `
-servicePrincipalClientSecret $secureSecret `
-suffix $suffix `
-AsJob
$progress = ('.', '..', '...')
While ($job.State -eq "Running") {
Foreach ($x in $progress) {
Clear-Host
Write-Host "Deployment 2 of 2 is in progress, this will take approximately 10 minutes"
Write-Host "Running${x}"
Start-Sleep 1
}
}
Section 6
# # Clean-Up Service Principal
Remove-AzRoleAssignment -ResourceGroupName $resourceGroupName -ObjectId $sp.Id -RoleDefinitionName "Owner"
Remove-AzADServicePrincipal -ObjectId $sp.Id
Remove-AzADApplication -DisplayName $sp.DisplayName
Section 7
# # Clean-Up User Assigned Managed Identity
$configAssignment = Get-AzRoleAssignment -ResourceGroupName $resourceGroupName | Where-Object {$_.DisplayName.Equals("configDeployer")}
Remove-AzRoleAssignment -ResourceGroupName $resourceGroupName -ObjectId $configAssignment.ObjectId -RoleDefinitionName "Contributor"
Section 8
# Deployment Complete
$pv = (Get-AzResource -ResourceGroupName $resourceGroupName -ResourceType "Microsoft.Purview/accounts").Name
Clear-Host
Write-Host "Deployment complete! https://web.purview.azure.com/resource/${pv}`r`nNote: The Azure Data Factory pipeline and Azure Purview scans may still be running, these jobs will complete shortly."
@isdataninja - As documented here: Azure AD to Microsoft Graph migration changes in Azure PowerShell, the Az.Resources
PowerShell module version 5.1.0 introduced changes to the identity-related cmdlets:
Changes to the ServicePrincipal Object
ApplicationId
has been replaced byAppId
Changes to the ServicePrincipal Credential Object
Password
has been replaced bySecretText
I believe you may be running an older version. This can be checked by running the following command:
Get-InstalledModule -Name "Az.Resources"
If we need to, let's raise this as a seperate issue and keep this thread focused on the original topic.
Original Error Message
The client '<client_id>' with object id '<object_id>' does not have authorization to perform action 'Microsoft.Purview/accounts/write' over scope '/subscriptions/<subscription_id>/resourcegroups/<resource_group>/providers/Microsoft.Purview/accounts/<purview_account_name>' or the scope is invalid.
In other words... the Service Principal that was created as part of the template deployment process did not have sufficient permissions to perform the action Microsoft.Purview/accounts/write within the scope of the target Subscription and Resource Group.
@leaubl - Final error message aside (as this may be a seperate issue), was the deployment successful? You can check this by navigating to the resource group and clicking Deployments
. If there is an error message, can you please post it in this thread.
@tayganr deployment is successful with only Purview account created. Other resources are not there.
@tayganr deployment is successful with only Purview account created. Other resources are not there.
@leaubl - If the Azure Purview account is the only resource that deployed, that means at least one of the deployments have failed. If you navigate to the target resource group and then click on "Deployments", it should reveal the failed deployment and related error message.
@leaubl - Based on our remote session, it appears the issue occurs during the section 5 code snippet, where deployment 2 of 2 is initiated to run as a background job. The script as it currently stands, expects the $job variable to immediately be in a "Running" state, but in your case, it is in a "Failed" state and therefore never runs.
I'll work on updating the script to better handle this scenario, in the meantime...
- Can you please copy and paste the code snippets one by one, from the start, until and including section 5.
- Once the code snippet in section 5 has run, can you please paste these new code snippets and share the response.
Command 1
$job.JobStateInfo | Format-List -Property *
Command 2
$job | Format-List -Property *
@tayganr - below is the response for the 2 commands. Thanks.
PS /home/bee> $job.JobStateInfo | Format-List -Property *
State : Failed
Reason :
PS /home/bee> $job | Format-List -Property *
State : Failed
HasMoreData : True
Location : localhost
StatusMessage : Failed
CurrentPSTransaction :
Host : System.Management.Automation.Internal.Host.InternalHost
Command : New-AzResourceGroupDeployment
JobStateInfo : Failed
Finished : System.Threading.ManualResetEvent
InstanceId : c5cdbed9-da77-4afa-ae02-378b225e2b10
Id : 2
Name : Long Running Operation for 'New-AzResourceGroupDeployment' on resource 'pvDemoTemplate-z7aev'
ChildJobs : {}
PSBeginTime : 4/8/2022 1:25:06 AM
PSEndTime : 4/8/2022 1:25:07 AM
PSJobTypeName : AzureLongRunningJob`1
Output : {}
Error : {1:25:07 AM - Error: Code=InvalidTemplateDeployment; Message=The template deployment failed because of policy violation. Please see details for more information.
, 1:25:07 AM - Error: Code=RequestDisallowedByPolicy; Message=Resource 'pvdemoz7aevadls' was disallowed by policy. Policy identifiers: '[{"policyAssignment":{"name":
"CustomPurview","id":"/subscriptions/20d6eaa0-9bc1-49dc-be43-575a36c40752/providers/Microsoft.Authorization/policyAssignments/70b6f06669ce473bbea41bc2"},"policyDefin
ition":{"name":"CustomPurview","id":"/subscriptions/20d6eaa0-9bc1-49dc-be43-575a36c40752/providers/Microsoft.Authorization/policyDefinitions/905bff0f-250c-4e33-8168-
63b53e62e098"}}]'.
, The deployment validation failed}
Progress : {}
Verbose : {}
Debug : {[AzureLongRunningJob]: Starting cmdlet execution, setting for cmdlet confirmation required: 'False', [AzureLongRunningJob]: Error in cmdlet execution}
Warning : {}
Information : {}
@leaubl - Looks like there is an Azure Policy in your environment that is blocking the deployment.
Error: Code=RequestDisallowedByPolicy; Message=Resource 'pvdemoz7aevadls' was disallowed by policy.
Policy details:
{
"policyAssignment":{
"name":"CustomPurview",
"id":"/subscriptions/20d6eaa0-9bc1-49dc-be43-575a36c40752/providers/Microsoft.Authorization/policyAssignments/70b6f06669ce473bbea41bc2"
},
"policyDefinition":{
"name":"CustomPurview",
"id":"/subscriptions/20d6eaa0-9bc1-49dc-be43-575a36c40752/providers/Microsoft.Authorization/policyDefinitions/905bff0f-250c-4e33-8168-63b53e62e098"
}
}
@tayganr
There is only 1 policy as below.
Name: ASC Default (subscription: xxxxxxxxx)
Description: This is the default set of policies monitored by Azure Security Center. It was automatically assigned as part of onboarding to Security Center. The default assignment contains only audit policies. For more information please visit https://aka.ms/ascpolicies
Please advise how to overcome this. Thanks.
@leaubl - Inspecting the error message, the details seem to indicate that the name of the policy definition is CustomPurview.
[
{
"policyAssignment":{
"name":"CustomPurview",
"id":"/subscriptions/20d6eaa0-9bc1-49dc-be43-575a36c40752/providers/Microsoft.Authorization/policyAssignments/70b6f06669ce473bbea41bc2"
},
"policyDefinition":{
"name":"CustomPurview",
"id":"/subscriptions/20d6eaa0-9bc1-49dc-be43-575a36c40752/providers/Microsoft.Authorization/policyDefinitions/905bff0f-250c-4e33-8168-63b53e62e098"
}
}
]
Can you try:
- Navigate to Azure Policy in the Azure Portal
- Select Definitions
- Set the Scope to the Azure Subscription with Subscription ID
20d6eaa0-9bc1-49dc-be43-575a36c40752
- Ensure the Definition Type and Category are both set to all, then search for Definition ID
905bff0f-250c-4e33-8168-63b53e62e098
If this is still returning blank, is it possible that your account may not have sufficient access to see all policy definitions?
@tayganr we deleted CustomPurview policy and the second deployment went through!!
All steps in Validate Deployment are fine except for step 6 - test connection to Azure SQL Database failed. Please advise further.
Thanks so much for making it this far. :)
@leaubl - As part of the script, there are API calls to automatically create and run scans against the two data sources. If you navigate to Data map > Sources and then click View details on the Azure SQL Database, is there a successful scan? Note: The Azure SQL Database is a serverless SKU, when testing the connection it may have gone to sleep, if you click Test connection multiple times it should wake up and start testing successfully again.
@leaubl - Speaking with @isantillan1 he rightly pointed out that the reason why the connection is failing is because the Lineage extraction (preview) feature is toggled ON and this requires additional permissions that are not automated as part of the script. If you toggle this OFF then test, it should be OK. I'm going to close this issue now as the original problem has been solved. This can be raised as a separate issue.