Azure Policy Definition Permission Error : AuthorizationFailed - azure

I am defining a custom azure policy by using this azure template (official github repo of azure).
As a parameter, i am just passing the log analytics workspace name in the param. The below powershell code (taken from the azure repo) is used for that purpose, i have just added -AssignIdentity to the second command as it is necessary. As a role definition, i give owner of subscription rights inside the template.
$definition = New-AzPolicyDefinition -Name "deploy-oms-vm-extension-windows-vm" -DisplayName "Deploy default Log Analytics VM Extension for Windows VMs." -description "This policy deploys the Log Analytics VM Extensions on Windows VMs, and connects to the selected Log Analytics workspace." -Policy 'https://raw.githubusercontent.com/Azure/azure-policy/master/samples/Compute/deploy-oms-vm-extension-windows-vm/azurepolicy.rules.json' -Parameter 'https://raw.githubusercontent.com/Azure/azure-policy/master/samples/Compute/deploy-oms-vm-extension-windows-vm/azurepolicy.parameters.json' -Mode Indexed
$definition
$assignment = New-AzPolicyAssignment -Name <assignmentname> -Scope <scope> -logAnalytics <logAnalytics> -PolicyDefinition $definition -AssignIdentity
$assignment
The policy is created correctly. But when i try to create a remediation task, the task fails and i get the error below:
Details
Code AuthorizationFailed
Message The client 'xxxx-xxx-xxxx-xxxx-xxxx' with object id 'xxxx-xxx-xxxx-xxxx-xxxx' does not have authorization to perform action 'Microsoft.Resources/deployments/validate/action' over scope '/subscriptions/xxxx-xxx-xxxx-xxxx-xxxx/resourcegroups/rg-test/providers/Microsoft.Resources/deployments/PolicyDeployment_17825756917269472742' or the scope is invalid. If access was recently granted, please refresh your credentials.
On the portal, i see that the policy definition has owner rights as i have defined.
But i also see this on the policy remediation page:
I don't understand the reason of this error. Does someone have any idea?

According to some test, it may be caused by your account permission. I don't think it has anything to do with the role of your policy definition.
One case to show the same error message is do the operation with wrong subscription or wrong resource group, but I think it's a very low probability to choose wrong subscription or resource group because you do it on portal.
The other case to show this error message is what I test in my side. I test with one account hasn't be assigned a role which have enough permission, it shows same error message. So please check your account role and assign a role with higher permission, then create remediation task.

I have found a solution. So the managed identity created during the New-AzPolicyAssignment command execution, is not created with the right permission. The workaround solution is like this:
$definition = New-AzPolicyDefinition -Name "deploy-oms-vm-extension-windows-vm" -DisplayName "Deploy default Log Analytics VM Extension for Windows VMs." -description "This policy deploys the Log Analytics VM Extensions on Windows VMs, and connects to the selected Log Analytics workspace." -Policy 'https://raw.githubusercontent.com/Azure/azure-policy/master/samples/Compute/deploy-oms-vm-extension-windows-vm/azurepolicy.rules.json' -Parameter 'https://raw.githubusercontent.com/Azure/azure-policy/master/samples/Compute/deploy-oms-vm-extension-windows-vm/azurepolicy.parameters.json' -Mode Indexed
$assignment = New-AzPolicyAssignment -Name <assignmentname> -Scope <scope> -logAnalytics <logAnalytics> -PolicyDefinition $definition -AssignIdentity
## Get newly created policy assignment object
$PolicyAssignment = Get-AzPolicyAssignment -Name $assignmentname -Scope $scope
## Extract the RoleID and ObjectID
$roleDefinitionId = [GUID]($definition.properties.policyRule.then.details.roleDefinitionIds -split "/")[4]
$objectID = [GUID]($PolicyAssignment.Identity.principalId)
## Create a role assignment from the previous information
New-AzRoleAssignment -Scope $scope -ObjectId $objectID -RoleDefinitionId $roleDefinitionId
There is a already opened issue here. I have adapted the solution from there.

Related

Problems with assigning a Azure policy and multiple subscriptions

