Terraform's own recommended practices documentation suggests managing user accounts in IaC — and if you read that and felt like something was off, you're not wrong. The recommendation makes sense for service accounts and machine identities tied to infrastructure resources. For human user accounts that need to respond to HR events, role changes, and terminations on a continuous and unpredictable basis, trying to drive that lifecycle through Terraform state quickly runs into the exact idiosyncrasies people have been documenting for years.
The practical conclusion most engineers reach in production — and what the OP landed on in this thread — is to keep Terraform for what it's genuinely good at (infrastructure resources, security group definitions, role assignments) and use a different tool for the human identity layer. The question is what that different tool should be.
Why Terraform State Breaks Down for Human User Accounts
Terraform's state model assumes that resources are relatively stable and that changes are intentional, planned, and applied through a pipeline. Infrastructure resources fit that model well. Human users don't.
A new hire starts on Monday. An employee is terminated mid-sprint. Someone transfers departments and needs their access updated the same day. A contractor's access expires. These events happen continuously, driven by HR systems rather than code commits, and they need to execute immediately rather than waiting for the next pipeline run. Wrapping that in a Terraform module means every joiner, mover, and leaver event requires a code change, a PR, a pipeline trigger, and a state apply — and the state file accumulates every user account your organization has ever had.
One commenter in this thread articulated the architectural boundary clearly: Terraform is the right tool for assigning security groups to Azure resources and mapping groups to roles. User assignments to those security groups are out of band from IaC. The project leader requests group membership changes; they're responsible for the access reviews. That's the right separation — IaC manages the infrastructure layer, and a separate system manages who belongs in what group.
The other commenter's framing is equally useful: use AZ CLI or PowerShell scripts to create the users Terraform uses, in a separate project and repository with tight access controls. For service accounts tied to infrastructure resources, Terraform manages the lifecycle holistically — created when the service is created, destroyed when it becomes unnecessary. For actual human users, non-state-dependent tools handle it better.
The problem with scripts for human lifecycle management is the same problem that comes up in every thread on this topic: PowerShell scripts work until Microsoft changes something, someone leaves and the scripts become unmaintained, or the organization scales past the point where per-script maintenance is sustainable.
The Right Architecture: IaC for Infrastructure, IGA for Human Identity
The practical production architecture separates two concerns that Terraform conflates when you try to manage human users in state:
Infrastructure layer (Terraform's domain): Security group definitions, role assignments, resource-to-group mappings, service account creation tied to infrastructure resources. Terraform manages this well because these resources are relatively stable, change through deliberate commits, and don't need to respond to HR events.
Identity lifecycle layer (IGA's domain): Human user account creation, group membership assignment based on role, license allocation, mover workflows for department transfers, offboarding triggered by HR termination events, access reviews. These are event-driven, continuous, and HRMS-sourced — none of which fits Terraform's state model.
Zluri sits in the identity lifecycle layer. It connects to your HRMS as the authoritative source of truth and responds to the events Terraform can't handle natively: a new hire record appearing in BambooHR, a department change in Workday, a termination status update that needs to trigger immediate account disablement and group removal in Azure AD.
Automating the Joiner-Mover-Leaver Flow in Azure AD Without Terraform
When a new hire is added to the HRMS, Zluri detects the event and runs an Onboarding Playbook automatically. The playbook creates the Azure AD account via direct API, assigns the correct licenses, and adds the user to the security groups appropriate for their role and department. No code change, no pipeline trigger, no state file update. The account is ready before day one without any IT manual intervention.
For role changes — the mover scenario that's hardest to handle in IaC — Zluri detects the attribute change in the HRMS and runs a workflow that simultaneously removes the user from groups tied to their previous role and adds them to the groups for their new position. Both sides of the transition happen in the same automated run, preventing the privilege accumulation that occurs when only the provisioning side of a role change gets handled.
For terminations, Zluri detects the status change and triggers an Offboarding Playbook: the Azure AD account is disabled, the user is removed from all groups, licenses are reclaimed. For downstream applications beyond Azure AD — including tools not connected via SSO — the Discovery Engine identifies every application the user had access to and triggers the appropriate deprovisioning action per app, whether that's a direct API call, a custom HTTP request, or a tracked manual task routed to the app owner.
The Microsoft identity governance capabilities mentioned in the thread — PIM, entitlement management, lifecycle workflows, access packages with expiration dates — are genuinely useful for specific scenarios, particularly guest user access with defined expiration. For the core JML automation at scale across Azure AD and the broader SaaS stack, an IGA orchestration layer handles the breadth that native Microsoft tooling doesn't reach on its own.
What Terraform Should Still Own
The right answer isn't to remove Terraform from the identity picture — it's to be precise about what belongs in IaC and what doesn't.
Terraform owns security group definitions in Azure, role-to-group mappings, resource access policies, and service accounts tied to infrastructure resources. When a new project spins up and needs a set of security groups with defined permissions, Terraform creates them. When the project ends, Terraform destroys them.
Zluri owns who belongs in those groups. When a new hire joins the Engineering team, Zluri adds them to the engineering-prod-access group that Terraform defined. When they transfer to Sales, Zluri removes them from Engineering groups and adds them to Sales groups. The group itself is IaC. The membership is identity lifecycle automation driven by HR events.
Keeping these concerns separate means neither system is doing work it's poorly suited for — and the state file stays clean of the continuous churn that human user accounts generate.
Frequently Asked Questions
Should you manage Azure AD user accounts in Terraform?
Terraform works well for service accounts tied to infrastructure resources — they follow the same lifecycle as the resource and can be managed holistically in state. For human user accounts, the event-driven nature of HR-sourced lifecycle events (new hires, role changes, terminations) doesn't fit Terraform's state model well. Most production environments keep infrastructure in Terraform and handle human user lifecycle through a dedicated IGA platform or scripts, with Terraform referencing groups rather than owning user membership.
What is the difference between IaC user provisioning and IGA user provisioning?
IaC provisioning (Terraform, Pulumi, etc.) is designed for infrastructure resources that change through deliberate code commits and pipeline runs. IGA provisioning responds to HR events — a new hire appearing in the HRMS, a role change, a termination — and executes immediately without a code change. IaC is the right tool for defining what security groups exist and what roles they map to. IGA is the right tool for managing who belongs in those groups based on employment status and role.
What are the limitations of PowerShell scripts for Azure AD user lifecycle management?
PowerShell scripts work for stable, well-documented workflows but break when Microsoft changes an API or deprecates a module, when the person who wrote the script leaves, or when the organization scales past the point where per-script maintenance is sustainable. Scripts also don't provide the audit trail, access review, and compliance reporting that IGA platforms include — which matters specifically for SOC 2 and ISO 27001 requirements around access management evidence.
How do you automate the mover workflow in Azure AD when an employee changes departments?
Mover automation requires detecting the attribute change in the HRMS (department, title, or manager field updating), then simultaneously revoking access tied to the previous role and provisioning access for the new role. Terraform can't respond to HRMS events, and scripts typically handle only one side of the transition. An IGA platform like Zluri runs a Mover workflow triggered by the HRMS attribute change that handles both deprovisioning and provisioning in the same automated run.
See How Zluri Maps to Your Azure AD Environment
If you're drawing the line between what Terraform should own and what needs a dedicated identity lifecycle layer, see how Zluri maps to your Azure AD environment — including the group membership automation that keeps your IaC layer clean of user lifecycle churn.












