Skip to main content

Command Palette

Search for a command to run...

Permanent PIM Eligible Role Assignment with Infrastructure as Code

Updated
5 min readView as Markdown

Permanent PIM Eligible Role Assignment with Infrastructure as Code

Introduction

This article will go over how to enable a PIM role assignment permanently without any expiration date for Azure resources with Terraform. You might encounter a 365-day limitation on PIM eligible role assignments. This article will show how to work around that.

What I was trying to achieve

While improving our security posture, we were switching from permanent normal role assignments to PIM eligible role assignments for our Entra ID groups. While enabling PIM on these, we ran into a constraint on the maximum eligible assignment duration: The management policy did not allow more than 365 days, so we couldn't set the assignment to have no expiration date. Our goal was to keep administrative overhead low and keep the PIM eligibility permanent on the assigned groups. Without a fix, we'd be renewing role assignments every 365 days, which at scale is untenable

Prerequisites

Requirement Details
Licensing Entra ID P2 / Governance
Graph API permissions Group.Read.All, Group.Create (if also creating groups), User.Read.All
Azure RBAC User Access Administrator is sufficient at the resource group, subscription, or management group level for the identity running Terraform
Terraform provider version azurerm 4.79.0 or later

Understanding the components

PIM for Azure resources vs. Entra roles

PIM can be enabled for Entra roles such as Global Administrator, Security Reader, etc., and the scope is tenant-wide.

But PIM can also be enabled for Azure resources that handle Azure RBAC roles such as Owner, Contributor, etc., and the scope can be set to RG, subscription, or management group level.

My scenario covers PIM eligibility for Azure resources.

Active vs. Eligible

An active assignment means the user has the role right now and can use it without any activation step. This is what a normal azurerm_role_assignment grants, and also what azurerm_pim_active_role_assignment gives but under PIM governance.

An eligible assignment means the user is allowed to hold the role but does not have it until they explicitly activate it in PIM, also known as the just-in-time (JIT) model. This is what my scenario covers, with azurerm_pim_eligible_role_assignment.

Role management policy

A crucial component to understand is the role management policy. This ruleset governs how an eligible assignment or activation behaves. This policy handles multiple controls, one of which is eligibility expiration. This is set at the RG, subscription, or management group level and covers all assignments under the respective scope.

Key observations

Provider version in lock file

We had a lot of back and forth with azurerm_pim_eligible_role_assignment because of an older version of azurerm pinned in our lock file. That version's resource block didn't support all arguments — pin at least 4.79.0 (or latest) and you won't need to think about it.

Existing management policy on the target scope

Before editing, check the management policy already set at your target scope. I was never able to find a dedicated portal view for the underlying policy object itself — the closest is Microsoft docs on Azure resource role settings, which covers the same settings from the role-settings UI. A policy applied at a higher scope, like the subscription, is inherited by every resource group beneath it; it isn't scoped to just the one resource you're editing. That inheritance might make you wonder whether a permanent eligible assignment weakens protection further down. It doesn't: permanent eligibility only changes how long a principal is allowed to stay eligible, not what happens at activation — MFA, approval, and any narrower policy set at a lower scope still apply. What changes is who's responsible for cleaning up stale eligibilities, not which controls fire.

Dependencies

Terraform's apply order comes from resource attribute references, and here the two resources don't reference each other — they each just take scope and role_definition_id as separate input variables. Without an explicit dependency, Terraform is free to create the azurerm_pim_eligible_role_assignment before the azurerm_role_management_policy update has landed, which means the assignment gets created under whatever policy is already active on that scope. If that policy still requires an expiration, the apply fails on the same 365-day constraint from the introduction. Add depends_on = [azurerm_role_management_policy.management_policy] to the role assignment resource block so the policy is guaranteed to apply first.

Terraform automation

Below is an example of how to create:

  • Entra ID group

  • Management policy with no expiration

  • PIM eligible role assignment with no expiration

Group creation

resource "azuread_group" "group" {
  display_name     = var.group_name
  owners           = var.owners
  security_enabled = true
}

Management policy creation with no expiration for PIM role assignments

resource "azurerm_role_management_policy" "management_policy" {
  scope              = var.subscription_id
  role_definition_id = var.role_definition_id

  eligible_assignment_rules {
    expiration_required = false # Ensures expiration is not required in role assignment
  }
}

PIM eligible role assignment creation without expiration

resource "azurerm_pim_eligible_role_assignment" "pim_role_assignment" {
  scope              = var.subscription_id
  role_definition_id = var.role_definition_id
  principal_id       = var.principal_id
  depends_on         = [azurerm_role_management_policy.management_policy] # ensures assignment is compliant with new management policy
}

IAM overview in portal

The screenshot below shows both assignments in the Azure portal's IAM blade. One active permanent, one eligible permanent:

Conclusion

If I did this again, I would understand and check the existing role management policy before touching anything. This is the most crucial part of the setup and requires a good understanding of the backend governance that is not visible in the Entra ID portal.

That upfront effort only pays off if you're repeating it: I'd recommend this approach to any team managing role assignments at scale, but not necessarily for a single role assignment — such a setup would be overkill.

blog

Part 1 of 1

Technical blogs and articles