The role assignments where the user has been removed remain as Identity not found.
The az role assignment list does not return displayName to filter it out that way.
Ex:
"canDelegate": null,
"condition": null,
"conditionVersion": null,
"description": "",
"id": "/subscriptions/xxxxxxxxxxxxx/providers/Microsoft.Authorization/roleAssignments/xxxxxxxxxxxxx",
"name": "xxxxxxxxxxxxx",
"principalId": "xxxxxxxxxxxxx",
"principalType": "ServicePrincipal",
"roleDefinitionId": "/subscriptions/xxxxxxxxxxxxx/providers/Microsoft.Authorization/roleDefinitions/xxxxxxxxxxxxx",
"roleDefinitionName": "User Access Administrator",
"scope": "/subscriptions/xxxxxxxxxxxxx",
"type": "Microsoft.Authorization/roleAssignments"
Do we have any easy way of finding these and removing them using az cli? So that this can be put into a script.
Do we have any easy way of finding these and removing them using az cli
Using azure cli I couldn't find any way to get Orphaned Roles but I could able to find an alternative that is Uinsg PowerShell as below and I followed Microsoft-Document and SO-Thread:
Get-AzRoleAssignment | Where-object -Property Displayname -eq $null
Output:
You could also get Orphaned Role using below commands and I followed
$o = "Unknown"
Get-AzRoleAssignment | Where-object -Property ObjectType -eq $o
Output:
Now you can use Remove-AzRoleAssignment to remove these roles MS-Doc.
Related
I have a thousand app services in different subscriptions running on Microsoft Azure. I need to pull all the runtime version for each webapp.
I used this CLI Azure command to list the runtimes actually running in my subscriptions:
az webapp list-runtimes --subscription
But, I need to have the information for each webapp.
How can I do it?
This is more difficult than it should be given that not all properties are exposed by all CLI methods (or REST API calls), and some of the ones that are aren't populated. It is made even more complex by the fact that different properties are used for Windows and Linux hosts.
However it can be done using a combination of CLI commands. This PowerShell script will generate a JSON file for all the app services in a subscription, with their relevant runtimes and versions. Like this:
Script:
# Define a collection to hold the output
$runtimes = [System.Collections.Generic.List[object]]#()
# Get subscription id
Write-Progress "Fetching subscription id"
$sub = (az account show --query id -o tsv)
# Get all resource groups in the subscription
Write-Progress "Searching for resource groups"
$groups = (az group list --query "[].name" -o tsv)
# Set counter for group progress
$groupCounter = 1;
# Loop through each resource group to find all the web apps in it
foreach($group in $groups) {
# Find web apps in the specified group
Write-Progress "Searching for web apps in resource group $group" -PercentComplete (($groupCounter / $groups.Count) * 100)
$apps =(az webapp list -g $group --query "[?kind=='app' || kind=='app,linux'].name" -o tsv)
# Iterate the web apps
foreach($app in $apps) {
# Query the web app for versions
Write-Progress "Querying web app $app"
$appConfig = (az webapp show -n $app -g $group --query "{java:siteConfig.javaversion,netFramework:siteConfig.netFrameworkVersion,php:siteConfig.phpVersion,python:siteConfig.pythonVersion,linux:siteConfig.linuxFxVersion}") | ConvertFrom-Json
# Define an output object
$output = [PSCustomObject]#{
group = $group
name = $app
host = $null
runtime = $null
version = $null
}
# Determine which type of app service it is and get the values accordingly
if($appConfig.linux -eq "") {
# Windows platform
$output.host = "windows"
# Query the app config to get the metadata for the current stack
$uri = "https://management.azure.com/subscriptions/$sub/resourceGroups/$group/providers/Microsoft.Web/sites/$app/config/metadata/list?api-version=2020-10-01"
$output.runtime = (az rest --method post --uri $uri --query "properties.CURRENT_STACK" -o tsv)
# Determine the version of the relevant stack
$output.version = switch($output.runtime) {
"dotnet" {$appConfig.netFramework}
"dotnetcore" {$null}
"python" {$appConfig.python}
"php" {$appConfig.php}
"java" {$appConfig.java}
default {$null}
}
} else {
# Linux platform
$output.host = "linux"
# Split out the stack from the version
$output.runtime = $appConfig.linux.split("|")[0]
$output.version = $appConfig.linux.split("|")[1]
}
$runtimes.Add($output)
}
$groupCounter = $groupCounter + 1
}
# Convert the collection to JSON and write it out to a file
Write-Output $runtimes | ConvertTo-Json > "webapp-runtimes-$sub.json"
Output:
[
{
"group": "sample-group",
"name": "sample-ruby-app",
"host": "linux",
"runtime": "RUBY",
"version": "2.6"
},
{
"group": "php-group",
"name": "sample-php-app",
"host": "windows",
"runtime": "php",
"version": "7.3"
},
{
"group": "linux-apps",
"name": "sample-node-app",
"host": "linux",
"runtime": "NODE",
"version": "14-lts"
},
{
"group": "linux-apps",
"name": "sample-dotnetcore-app",
"host": "linux",
"runtime": "DOTNETCORE",
"version": "3.1"
}
]
Here is an example how to get runtime versions for each app services in multiple subscriptions:
Assuming that you have all the subscriptions within same account
Assuming that you have Windows WebApps
Code:
$subscriptions = az account list | ConvertFrom-Json
foreach ($s in $subscriptions) {
az account set -s $s.name
$webapps = az resource list --resource-type 'Microsoft.Web/sites' | ConvertFrom-Json
foreach ($w in $webapps) {
$config = az webapp config show --name $w.name --resource-group $w.resourcegroup | ConvertFrom-Json
$res = $config.name + ""
$res += $config.windowsFxVersion
$res >> file.txt
}
}
This template run on the same resource group produced the error StorageAccountAlreadyTaken but it is expected to do incremental deployment, ie. not to create any new resources. How to fix this?
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('prodSaName')]",
"tags": { "displayName": "Storage account" },
"apiVersion": "2016-01-01",
"location": "[parameters('location')]",
"sku": { "name": "Standard_LRS" },
"kind": "Storage",
"properties": {}
},
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[ge.saName(parameters('brn'), parameters('environments')[copyIndex()])]",
"tags": { "displayName": "Storage account" },
"apiVersion": "2016-01-01",
"location": "[parameters('location')]",
"sku": { "name": "Standard_LRS" },
"kind": "Storage",
"copy": {
"name": "EnvStorageAccounts",
"count": "[length(parameters('environments'))]"
},
Run New-AzureRmResourceGroupDeployment #args -debug with this template and it outputs:
New-AzureRmResourceGroupDeployment : 15:03:38 - Error: Code=StorageAccountAlreadyTaken; Message=The storage account named
UNIQUENAMEOFTHERESOURCE is already taken.
At C:\coding\gameo\gameoemergency\provision.run.ps1:101 char:9
+ New-AzureRmResourceGroupDeployment #args -debug
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [New-AzureRmResourceGroupDeployment], Exception
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.NewAzureResourceGroupDeploymentCmdle
t
PS. Somehow running from VSTS doesn't have this result. That run from local machine. Also there is no such error in Activity Log, strangely.
Update.
If I don't do these selects of a subscription as below but only for RM there are no errors.
Select-AzureRmSubscription -SubscriptionID $Cfg.subscriptionId > $null
# this seems to be the reason of the error, if removed - works:
Select-AzureSubscription -SubscriptionId $Cfg.subscriptionId > $null
# ... in order to run:
exec { Start-AzureWebsiteJob #startArgs | out-null }
Not sure if its a help but I had this issue with APIs prior to 2016-01-01 as there was a known bug. I updated to 2016-12-01 as this was the latest at the time and it worked for me.
Have you tried updating the api to the latest and trying again? The latest is 2018-02-01
This is the result of selecting a subscription twice for Resource Manager cmdlets and using Select-AzureSubscription as below:
Select-AzureRmSubscription -SubscriptionID $Cfg.subscriptionId > $null
# this seems to be the reason of the error, if removed - works:
# Select-AzureSubscription -SubscriptionId $Cfg.subscriptionId > $null
To avoid old cmdlets (before RM) we can use Invoke-AzureRmResourceAction. See example at https://stackoverflow.com/a/51712321/511144
A good thing to do before performing a deployment is to validate the resources that if it can be created with the name provided. For EventHub and Storage Account there are built in cmdlets that allows you to check it.
For EventHub
Test-AzureRmEventHubName -Namespace $eventHubNamespaceName | Select-Object -ExpandProperty NameAvailable
if ($availability -eq $true) {
Write-Host -ForegroundColor Green `r`n"Entered Event Hub Namespace name is available"
For Storage Account
while ($true) {
Write-Host -ForegroundColor Yellow `r`n"Enter Storage account name (Press Enter for default) : " -NoNewline
$storageAccountName = Read-Host
if ([string]::IsNullOrEmpty($storageAccountName)) {
$storageAccountName = $defaultstorageAccountName
}
Write-Host -ForegroundColor Yellow `r`n"Checking whether the entered name for Storage account is available"
$availability = Get-AzureRmStorageAccountNameAvailability -Name $storageAccountName | Select-Object -ExpandProperty NameAvailable
if ($availability -eq $true ) {
Write-Host -ForegroundColor Green `r`n"Entered Storage account name is available"
break
}
Write-Host `r`n"Enter valid Storage account name"
}
This will prevent deployment errors by validating before deployment and asking the user to enter a valid name again if the entered one is not present.
I'm attempting to create an ARM Template that includes creating a Storage account.
I want to create a StorageV2 (general purpose v2) account but this seems to fail because StorageV2 does not exist in the schema.
{
"name": "[variables('xblobstorageName')]",
"type": "Microsoft.Storage/storageAccounts",
"location": "[resourceGroup().location]",
"apiVersion": "2016-01-01",
"sku": {
"name": "[parameters('xblobstorageType')]"
},
"dependsOn": [],
"tags": {
"displayName": "xblobstorage"
},
"kind": "StorageV2"
}
The only allowed values for kind are Storage and BlobStorage so when attempting to deploy the above template the following error is received:
"error": {
"code": "AccountPropertyIsInvalid",
"message": "Account property kind is invalid for the request."
}
Is it possible to create a V2 storage account using ARM Templates?
You have to update the apiVersion to 2018-02-01.
I wrote a PowerShell script to determine the latest API Version for a resource provider:
<#
.Synopsis
Gets the latest API version of a resource provider
.DESCRIPTION
The following cmdlet returns the latest API version for the specified resource provider.
You can also include pre-release (preview) versions using the -IncludePreview switch
.EXAMPLE
Using the Full Parameter Set:
Get-AzureRmResourceProviderLatestApiVersion -Type Microsoft.Storage/storageAccounts
.EXAMPLE
Using the Full Parameter Set with the -IncludePreview switch:
Get-AzureRmResourceProviderLatestApiVersion -Type Microsoft.Storage/storageAccounts -IncludePreview
.EXAMPLE
Using the ProviderAndType Parameter Set:
Get-AzureRmResourceProviderLatestApiVersion -ResourceProvider Microsoft.Storage -ResourceType storageAccounts
#>
function Get-AzureRmResourceProviderLatestApiVersion
{
[CmdletBinding()]
[Alias()]
[OutputType([string])]
Param
(
[Parameter(ParameterSetName = 'Full', Mandatory = $true, Position = 0)]
[string]$Type,
[Parameter(ParameterSetName = 'ProviderAndType', Mandatory = $true, Position = 0)]
[string]$ResourceProvider,
[Parameter(ParameterSetName = 'ProviderAndType', Mandatory = $true, Position = 1)]
[string]$ResourceType,
[switch]$IncludePreview
)
# retrieving the resource providers is time consuming therefore we store
# them in a script variable to accelerate subsequent requests.
if (-not $script:resourceProvider)
{
$script:resourceProvider = Get-AzureRmResourceProvider
}
if ($PSCmdlet.ParameterSetName -eq 'Full')
{
$ResourceProvider = ($Type -replace "\/.*")
$ResourceType = ($Type -replace ".*?\/(.+)", '$1')
}
$provider = $script:resourceProvider |
Where-Object {
$_.ProviderNamespace -eq $ResourceProvider -and
$_.ResourceTypes.ResourceTypeName -eq $ResourceType
}
if ($IncludePreview)
{
$provider.ResourceTypes.ApiVersions[0]
}
else
{
$provider.ResourceTypes.ApiVersions | Where-Object {
$_ -notmatch '-preview'
} | Select-Object -First 1
}
}
Usage:
Get-AzureRmResourceProviderLatestApiVersion -Type Microsoft.Storage/storageAccounts
And wrote a blog article about it:
Determine latest API version for a resource provider
For a given Azure subscription I want to assign custom role to Service Principal. In order to achieve this, I first check if the custom role definition exists in the subscription. If the role does not exists I update the role definition's assignable scope to include this subscription. I am facing 'RoleDefinitionDoesNotExist' error intermittently when I try to assign role. How do I fix this?
My code:
$roleDef = Get-AzureRmRoleDefinition -Name $azureRmRole
if($roleDef -eq $null)
{
Select-AzureRmSubscription -SubscriptionName $prodSubscription
#Role definition exists in $prodSubscription
$newRole = Get-AzureRmRoleDefinition -Name $azureRmRole
#$scope = '/subscriptions/xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx'
$newRole.AssignableScopes.Add($scope)
$def = Set-AzureRmRoleDefinition -Role $newRole
# I have verified that role definition is updated
}
Select-AzureRmSubscription -SubscriptionName $SubscriptionName
New-AzureRmRoleAssignment -RoleDefinitionName $azureRmRole -ObjectId $SPNid -Scope $scope
Error:
New-AzureRmRoleAssignment : The specified role definition with ID 'xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx' does not exist.
At C:\Untitled1.ps1:71 char:1
+ New-AzureRmRoleAssignment -RoleDefinitionName $azureRmRole -ObjectId ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [New-AzureRmRoleAssignment], CloudException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Resources.NewAzureRoleAssignmentCommand
You should define your custom role like below:
{
"Name": "Virtual Machine Power Manager",
"IsCustom": true,
"Description": "Can monitor, stop, start and restart v2 ARM virtual machines.",
"Actions": [
"Microsoft.Storage/*/read",
"Microsoft.Network/*/read",
"Microsoft.Compute/*/read",
"Microsoft.Compute/virtualMachines/start/action",
"Microsoft.Compute/virtualMachines/powerOff/action",
"Microsoft.Compute/virtualMachines/deallocate/action",
"Microsoft.Compute/virtualMachines/restart/action",
"Microsoft.Authorization/*/read",
"Microsoft.Resources/subscriptions/resourceGroups/read",
"Microsoft.Insights/alertRules/*",
"Microsoft.Insights/diagnosticSettings/*",
"Microsoft.Support/*"
],
"NotActions": [
],
"AssignableScopes": [
"/subscriptions/c25b1c8e-xxxx-1111-abcd-1a12d7012123"
]
}
According to your description, you role's definition maybe wrong, you had better check it.
If you want to give custom role to a service principal, please try to use the following cmdlet.
New-AzureRmRoleAssignment -ServicePrincipalName "https://shuiweb.azurewebsites.net" `
-RoleDefinitionName 'Virtual Machine Power Manager' `
-Scope '/subscriptions/*******'
The blog:AZURE AUTOMATION RUNBOOKS WITH AZURE AD SERVICE PRINCIPALS AND CUSTOM RBAC ROLES will be helpful.
Post updated. Issue has been solved. The scripts below will create a resource group, create a service principal, deploy a key vault, configure permissions and write a secret to the vault. Hopes this help! :)
Problem:
I am logged into PowerShell as a Service Principal that has Owner permissions on a resource group.
I get permission errors when i try to create a vault, set permission on the vault and when i try to write secrets.
Solution:
Step 1: Create resource group and Service Principal. You must be logged in as an administrator to execute this script
Clear-Host
Import-Module Azure
Import-Module AzureRM.Resources
Add-AzureRmAccount
Get-AzureRmSubscription
Set-AzureRmContext -SubscriptionId <Your subscription id goes here>
$ServicePrincipalDisplayName = "myServicePrincipalName"
$CertificateName = "CN=SomeCertName"
$cert = New-SelfSignedCertificate -CertStoreLocation "cert:\CurrentUser\My" -Subject $CertificateName -KeySpec KeyExchange
$keyValue = [Convert]::ToBase64String($cert.GetRawCertData())
$ResouceGroupName = "myRessourceGroup"
$location = "North Central US"
# Create the resource group
New-AzureRmResourceGroup -Name $ResouceGroupName -Location $location
$ResouceGroupNameScope = (Get-AzureRmResourceGroup -Name $ResouceGroupName -ErrorAction Stop).ResourceId
# Create the Service Principal that logs in with a certificate
New-AzureRMADServicePrincipal -DisplayName $ServicePrincipalDisplayName -CertValue $keyValue -EndDate $cert.NotAfter -StartDate $cert.NotBefore
$myServicePrincipal = Get-AzureRmADServicePrincipal -SearchString $ServicePrincipalDisplayName
Write-Host "myServicePrincipal.ApplicationId " $myServicePrincipal.ApplicationId -ForegroundColor Green
Write-Host "myServicePrincipal.DisplayName " $myServicePrincipal.DisplayName
# Sleep here for a few seconds to allow the service principal application to become active (should only take a couple of seconds normally)
Write-Host "Waiting 10 seconds"
Start-Sleep -s 10
Write-Host "Make the Service Principal owner of the resource group " $ResouceGroupName
$NewRole = $null
$Retries = 0
While ($NewRole -eq $null -and $Retries -le 6)
{
New-AzureRMRoleAssignment -RoleDefinitionName Owner -ServicePrincipalName $myServicePrincipal.ApplicationId -Scope $ResouceGroupNameScope -ErrorAction SilentlyContinue
$NewRole = Get-AzureRMRoleAssignment -ServicePrincipalName $myServicePrincipal.ApplicationId
Write-Host "NewRole.DisplayName " $NewRole.DisplayName
Write-Host "NewRole.Scope: " $NewRole.Scope
$Retries++
Start-Sleep -s 10
}
Write-Host "Service principal created" -ForegroundColor Green
Step 2 : ARM deployment of the vault. Create a filenamed keyvault2.parameters.json Update the id's to reflect your installation (5479eaf6-31a3-4be3-9fb6-c2cdadc31735 is the service principal used by azure web apps when accessing the vault.)
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"vaultName": {
"value": "valueFromParameterFile"
},
"vaultlocation": {
"value": "valueFromParameterFile"
},
"skumode": {
"value": "Standard"
},
"accessPolicyList": {
"value": [
{
"objectId": "The object ID for your AAD user goes here so that you can read secrets etc",
"tenantId": "Your Tenant Id goes here",
"permissions": {
"keys": [
"Get",
"List"
],
"secrets": [
"Get",
"List"
],
"certificates": [
"Get",
"List"
]
}
},
{
"objectId": "The object ID for the service principal goes here Get-AzureRmADServicePrincipal -ServicePrincipalName <Service Principal Application ID>",
"tenantId": "Your Tenant Id goes here",
"permissions": {
"keys": [
"Get",
"List",
"Update",
"Create",
"Import",
"Delete",
"Recover",
"Backup",
"Restore"
],
"secrets": [
"Get",
"List",
"Set",
"Delete",
"Recover",
"Backup",
"Restore"
],
"certificates": [
"Get",
"List",
"Update",
"Create",
"Import",
"Delete",
"ManageContacts",
"ManageIssuers",
"GetIssuers",
"ListIssuers",
"SetIssuers",
"DeleteIssuers"
]
},
"applicationId": null
},
{
"objectId": "5479eaf6-31a3-4be3-9fb6-c2cdadc31735",
"tenantId": "Your Tenant Id goes here",
"permissions": {
"keys": [],
"secrets": [
"Get"
],
"certificates": []
},
"applicationId": null
}
]
},
"tenant": {
"value": "Your Tenant Id goes here"
},
"isenabledForDeployment": {
"value": true
},
"isenabledForTemplateDeployment": {
"value": false
},
"isenabledForDiskEncryption": {
"value": false
}
}
}
Step 3 : ARM deployment of the vault. Create a filenamed keyvault2.template.json
{
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"vaultName": {
"type": "string"
},
"vaultlocation": {
"type": "string"
},
"skumode": {
"type": "string",
"defaultValue": "Standard",
"allowedValues": [
"Standard",
"standard",
"Premium",
"premium"
],
"metadata": {
"description": "SKU for the vault"
}
},
"accessPolicyList": {
"type": "array",
"defaultValue": [],
"metadata": {
"description": "The access policies defined for this vault."
}
},
"tenant": {
"type": "string"
},
"isenabledForDeployment": {
"type": "bool"
},
"isenabledForTemplateDeployment": {
"type": "bool"
},
"isenabledForDiskEncryption": {
"type": "bool"
}
},
"resources": [
{
"apiVersion": "2015-06-01",
"name": "[parameters('vaultName')]",
"location": "[parameters('vaultlocation')]",
"type": "Microsoft.KeyVault/vaults",
"properties": {
"enabledForDeployment": "[parameters('isenabledForDeployment')]",
"enabledForTemplateDeployment": "[parameters('isenabledForTemplateDeployment')]",
"enabledForDiskEncryption": "[parameters('isenabledForDiskEncryption')]",
"accessPolicies": "[parameters('accessPolicyList')]",
"tenantId": "[parameters('tenant')]",
"sku": {
"name": "[parameters('skumode')]",
"family": "A"
}
}
}
]
}
Step 4 : Deploy vault. Start a new powershell window and execute this script. Update 3 x id's
Clear-Host
Import-Module Azure
Import-Module AzureRM.Resources
$ServicePrincipalApplicationId = "xxx"
$TenantId = "yyy"
$SubscriptionId = "zzz"
$CertificateName = "CN=SomeCertName"
$ResouceGroupName = "myRessourceGroup"
$location = "North Central US"
$VaultName = "MyVault" + (Get-Random -minimum 10000000 -maximum 1000000000)
$MySecret = ConvertTo-SecureString -String "MyValue" -AsPlainText -Force
$Cert = Get-ChildItem cert:\CurrentUser\My\ | Where-Object {$_.Subject -match $CertificateName }
Write-Host "cert.Thumbprint " $cert.Thumbprint
Write-Host "cert.Subject " $cert.Subject
Add-AzureRmAccount -ServicePrincipal -CertificateThumbprint $cert.Thumbprint -ApplicationId $ServicePrincipalApplicationId -TenantId $TenantId
Get-AzureRmSubscription
Set-AzureRmContext -SubscriptionId $SubscriptionId
Write-Host ""
Write-Host "Creating vault" -ForegroundColor Yellow
New-AzureRmResourceGroupDeployment -ResourceGroupName $ResouceGroupName -vaultName $vaultName -vaultlocation $location -isenabledForDeployment $true -TemplateFile ".\keyvault2.template.json" -TemplateParameterFile ".\keyvault2.parameters.json"
Write-Host ""
Write-Host "Key Vault " $vaultName " deployed" -ForegroundColor green
Write-Host "Wait 5 seconds"
Start-Sleep -Seconds 5
Write-Host "Write Secret" -ForegroundColor Yellow
Set-AzureKeyVaultSecret -VaultName $VaultName -Name "MyKey" -SecretValue $MySecret
Write-Host "Wait 10 seconds"
Start-Sleep -Seconds 10
Write-Host "Read secret"
Get-AzureKeyVaultSecret -VaultName $VaultName -Name "MyKey"
Set-AzureRmKeyVaultAccessPolicy -VaultName $name -ObjectId $oId -PermissionsToSecrets get
returns error
Set-AzureRmKeyVaultAccessPolicy : Insufficient privileges to complete the operation.
Solution is to add additional parameter -BypassObjectIdValidation
Set-AzureRmKeyVaultAccessPolicy -BypassObjectIdValidation -VaultName $name -ObjectId $oId -PermissionsToSecrets get
Solution looks like a hack, but it works for me. After this, object with $oId have got access to keyVault. (For checks access polices use Get-AzureRmKeyVault -VaultName $vaultName)
The solution was to move the configuration of the permission to the ARM template instead of trying to do it using PowerShell. As soon as i did that all permission issues got solved.
In the ARM template the object Id i had specified for the Service Principal was wrong. It thought it as the Object Id you can find in the portal under app registrations, but no, it is actually the object ID of the service principal of the Azure AD application it wants.
It will let you deploy the ARM template just fine even if you use the wrong Id and everything like too correct configured, until you start wondering about why the icon looks different for you service principal compared to the other users. This of course you will not notice until much later if you like me only had one user ...
Wrong id (This icon is different):
Correct id:
This post gave me that final solution.
How do I fix an "Operation 'set' not allowed" error when creating an Azure KeyVault secret programmatically?
I struggled with this issue a lot this week, as I don't have permission in my AAD to add API permissions for the service principal. I found a solution using the ARM Output marketplace item. Using the ARM output task, I can retrieve the Principal ID's of my objects from the ARM template and convert them to pipeline variables, which in turn can be consumed by an Azure PowerShell script to successfully update the Key vault access policies .
In the ARM template, I added this output variable, to return the website principal id - this is the information I couldn't query AD with.
"outputs": {
"websitePrincipalId": {
"type": "string",
"value": "[reference(concat(resourceId('Microsoft.Web/sites', variables('webSiteName')), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').principalId]"
}
}
Then I used the ARM Output task, to return the output as pipeline variables, which is useful in a Azure PowerShell script where I was able to use this to populate my key vault with the correct access policies:
Set-AzKeyVaultAccessPolicy -VaultName "$(KeyVaultName)" -ObjectId "$(servicePrincipalId)" -PermissionsToSecrets list,get -PassThru -BypassObjectIdValidation
According to your description, I test in my lab, I also use my Service Principal to login my Azure subscription. Your cmdlet works for me.
Do you check my Service Principal role? You could check it on Azure Portal.
Please ensure your Service Principal has Contributor or Owner permission. More information about this please refer to this link.
Update:
I test in my lab, your PowerShell script works fine for you. I suggest you could use Power Shell to create key vault and give permissions.
2022 refer to https://learn.microsoft.com/en-us/azure/key-vault/general/assign-access-policy?tabs=azure-cli
ran on Azure Cloud shell 2.43.0
az keyvault set-policy --name myKeyVault --object-id --secret-permissions --key-permissions --certificate-permissions
remove flags you don't want