Planet PowerShell logo

Contents

Provision Multiple Users in Azure Ad With Infrastructure as Code, Using Terraform

A couple of days ago I wrote a post on how you can get started with Terraform, and how you can use it to provision users and groups in your Azure Active Directory Tenant. In that post, I showed how you can hardcode a user’s information inside the Terraform main.tf file. Although you could create a terraform module and keep the user’s information in that module, it might be easier to use something like a CSV file.

So in this post, I will show how you can advance some of the Terraform I showed in the last post, and how you could create a setup for provisioning your users in a bit more production-ready setup.

If you haven’t read the last post you might want to check it out here: Managing Azure Ad Users and Groups With Infrastructure as Code Using Terraform - ScriptingChris

You will be able to find all code used in this post on my github: BlogContent/IaC/Terraform/tf_aad_users_and_groups02 at main · ScriptingChris/BlogContent (github.com)

Setting up the main.tf file and adding the Azure AD Provider

Just like in the last post I will create a new project folder, in which I will create a main.tf file. I will then add the provider-specific information for adding Azure AD as a provider.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
terraform {
  required_providers {
    azuread = {
      source  = "hashicorp/azuread"
      version = "~> 2.0.0"
    }
  }
}


provider "azuread" {}

Reading and looping through the users.csv

I have created a csv file named users.csv looking similar to the below and placed it inside my project folder.

first_name,last_name,department,job_title,domain_name
Max,Mayfield,HR,HR Assistant,scriptingchris.tech
Will,Byers,Finance,Accountant,scriptingchris.tech
Dustin,Henderson,IT,IT Supporter,scriptingchris.tech

In this example, I have provided the user attributes: first_name, last_name, department, and job_title. I will also provide a user_principal_name, a display_name, and a password, but these attributes will be created dynamically with terraform functions.

For the attributes, you can provide all of the user’s attributes you are used to from Azure AD. If you want to read more about it, you can have a look at the Azure AD Provider documentation: azuread_user | Resources | hashicorp/azuread | Terraform Registry.

For reading the csv file I will add the following code block to my main.tf file.

1
2
3
locals {
  users = csvdecode(file("${path.module}/users.csv"))
}

I will then create a foreach loop, which will loop through all the users in the csv file and provision them in Azure AD. This foreach loop will run inside the resource “azuread_user”

to create the loop add the following code block:

1
2
resource "azuread_user" "users" {
  for_each = { for user in local.users : user.first_name => user }

Now inside the foreach loop, I will start generating the user’s user_principal_name. To do this I can use a built-in Terraform function called format(). This can be used for combining multiple strings into a single string. You can read more about the function here.

for creating the user_principal_name I will add the following code block:

1
2
3
4
5
6
user_principal_name = format(
  "%s%[email protected]%s",
  substr(lower(each.value.first_name), 0 , 1),
  lower(each.value.last_name),
  local.domain_name
)

The format() function will start by defining that for the following lines it should convert to string and insert the strings characters. This is done by the verb “%s”. For this formatting it should format it like below:

first-character-of-first_name + . + lastname + @ + domain

example:

After the user_principal_name has been generated I will need to generate a password for the user. I do this with a code block very similar to creating the user_principal_name.

1
2
3
4
5
6
password = format(
  "%s%s%s!",
  lower(each.value.last_name),
  substr(lower(each.value.first_name), 0 , 1),
  length(each.value.first_name)
)

Because I am creating a very easy password I will set the attribute force_password_change to force the user to change their password the first time they login

1
force_password_change = true

Then after i have created a password i will need to create a display_name, and i can to this with the following code block

1
display_name = "${each.value.first_name} ${each.value.last_name}"

After creating the display name I will just add the rest of the attributes provided in the csv file.

1
2
department = each.value.department
job_title = each.value.job_title

and my complete main.tf file looking similar to below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
terraform {
  required_providers {
    azuread = {
      source  = "hashicorp/azuread"
      version = "~> 2.0.0"
    }
  }
}

provider "azuread" {}

locals {
  users = csvdecode(file("${path.module}/users.csv"))
}

resource "azuread_user" "users" {
  for_each = { for user in local.users : user.first_name => user }
  
  user_principal_name = format(
    "%s%[email protected]%s",
    substr(lower(each.value.first_name), 0 , 1),
    lower(each.value.last_name),
    lower(each.value.domain_name)
  )

  password = format(
    "%s%s%s!",
    lower(each.value.last_name),
    substr(lower(each.value.first_name), 0, 1),
    length(each.value.first_name)
  )

  force_password_change = true

  display_name = "${each.value.first_name} ${each.value.last_name}"
  department   = each.value.department
  job_title    = each.value.job_title
}

Provisioning the users in Azure Active Directory

Now to provision the users in Azure Active Directory you will need to start logging into azure-cli

1
az login

After you have logged into azure cli you can start initializing your terraform project by running the command:

1
terraform init

If the initialization was successful you validate your terraform file by running the command:

1
terraform validate

If your validation was successful you can create a terraform plan by running the command:

1
terraform plan

If the terraform plan was successful you should now be provided with an output showing you what exactly will be provisioned in Azure Active Directory.

Here is an example of one user

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# azuread_user.users["Dustin"] will be created
+ resource "azuread_user" "users" {
  + about_me                       = (known after apply)
  + account_enabled                = true
  + business_phones                = (known after apply)
  + creation_type                  = (known after apply)
  + department                     = "IT"
  + display_name                   = "Dustin Henderson"
  + external_user_state            = (known after apply)
  + force_password_change          = true
  + id                             = (known after apply)
  + im_addresses                   = (known after apply)
  + job_title                      = "IT Supporter"
  + mail                           = (known after apply)
  + mail_nickname                  = (known after apply)
  + object_id                      = (known after apply)
  + onpremises_distinguished_name  = (known after apply)
  + onpremises_domain_name         = (known after apply)
  + onpremises_immutable_id        = (known after apply)
  + onpremises_sam_account_name    = (known after apply)
  + onpremises_security_identifier = (known after apply)
  + onpremises_sync_enabled        = (known after apply)
  + onpremises_user_principal_name = (known after apply)
  + password                       = (sensitive value)
  + proxy_addresses                = (known after apply)
  + show_in_address_list           = true
  + user_principal_name            = "[email protected]"
  + user_type                      = (known after apply)
}

Now that you have reviewed your terraform plan, you are ready to provision the users in Azure AD. To do this run the command:

1
terraform apply -auto-approve

if everything went well you should now be able to see your new users in your Azure Active Directory

/images/provision-multiple-users-in-azure-ad-with-infrastructure-as-code-using-terraform/using-terraform-with-azuread.png

Now if you want to remove the resources you have created in your Azure Active Directory Tenant you can run the command:

1
terraform destroy