hashicorp/vault-plugin-secrets-azure

Dynamic service principal AD permissions

lightdrive opened this issue ยท 19 comments

I ran into issues in generating the Dynamic SP with 403 error "Insufficient privileges to complete the operation." even though I had granted the following API Permissions in AD;

Microsoft Graph;
Appplication.ReadWrite.All
Directory.ReadWrite.All

Everything looked correct on the Azure Secrets backend configuration and App had the Owner on the subscription. After some digging I came across this in the forum;

https://discuss.hashicorp.com/t/azure-secrets-engine/2090/2

There are two APIs - I added the 'legacy' API Azure Active Directory Graph Application.ReadWrite.All Permission and it started working, dynamically generating the SP.

The docs need a little tweak to nudge people down the correct path as the portal will default someone to granting 'Microsoft Graph' API permissions instead of the legacy 'Azure Active Directory Graph API' permissions;

_The following Azure roles and Azure Active Directory (AAD) permissions are required, regardless of which authentication method is used:

Azure Subscription - "Owner" role for the subscription scope
Azure Active Directory Graph API - "Read and write all applications" permission_

@lightdrive Thanks for the heads up on this. Permissions for Azure Secrets has always been a challenge, and I'm going to review Microsoft Graph vs. AAD Graph distinction. I do plan on updating the docs, and one strategy I've been considering is to provide examples using the CLI and a manifest file. This would allow precise assignment of the permissions in a copy-n-pasteable way, versus navigating the portal.

sylus commented

Hey @kalafut we are trying to get this to work but we are using MSI instead and are unable to assign the Azure AD Directory Graph API permissions cause the page doesn't exist in the portal, the page 404's in the Enterprise App.

We reached out to Hashicorp and just linked to the doc about using this plugin with Service Prinicpals, but was really hoping to get this to work with MSI and can't find any clear instructions.

Thanks for any feedback or pointers you might have :D

sylus commented

Woot nevermind a colleague got it working :D Very cool to see rotating S.P's thank so much :D

Woot nevermind a colleague got it working :D Very cool to see rotating S.P's thank so much :D

@sylus
Can you please post what you did to get the MSI working, I am running into the same problem.

@sylus any idea on how to use MSI to get Azure AD Directory Graph API perms?

Woot nevermind a colleague got it working :D Very cool to see rotating S.P's thank so much :D

How did you get MSI working with the Graph permissions? Be good to see your solution, I've been pulling my hair out with this for a few days now.

Here's what we did to get this to work as @sylus mentioned:

With our Azure managed identity:

  1. Grant Owner permissions on all subscriptions
  2. Assign the following Graph permissions. This cannot be done through the UI, so we used PowerShell:
// Windows AAD Graph
$graph = Get-AzureADServicePrincipal -Filter "AppId eq '00000002-0000-0000-c000-000000000000'"
$msi = Get-AzureADServicePrincipal -Filter "AppId eq '$MANAGED_IDENTITY_APP_ID'"

// Application.ReadWrite.All
$role = $graph.AppRoles | where Value -Like "Application.ReadWrite.All" | Select-Object -First 1
New-AzureADServiceAppRoleAssignment -Id $role.Id -PrincipalId $msi.ObjectId -ResourceId $graph.ObjectId -ObjectId $msi.ObjectId

// Directory.ReadWrite.All
$role = $graph.AppRoles | where Value -Like "Directory.ReadWrite.All" | Select-Object -First 1
New-AzureADServiceAppRoleAssignment -Id $role.Id -PrincipalId $msi.ObjectId -ResourceId $graph.ObjectId -ObjectId $msi.ObjectId

Note that these commands only worked when we were using an account with Global Admin privileges.

@kalafut facing the same issue with Vault v1.5.0

I have the following permissions in Azure:
"Read and write all applications" permission in AAD
"Read and write all applications" permission in Microsoft Graph
"Owner" role for the subscription scope