I'm having some issues assigning one of the built-in policies with a logAnalytics parameter where there are multiple subscriptions involved. I need to do it with code. Here's how I try to accomplish it.
Get a reference to the built-in policy definition to assign
$definition = Get-AzPolicyDefinition | Where-Object { $_.Properties.DisplayName -eq 'Deploy Log Analytics agent for Windows VMs' }
$parameter = #{
logAnalytics = '<resourceId to my logAnalytics workspace>'
}
Create the policy assignment with the built-in definition against your resource group
New-AzPolicyAssignment -Name 'Deploy LA Agent Windows VMs' -DisplayName 'Deploy LA Agent Windows VMs' -Scope "/subscriptions/<my subscriptionId" -PolicyDefinition $definition -AssignIdentity -Location 'norwayeast' -PolicyParameterObject $parameter
This code works fine if I assign the policy to the same subscription where the logAnalytics workspace is located, but if I scope the policy assignment to another subscription and afterward check the assignment in the portal, the Log Analytics Workspace parameter will be empty.
The service principal that runs these commands is owner of both subscriptions.
The most straight-forward way of applying policies across multiple subscriptions is to make them part of a management group. You can apply a policy to the management group and every subscription which is a member will inherit it.
Further information on management groups can be found here:
https://learn.microsoft.com/en-us/azure/governance/management-groups/overview
Amended code using management groups:
New-AzPolicyAssignment -Name 'Deploy LA Agent Windows VMs' -DisplayName 'Deploy LA Agent Windows VMs' -Scope "/providers/Microsoft.Management/managementGroups/managementGroup001" -PolicyDefinition $definition -AssignIdentity -Location 'norwayeast' -PolicyParameterObject $parameter
Notes
You will need to create a management group and add subscription(s) to it before running any commands.
Assigning subscription(s) to an existing management group can have adverse effects, check there are no conflicts.
An error is likely to be generated regarding the length of the names used as they are restricted to 24 characters. You should shorten or abbreviate them.
I have not tested this code so please double-check by reviewing the documentation on Microsoft's site before running in your own environment.

'this.Client.SubscriptionId' cannot be null

We noticed that our Azure Subscription field is empty eg:
Get-AzContext -ListAvailable
Name Account SubscriptionName Environment TenantId
---- ------- ---------------- ----------- --------
kk89gan-db99-41c8-95c4-d43adfdfaf34ad ... mymy#outlook.zzz ... AzureCloud 674ce2a1-d4sd1da..
so when I try to run on ps command, I receive an error:
New-AzResourceGroup -Name az1rg -Location 'eastus'
New-AzResourceGroup : 'this.Client.SubscriptionId' cannot be null.
At line:1 char:1
If you don't set an Azure subscription, you won't be allowed to create any Azure resources without the subscription.
You need use Get-AzSubscription to list all the available subscriptions.
Then set the subscription by using Select-AzSubscription {subscription id}.
Now you could create Azure resources.
I notice that your account seems to be a guest user right?
If so, you should assign the guest user as an administrator of a subscription at first. Then the guest user can see the subscription in Powershell.
Add your System Managed Identity as Contributor role in Subscription level.
Add Contributor role on subscription level.
Correct me if I am wrong. Thank You.
The following works
Use Get-AzSubscription to list all the available subscriptions.
Set the subscription by using Select-AzSubscription {subscription id}.
This error also occurs if you are using a Managed Identity to authenticate, but the Automation Account (or Functional App) does not have a Role assigned. Assigning a Role (presumably) "homes" this identity in Subscription and populates this property automatically during authentication.
Issue reported in 2019:
https://github.com/Azure/Azure-Functions/issues/1285

Use Automation RunAs service principal to connect to Azure Analysis Services and process

