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"
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):
This post gave me that final solution.