It fails with the following error:
* graphrbac.ApplicationsClient#Create: Failure responding to request: StatusCode=403 -- Original Error: autorest/azure: Service returned an error. Status=403 Code="Unknown" Message="Unknown service error" Details=[{"odata.error":{"code":"Authorization_RequestDenied","date":"2020-08-29T05:42:15","message":{"lang":"en","value":"Insufficient privileges to complete the operation."},

I had the same issue as @aratik711 but after reading the article @lightdrive provided (https://discuss.hashicorp.com/t/azure-secrets-engine/2090/2), there were additional permissions needed to get it working:

Azure Active Directory Graph
Application.ReadWrite.All
Directory.ReadWrite.All
User.Read

I had the same issue as @aratik711 but after reading the article @lightdrive provided (https://discuss.hashicorp.com/t/azure-secrets-engine/2090/2), there were additional permissions needed to get it working:

Azure Active Directory Graph
Application.ReadWrite.All
Directory.ReadWrite.All
User.Read

Using a MSI there is no option in the Azure Portal to add the needed API permissions. With PowerShell there is but currently I don't know how to add the type "delegated" instead of "application"

Your tenant id (in Azure Portal, under Azure Active Directory -> Overview )

$TenantID="xxx"

Microsoft Graph App ID (DON'T CHANGE)

$GraphAppId = "00000003-0000-0000-c000-000000000000"

Name of the manage identity (same as the Logic App name)

$DisplayNameOfMSI="xxx"

Check the Microsoft Graph documentation for the permission you need for the operation

$PermissionName = "User.Read.All"
$PermissionName1 = "Application.ReadWrite.All"
$PermissionName2 = "Directory.ReadWrite.All"

Install the module (You need admin on the machine)

Install-Module AzureAD

Connect-AzureAD -TenantId $TenantID
$MSI = (Get-AzureADServicePrincipal -Filter "displayName eq '$DisplayNameOfMSI'")
Start-Sleep -Seconds 10
$GraphServicePrincipal = Get-AzureADServicePrincipal -Filter "appId eq '$GraphAppId'"
$AppRole = $GraphServicePrincipal.AppRoles | Where-Object {$.Value -eq $PermissionName -and $.AllowedMemberTypes -contains "Application"}
$AppRole1 = $GraphServicePrincipal.AppRoles | Where-Object {$.Value -eq $PermissionName1 -and $.AllowedMemberTypes -contains "Application"}
$AppRole2 = $GraphServicePrincipal.AppRoles | Where-Object {$.Value -eq $PermissionName2 -and $.AllowedMemberTypes -contains "Application"}
New-AzureAdServiceAppRoleAssignment -ObjectId $MSI.ObjectId -PrincipalId $MSI.ObjectId -ResourceId $GraphServicePrincipal.ObjectId -Id $AppRole.Id
New-AzureAdServiceAppRoleAssignment -ObjectId $MSI.ObjectId -PrincipalId $MSI.ObjectId -ResourceId $GraphServicePrincipal.ObjectId -Id $AppRole1.Id
New-AzureAdServiceAppRoleAssignment -ObjectId $MSI.ObjectId -PrincipalId $MSI.ObjectId -ResourceId $GraphServicePrincipal.ObjectId -Id $AppRole2.Id

I also came across this recently and while the API permission "Application.ReadWrite.All" on "Azure Active Directory Graph" was allowing Vault to create and delete app registrations / service principals we did not get approval from the owner of our production AAD tenant to grant these API permission as it would allow also to manage (delete) app registrations that were not created by Vault.
We hence tested with the API permission "Application.ReadWrite.OwnedBy" and this also showed successful in our tests. This would mean that Vault can only delete app registrations it had created previously.

The CLI command to add this permission would be the following:

az ad app permission add --id <id-of-app-registration-used-by-vault> --api 00000002-0000-0000-c000-000000000000 --api-permissions 824c81eb-e3f8-4ee6-8f6d-de7f50d565b7=Role

Maybe others can confirm our findings. If so I would suggest to adjust the documentation in https://www.vaultproject.io/docs/secrets/azure which just says that "Read and write all applications" permission in AAD is required. We could mention that permissions are required on the legacy API (not Graph API) plus that "Application.ReadWrite.OwnedBy" is least-privilege enough.

As of writing this, Azure Portal does not allow you to choose "Azure Active Directory" in API perms and only allows "Microsoft Graph". Got around this UI limitation using Azure CLI. CLI Command Src
Try the first command given in the example to add Delegated perms to the vault app for User.Read:
az ad app permission add --id eeba0b46-78e5-4a1a-a1aa-cafe6c123456 --api 00000002-0000-0000-c000-000000000000 --api-permissions 311a71cc-e848-46a1-bdf8-97ff7156d8e6=Scope

Just replace the --id field with vault's client_id. One you do that the UI element appears on Azure Portal and then you can add the other perms on the portal itself by clicking on the "Azure Active Directory Graph" field under "API Permissions":

  • Directory.ReadWrite.All
  • Application.ReadWrite.All

https://techcommunity.microsoft.com/t5/azure-active-directory-identity/end-of-support-for-azure-ad-graph-permission-sign-up-through/ba-p/2464404
As the previous user wrote, the Azure Portal did not allow this anymore, now this portal feature has officially been end-of-lifed. Given that the Graph API will be retired alltogether soon I think the switch to Graph API should really happen now !

Hi

What are the plans to make this work once the Active Directory Graph API is retired in June 2022? The documentation here lists a load of graph permissions which need applying but these simply do not work. Applying the permissions in the document gives the following error:

graphrbac.ApplicationsClient#Create: Failure responding to request: StatusCode=403 -- Original Error: autorest/azure: Service returned an error. Status=403 Code="Unknown" Message="Unknown service error" Details=[{"odata.error":{"code":"Authorization_RequestDenied","date":"2022-04-08T15:28:09","message":{"lang":"en","value":"Insufficient privileges to complete the operation."},"requestId":"921da942-7739-4f1f-9b46-fb5e8b4712af"}}]

As soon as I apply the old recommended permissions from the Active Directory Graph API the azure secret engine works and is able to create SPs without issue. For reference these are the permissions in the the AD Graph API:

image

Thanks

@FiggyRoll Hi

If I am reading your comment correctly, you were trying to apply permission required for Microsoft Graph to a setup for Active Directory Graph API.

As soon as I apply the old recommended permissions from the Active Directory Graph API the azure secret engine works

The Azure Secrets Engine Learn Guid has everything you need to setup Microsoft Graph.

For more info on AAD and migrating from AAD to Microsoft Graph, please see the Azure Secrets Engine docs.

Hi @fairclothjm

Apologies for commenting on a closed thread. Unfortunately those permissions do not work. I have applied all the API permissions specified in the document and yet the error persists. One question I do have is around the 'use_microsoft_graph_api=true' requirement. Even though I have set this, if I then do a read on the config for the secret engine, it does not show this value. It only shows the tenant ID, client ID, secret and environment.

Is this normal behaviour?

Thanks

Hi @fairclothjm

As @FiggyRoll pointed out, the docs you listed and the respective examples do not work... I raised this issue also here: #94

Thank you for having a look at it.

Update: Now working, possibly my own fault

So for anyone else that stumbles across this and has the same issue. I got this working last night and 99% sure its completely my own fault for not reading the doc properly. Noticed that the docs state to use graph API then use vault version 1.9 and above, we where running 1.8.x

Upgraded to 1.9 and could then see the line use_microsoft_graph_api=true and it now worked to create the service principal. Still had one outstanding issue though where it could not add the dynamic SP to an AzureAD group.

I cant see anywhere obvious this is specified in the doc, but I needed to make the SP linked to the Azure secret engine and owner of the AAD group.

@fairclothjm is that bit in the doc and I have just missed it?

Thanks

@FiggyRoll Glad it is working for you!

We now have versioned docs at vaultproject.io, so we don't specifically call out required versions in general. The learn guides are not versioned however, so that may have been the source of your issue.