TL;DR
In summary the steps are:
Use the correct code (the last code in this post)
Manually add your app id in SSMS as either a server administrator or a database administrator
and then you can process an Azure Analysis Services cube from an Azure Automation Account without needing to create another seperate service account
Actual Question:
I am trying to process an Azure Analysis Services cube using the Azure Automation RunAs Service Principal. This is run within an Azure automation account
This code
#Get the existing AzureRunAsConnection connection
$Conn = Get-AutomationConnection -Name AzureRunAsConnection
# Login with service principal account
Login-AzureRMAccount
-ServicePrincipal
-Tenant $Conn.TenantID
-ApplicationId $Conn.ApplicationID
-CertificateThumbprint $Conn.CertificateThumbprint
# Process cube
Invoke-ProcessASDatabase -databasename "DB" -server "Server" -RefreshType "Full"
Results in
Authentication failed: User ID and Password are required when user interface is not
available.
My understanding is that when you create an Azure Automation Account, it also creates a 'RunAs' account, which in turn creates a service principal account. (Although the doco seems a bit light on)
I have tried finding this principal account in Azure AD and adding it to SSAS Admins in the Azure portal, but I can't find the actual account. Do service principals actually appear as accounts?
The code below works fine, but it uses a pre saved credential but I don't want to have to manage yet another account.
# Purpose: Run a full process the SSAS cube
$AzureCred = Get-AutomationPSCredential -Name "MyCredential"
Add-AzureRmAccount -Credential $AzureCred | Out-Null
Invoke-ProcessASDatabase -databasename "MyDB" -server "MyServer" -RefreshType "Full" -Credential $AzureCred
Update 1
I have also tried manually adding these in the SSMS membership area (after looking up the guids in the RunAs Account area in the automation account):
app:applicationid#tenantid
obj:serviceprincipalobjectid#tenantid
and I get the same error message.
I also ran the script with a non-admin user and got
The "zzz" database does not exist on the server.
So it would appear my issue is authentication, not authorisation. In other words it's not that I don't access, it's that I can't log in. I'm thinking based on that error, that -credential is not optional when calling Invoke-ProcessAsDatabase against Azure Analysis services
Also, I note that for the -credential option, the help says
If no credentials are specified, the default Windows account of the user running the script is assume
Given that Azure Analysis Services appears to only be able to use SQL credentials when connecting to a data source (no kind of AD credentials), I can only surmise that Azure Analysis Services is unable to use any kind of Azure Ad authentication for internal processes.
The annoying thing is that this isn't stated anywhere.
Update 2
So I did not read the link carefully enough. The code that works is mostly on the site posted by both answerers here. To pre authenicate to Azure Analysis Server you need to use Add-AzureAnalysisServicesAccount (The linked blog uses Login-AzureAsAccount but I couldn't get it working and couldn't find doco). You need to install powershell module "Azure.AnalysisServices" to use this.
$Conn = Get-AutomationConnection -Name AzureRunAsConnection
Add-AzureAnalysisServicesAccount -RolloutEnvironment "australiasoutheast.asazure.windows.net" -ServicePrincipal -Tenant $Conn.TenantID -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint
Invoke-ProcessASDatabase -databasename "MYDB" -server "MyServerEndpoint" -RefreshType "Full"
You can use the RunAs account with this, and afterwards you don't need to use -credential
So.. this actually works and logs in without needing a seperate credential, but now it doesn't have access to the database. Instead of a login error, I get
The "ZZZZ" database does not exist on the server.
I would appear that the RunAs account has access to the server but not the database and I can't work out to find it to give it access.
Update 3:
This is a more direct guide on how to give the app access to the model so it can be built:
Azure analysis service connection using Service principal not working
Note you can't add in the Azure portal as it won't find it. Add it "manually" in SSMS and it will work, and it will also appear in the Azure Portal as an admin
It all works now.
Update 4:
This has become a handy spot to store my discoveries around authenticating through MSI
Although this question is solved, no I want to connect to SQL Azure from something else using MSI security. No connection string supports this - none of the authentication methods in any connection string support MSI authentication. I did find this interesting link which implies you can create a connection string that supports authentication as MSI:
https://learn.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi
The bit of code of interest is:
az webapp config connection-string set
--resource-group myResourceGroup
--name <app name>
--settings MyDbConnection='Server=tcp:<server_name>.database.windows.net,1433;Database=<db_name>;'
--connection-string-type SQLAzure
I can't find any reference to the parameter --connection-string-type. But it looks like you simply exclude the authentication piece altogether.
In your example 1, it seems not your login Azure Login-AzureRMAccount get the error log. Based on my knowledge, Invoke-ProcessASDatabase is not a Azure Power Shell cmdlet. In fact, you no need to login your Azure subscription. Only Invoke-ProcessASDatabase -databasename "MyDB" -server "MyServer" -RefreshType "Full" -Credential $AzureCred should works for you.
Yes if I supply a credential it works, but I want to use the RunAs
credential. If I can't, then what is the point of it.
RunAs credential only works for login your Azure subscription, it does not stores credential for your SQL. In your scenario, you could store your SQL credential in runbook PSCredential, like your example2. In fact, in your example, you could remove Add-AzureRmAccount -Credential $AzureCred | Out-Null.
Update:
You should use following script in runbook.
$Conn = Get-AutomationConnection -Name AzureRunAsConnection
Login-AzureASAccount -RolloutEnvironment "southcentralus.asazure.windows.net" -ServicePrincipal -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint -TenantId $Conn.TenantID
Invoke-ProcessTable -Server "asazure://southcentralus.asazure.windows.net/myserver" -TableName "MyTable" -Database "MyDb" -RefreshType "Full"
More information about this please check this blog.
Per the official documentation:
Once the service principal is created, its application ID can be assigned permissions in the Azure Analysis Services server or model roles using the following syntax. The example below adds a service principal to the server administrators group in SSMS.
I didn't see the use of Run-as option, i'd recommend checking this blog
It also contains information about storing credentials in azure automation, this will help you in not hard writing credentials in the code.

How do I Choose which AAD you Create the Service Principal in?

