azure, terraform,

Grant Azure AD Admin Consent programmatically (with Terraform)

Jun 25, 2022 · 2 mins read · 19 views · Post a comment

Admin Consent by definition enables granting access to Azure-registered applications that requires admin approval securely.

Simply put, the app registers permissions that require admin consent are usually permissions that allows access to sensitive data in your org. So, when a user tries and fails to access an app, they send a request for admin approval. Now, if you want your app to work by any means, and you click the button (grant the admin consent), this will lead to accepting it for all users who are using the app.

In my case, I had an app with delegated Microsoft Graph API permissions which needless to say, some of them required Admin Consent – Directory.Read.All, Group.Read.All and User.Read.All.

azure ad grant admin consent

It’s a no sweat to grant the permissions from the Portal tho, so let’s see how it can be done in an automated IaC way by using Terraform.

Prerequisites

  • Azure account
  • Terraform

Solution

Before anything else since I’m taking the Microsoft Graph API permissions as an example, the Global Administrator Azure AD role is a must!

Example code snippet:

## variables.tf
variable "microsoft_graph_id" {
  type = string
}

variable "admin_consent_scope" {
  type = string
}

## terraform.tfvars
microsoft_graph_id  = "<get_graph_object_id_from_the_cli_as_shown_below>"
admin_consent_scope = "User.Read.All Group.Read.All Directory.Read.All"

## main.tf
resource "azuread_service_principal" "cloudflare_access" {
  application_id = azuread_application.cloudflare_access.application_id
  owners         = [data.azuread_client_config.current.object_id]
}

resource "null_resource" "grant_admin_consent" {
  triggers = {
    resourceId = var.microsoft_graph_id
    clientId   = azuread_service_principal.cloudflare_access.object_id
    scope      = var.admin_consent_scope
  }

  provisioner "local-exec" {
    command = <<-GRANTCONSENTCMD
      az rest --method POST \
        --uri 'https://graph.microsoft.com/v1.0/oauth2PermissionGrants' \
        --headers 'Content-Type=application/json' \
        --body '{
          "clientId": "${self.triggers.clientId}",
          "consentType": "AllPrincipals",
          "principalId": null,
          "resourceId": "${self.triggers.resourceId}",
          "scope": "${self.triggers.scope}"
        }'
      GRANTCONSENTCMD
  }
}

Note(s):

  • The resourceId gets the value of Microsoft Graph API service principal’s objectId. Though the MG API appId being 00000003-0000-0000-c000-000000000000 is the same across all Azure tenants, to find the resourceId (MG API SP’s objectId), run the following command:
    az ad sp show --id 00000003-0000-0000-c000-000000000000 --query "objectId"
    

Once you have that, save it under a TF variable var.microsoft_graph_id.

  • clientId gets the value of Azure-registered app service principal’s objectId.
  • scope gets the value of all permissions which require Admin Consent.
  • I’m sure this can be done from the Azure CLI as well, but figured it out it’s better to go all in with Terraform.

Conclusion

As always, feel free to share any questions, thoughts and opinions in the comment section below. On a side note, follow our official channel on Telegram.