Saturday 24 June 2023

Fix Terraform Azure AD Group Read with "403 Insufficient privileges" in Azure Pipelines

 For deploying Azure resources  with Terraform via Azure pipelines we use service principals (SPN) to connect to Azure from Azure DevOps. You might encounter "403 Insufficient privileges" errors while trying to read Azure AD groups data, which you might want to use to create role assignment in the new resources you are provsioning with Terraform. For example it can be a Azure AD group referred as data as shown below.

# refer to sub_owners AD group to assign as aks admins
data "azuread_group" "myteam" {
  display_name     = "sub_owners"
  security_enabled = true

 Let's look at the how to resolve the exception "403 Insufficient privileges".

The Terraform documentation here points out the service principal used to deploy Azure resources with Terraform vial Azure pipline requires to have Group.Read.All or Directory.Read.All .

To add the required permission open the service principal application (not the Enterprise application) in Azure AD.

Open the API permissions tab and click on Add a permission.

Select Microsoft Graph in the side popo up.

Search gor group and select  Group.Read.All and click Add permissons.

Then you have to click on Grant Admin concent for the AD.

This will enable the  Group.Read.All for the service principal.

With this you would be able to run terraform successfully to read the Azure AD group as data, and assign them to newly created resources as role assignments. For eample in below code segment the AD group is Assigned to AKS cluster Admin.

# aks cluster
resource "azurerm_kubernetes_cluster" "aks" {

  # any autoscaling should not be reset by TF after intial setup
  lifecycle {
    ignore_changes = [default_node_pool[0].node_count]

  name                         = "${var.PREFIX}-${var.PROJECT}-${var.ENVNAME}-aks"
  kubernetes_version           = local.kubernetes_version
  sku_tier                     = "Standard"
  location                     = azurerm_resource_group.rg.location
  resource_group_name          =
  dns_prefix                   = "${var.PREFIX}-${var.PROJECT}-${var.ENVNAME}-aks-dns"
  node_resource_group          = "${var.PREFIX}-${var.PROJECT}-${var.ENVNAME}-aks-rg"
  image_cleaner_enabled        = false # As this is a preview feature keep it disabled for now. Once feture is GA, it should be enabled.
  image_cleaner_interval_hours = 48

  network_profile {
    network_plugin    = "azure"
    load_balancer_sku = "standard"

  default_node_pool {
    name                 = "demolinux"
    orchestrator_version = local.kubernetes_version
    enable_auto_scaling  = true
    node_count           = 1
    min_count            = 1
    max_count            = 10
    max_pods             = 110
    vm_size              = "Standard_B4ms"
    vnet_subnet_id       =
    type                 = "VirtualMachineScaleSets"
    scale_down_mode      = "Delete"
    zones                = ["1", "2", "3"]

  identity {
    type = "SystemAssigned"

  windows_profile {
    admin_username = "nodeadmin"
    admin_password = "semesecurepwd"

  ingress_application_gateway {
    gateway_id =

  key_vault_secrets_provider {
    secret_rotation_enabled = false

  azure_active_directory_role_based_access_control {
    azure_rbac_enabled = false
    managed            = true
    tenant_id          = "tenantguid"

    # add my team as cluster admin
    admin_group_object_ids = [
    data.azuread_group.myteam.object_id] # azure AD group object ID



In addition to Group.Read.All  you can add Directory.Read.All  or other permissions to ther service principal following the steps described above.

No comments:

Popular Posts