I can't find any documentation on how to choose which AAD to create the service principal in. Basically, I can't find out if there is even a way to add the SP to the local AAD.
So we have a default Global AD which covers all of our enrollment and below that all subscriptions. I'm using Powershell derived from the many many examples on the net to create a SP in the default AD. Then I permission that SP against the subscription it is going to be working in.
At this point I've run into the following problem.
I'm rolling out a Key Vault, this works.
New-AzureRmKeyVault -VaultName $VaultName -EnabledForDeployment -EnabledForTemplateDeployment -ResourceGroupName $ResourceGroupName -Location $Location -Verbose
I need to add the first secret into it as part of the deployment. This bit fails because the SP doesn't have access to the KV.
# Set-AzureRmKeyVaultAccessPolicy -VaultName $VaultName -ResourceGroupName $ResourceGroupName -PermissionsToSecrets get,set -ServicePrincipalName $ServicePrincipalName
This is the result of that command.
Set-AzureRmKeyVaultAccessPolicy : Cannot find the Active Directory object
'Service-Principal-Name' in tenant '6166a717-xxxx-xxxxx-b0e8-6b7288c1f7ec'.
Please make sure that the user or application service principal you are
authorizing is registered in the current subscription's Azure Active
directory.
Reading into this, its not possible to set the Global AD Service Principal to have get/set on the local Keyvault. it would have to be a local Service Principal. However, we dont have one of them and nowhere can I work out how to create one of them.
Anyone else feeling this pain and know how to resolve it?
In the settings section of the old portal (manage.windowsazure.com), you will find a list of all subscriptions. The fourth column (Directory) shows the default directory that is associated with each subscription. No matter what, you will have to create the Service Principal in the Directory that is associated with that particular subscription. Please check this link to understand the relationship between Subscriptions and AAD.

Azure Credentials error in Azure Automation

I'm trying to create an Azure Automation job to create a standard set of tags/values in a subscription.
Working with Tags requires AzureResourceManager, which is not available in Automation out of the box (Go vote for this feedback item!), so I followed these steps to upload the ARM module.
When I test my runbook I get the following output:
-------------------------
PSComputerName : localhost
PSSourceJobInstanceId : a8b85213-ee0f-40ea-842f-d33f2e87c910
Id : xxxxx-56ad-42c2-97f4-e364456fc4a6
Name : xxxxx
Environment : AzureCloud
Account : my-service-principal-app-id
Properties : {Default, Tenants, SupportedModes}
-------------------------
New-AzureTag : Your Azure credentials have not been set up or have expired, please run Add-AzureAccount to set up your
Azure credentials.
At Add-SubscriptionTags:41 char:41
+
+ CategoryInfo : CloseError: (:) [New-AzureTag], ArgumentException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Tags.Tag.NewAzureTagCommand
Here's my runbook:
workflow Add-SubscriptionTags
{
param
(
# Subscription
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]
$SubscriptionName
)
# Get the PowerShell credential and prints its properties
$cred = Get-AutomationPSCredential -Name 'AzureMaint'
# Connect to Azure
Add-AzureAccount -Credential $cred -ServicePrincipal -Tenant 'xxx-49ab-8a9c-4abce32afc1e' | Write-Verbose
# Set subscription
$subscription = Select-AzureSubscription -SubscriptionName $SubscriptionName -PassThru
write-output '-------------------------'
write-output $subscription
write-output '-------------------------'
# Add tags (Requires AzureResourceManager module)
New-AzureTag -Name 'Managed' -Value $true
New-AzureTag -Name 'Managed' -Value $false
}
The AzureMaint PSCredential contains a service principal ID and key, and the service principal has been granted the Contributor role on the specified subscription. I can do Add-AzureAccount in the ISE with those credentials and add tags just fine. Since it successfully prints the subscription info I assume that means Add-AzureAccount was successful, so why do I get the error?
Update:
I created a new Automation Account without the ARM module and I'm still having the same issue, although the error message is slightly different:
Your Azure credentials have not been set up or have expired, please run Add-AzureAccount
to set up your Azure credentials. (Your Azure credentials have not been set up or
have expired, please run Add-AzureAccount to set up your Azure credentials. (Unable
to retrieve service key for ServicePrincipal account xxx-4a00-becf-952fda93edc5.
Please run the Add-AzureAccount cmdlet to supply the credentials for this service principal.))
So now I'm wondering if it doesn't like me using a Service Principal?
Just to update here, we've discovered that service principal authentication does not work in Azure Automation currently. Given you are trying to use a service principal, that is the reason for the issues you are hitting.
For now, a user principal should be used to work around this issue.
Please see the following for more info:
Authenticating to Azure Resource Manager with a Service Principal in Azure Automation
https://github.com/Azure/azure-powershell/issues/655
Using ARM cmdlets in Azure Automation is not officially supported yet. That said, various people have been successful doing so. Are your ARM and Azure PowerShell modules the same version? Weird things can happen if they are loaded side by side but are not the same version.

Resources