Access policies management with Azure AD Service Principal seems to be trivial - it's just an API method / CLI function - and using Service Principal instead of User Principal should not matter. But...
Let's create our SP:
az ad sp create-for-rbac -n "TestApp" --role owner --scopes /subscriptions/ssssssss-ssss-ssss-ssss-ssssssssssss
and in the output I will get:
{
"appId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"displayName": "TestApp",
"name": "http://TestApp",
"password": "pppppppp-pppp-pppp-pppp-pppppppppppp",
"tenant": "tttttttt-tttt-tttt-tttt-tttttttttttt"
}
Next, let's login as SP:
az login --service-principal --tenant tttttttt-tttt-tttt-tttt-tttttttttttt --username xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx --password pppppppp-pppp-pppp-pppp-pppppppppppp
Output:
[
{
"cloudName": "AzureCloud",
"id": "ssssssss-ssss-ssss-ssss-ssssssssssss",
"isDefault": true,
"name": "Subscription Name",
"state": "Enabled",
"tenantId": "tttttttt-tttt-tttt-tttt-tttttttttttt",
"user": {
"name": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"type": "servicePrincipal"
}
}
]
And now, let's try to create Key Vault policy:
az keyvault set-policy -n mdskv --upn tester@free-media.eu --secret-permissions get list
Output (client_exception):
GraphErrorException: Insufficient privileges to complete the operation.
But if we will try to set the same policy using User's obejctId instead of UPN:
az keyvault set-policy -n mdskv --object-id iiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii --secret-permissions get list
Output:
{
"id": "/subscriptions/ssssssss-ssss-ssss-ssss-ssssssssssss/resourceGroups/testrg/providers/Microsoft.KeyVault/vaults/mdskv",
"location": "westeurope",
"name": "mdskv",
"properties": {
"accessPolicies": [
{
"applicationId": null,
"objectId": "iiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii",
"permissions": {
"certificates": null,
"keys": null,
"secrets": [
"get",
"list"
],
"storage": null
},
"tenantId": "tttttttt-tttt-tttt-tttt-tttttttttttt"
}
],
"createMode": null,
"enableSoftDelete": null,
"enabledForDeployment": false,
"enabledForDiskEncryption": false,
"enabledForTemplateDeployment": false,
"sku": {
"name": "standard"
},
"tenantId": "tttttttt-tttt-tttt-tttt-tttttttttttt",
"vaultUri": "https://mdskv.vault.azure.net/"
},
"resourceGroup": "testrg",
"tags": {},
"type": "Microsoft.KeyVault/vaults"
}
So as we see, UPN-based policy creation does not work - we need to know an objectId
of the user. In most cases (for me), my team mates uses UPN instead of objectId
in their daily communication. Probably it is the same for you ;)
It is simple to get objectId
for UPN if you are logged-in as User:
az ad user list --query "[?contains(objectId, 'iiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii')]"
Output:
[
{
"displayName": "tester",
"mail": null,
"mailNickname": "tester",
"objectId": "iiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii",
"objectType": "User",
"signInName": null,
"usageLocation": null,
"userPrincipalName": "tester@free-media.eu"
}
]
...and not so simple if you are logged-in as SP:
az ad user list --query "[?contains(objectId, 'iiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii')]"
Output (client_exception):
GraphErrorException: Insufficient privileges to complete the operation.
That's because of no default privileges to read the directory for SP. I have described this case here. You need to add your SP to the "Directory Readers" AAD role to translate UPN to objectId
.