Planet PowerShell logo

Contents

Managing Azure Ad Users and Groups With Infrastructure as Code Using Terraform

In this post, I will explain how you can install and get started with Terraform. I will then show how you can use Terraform for building your users and groups in Azure Active Directory with Infrastructure as Code.

Building your entire directory of users with Infrastructure as Code will be useful for making easy onboardings of new users, and a very verbose and descriptive layout of all your users. You can also utilize Terraform modules for making different standards of users if you have a specific user type with specific group permissions.

Deploying and managing your Azure Active Directory with Terraform is a huge subject and I will write posts on many of the different resources you can configure with Terraform. But for this post, I will just show how you can get started with Terraform and maybe start exploring the tool yourself.

Installing Terraform

Installing Terraform on WIndows

To install Terraform on Windows you need to head over to the Hasicorp website. Then download the “Amd64” version. This will download a zip folder that contains the terraform binary. Extract the file to a folder to C:\Program Files\terraform.

Now before you will be able to run the program you will need to add it to your path. To do this open Win+R and type “sysdm.cpl”. Then click on the “Advanced” tab –> “Environment Variables”

/images/managing-azure-ad-users-and-groups-with-infrastructure-as-code-using-terraform/administrating_azure_ad_with_terraform_01.png

Then click on the variable “Path” and click on “Edit”. Then click on “New” and paste in the path where you extracted the terraform binary: C:\Program Files\terraform

You can now open a PowerShell terminal and write terraform, to see if the command work. If not, then you might need to restart your terminal.

If the command worked you should see an output similar to below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
terraform

Usage: terraform [global options] <subcommand> [args]

The available commands for execution are listed below.
The primary workflow commands are given first, followed by
less common or more advanced commands.

Main commands:
  init          Prepare your working directory for other commands
  validate      Check whether the configuration is valid
  plan          Show changes required by the current configuration
  apply         Create or update infrastructure
  destroy       Destroy previously-created infrastructure
...

Installing Terraform on MacOS

Installing terraform on MacOS can be done either through homebrew or with a binary download.

If you are using macOS with an M1 chip, I would suggest you download the binary package, and be sure to choose “Arm64”

Otherwise, if you are using a Mac with an Intel chip, you can download it through homebrew with the commands:

1
2
brew tap hashicorp/tap
brew install hashicorp/tap/terraform

You can download the binary from the HasiCorp website

Creating a user and a group with Terraform

If you want to see the code I have used in this example you can head over to my github repo).

Now to get started I have created a new file named: main.tf. Inside this file, I need to start by selecting which provider I want to use. The provider can be different if you are deploying to Azure, AWS VMware, or any other place. You can read all about the different providers here Browse Providers | Terraform Registry, and the documentation for how to use them.

If you want to read about the Azure Active Directory provider you can find it here: Docs overview | hashicorp/azuread | Terraform Registry.

Adding a provider

Inside your main.tf file you will need to add the Azure Active Directory provider. You do this by adding the code block:

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

All this do is stating, that you are using the azuread provider and the source for the provider is “hashicorp/azuread”, and that you want to use the version 2.15.0.

Then once the provider has been added you can start defining the resources you want to be deployed to Azure AD.

Adding a user resource

To create a user you will need to define it inside the main.tf file and you will need to add the following code block:

1
2
3
4
5
6
resource "azuread_user" "user" {
  user_principal_name = "[email protected]"
  display_name        = "TF Test01"
  mail_nickname       = "tf-test01"
  password            = "[email protected]"
}

Here i create a new resource with the type: “azuread_user”, and i have named it “user”.

I then define a user_principal_name, display_name, mail_nickname and a password the user i want to create.

If you read the documentation for the azuread_user resource, you can see that you will be able to add meta data such as: city, country, company_name, job_title, mobile_phone, manager_id etc. So more or less all the attributes you are used to add to a user in Azure Active Directory.

Adding a group resource

Now I also want to create a group in my Azure Active Directory, and I want my newly created user to be a member of this group. To do this I will need to add two more resources to my main.tf file. To create the group I will need to add the resource: “azuread_group”. And to add my user as a member of this group I will need the resource: “azuread_group_member”.

To add the group I will add the following code block:

1
2
3
4
resource "azuread_group" "group" {
  display_name     = "tf_group01"
  security_enabled = true
}

Here i create a new resource type: “azuread_group” and i give the resource the name of: “group”. I then give the group the display_name: “tf_group01” and select: security_enabled = true to define the group as a security group.

Then to add a member to the group i will add the following code block:

1
2
3
4
resource "azuread_group_member" "group_member" {
  group_object_id  = azuread_group.group.id
  member_object_id = azuread_user.user.id
}

Here I add the resource type “azuread_group_member” and give it the name: “group_member”.

I then define the group object id by calling a terraform variable: “azuread_group.group.id”

This variable is first looking at the resource type: “azuread_group” in then finds the specific type with the name: “group” and then it grabs the “id” of that specific resource.

Exactly the same happens for the member_object_id here is use a terraform variable to get the id of the user I defined earlier.

Deploying the Azure AD Infrastructure

Now once I have my main.tf file ready and all the resources I want to deploy defined in the file, I can go ahead and open up my terminal and navigate to the folder with the main.tf in it.

Once I am inside the folder I will need to login into the Azure CLI. If you don’t have the CLI installed you can download it from the Microsoft Docs How to install the Azure CLI | Microsoft Docs.

To sign in to Azure CLI:

1
az login

Once I am signed in to the Azure CLI i can start preparing my terraform file by running

1
terraform init

the init command will make sure that you have all the provider modules downloaded to your machine, to be able to deploy using that specific provider.

The output will look similar to below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/azuread versions matching "~> 2.15.0"...
- Installing hashicorp/azuread v2.15.0...
- Installed hashicorp/azuread v2.15.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Here just pay attention to the message: “Terraform has been successfully initialized!”

Then once the configuration has been initialized you can run a validate command to be sure that all the code should work as expected:

1
terraform validate

hopefully you will see a message similar to below:

1
Success! The configuration is valid.

Then once the code is validated you are ready to plan out the deployment and apply it to your environment.

To do this you start by creating a terraform plan. This will, if you had already deployed resources, compare the current state with the new state you are trying to deploy.

The create the terraform plan run the command:

1
terraform plan

The output of the command will show you if any resources are being created or deleted. So here you can see if the what you wanted to happen is actually going to happen

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Terraform will perform the following actions:

  # azuread_group.group will be created
  + resource "azuread_group" "group" {
      + display_name                   = "tf_group01"
      + id                             = (known after apply)
      + mail                           = (known after apply)
      + mail_nickname                  = (known after apply)
      + members                        = (known after apply)
      + object_id                      = (known after a

So in the example output above you can see that the resource type “azuread_group” with the name “group” will be created.

Then to apply the changes to your Azure Active Directory run the command:

1
terraform apply

If I now go into my Azure Active Directory and go into Users. I can see that the user I defined in Terraform has now been created

/images/managing-azure-ad-users-and-groups-with-infrastructure-as-code-using-terraform/administrating_azure_ad_with_terraform_02.png

And if i go into Groups, I can see that the group i defined has also been created

/images/managing-azure-ad-users-and-groups-with-infrastructure-as-code-using-terraform/administrating_azure_ad_with_terraform_03.png

And I can see that the user I created is also a member of the group I created

/images/managing-azure-ad-users-and-groups-with-infrastructure-as-code-using-terraform/administrating_azure_ad_with_terraform_04.png

Deleting resource with Terraform

Now the cool thing about Terraform is that if you now want to delete a resource you have created with Terraform, it is as easy as just commenting out or deleting the resource code from the main.tf file. Terraform will then compare the new version of the main.tf file with the current state of your Azure Active Directory, and then delete the resource in your environment.

In this example, I will comment out the following resource in the main.tf file:

1
2
3
4
#resource "azuread_group_member" "group_member" {
#  group_object_id  = azuread_group.group.id
#  member_object_id = azuread_user.user.id
#}

I will then run the commands:

1
2
3
4
5
terraform validate

terraform plan

terraform apply

Here the terraform command “plan” will tell me which resources will be destroyed

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Terraform will perform the following actions:

  # azuread_group_member.group_member will be destroyed
  # (because azuread_group_member.group_member is not in configuration)
  - resource "azuread_group_member" "group_member" {
      - group_object_id  = "669f2ded-4fad-4b30-92ac-3101d421ff2c" -> null
      - id               = "669f2ded-4fad-4b30-92ac-3101d421ff2c/member/e0259618-0a1c-47ea-8b2f-a1e121e3b7df" -> null
      - member_object_id = "e0259618-0a1c-47ea-8b2f-a1e121e3b7df" -> null
    }

Plan: 0 to add, 0 to change, 1 to destroy.

and here i see that a group membership will be destroyed.

If i now go to my Azure Active Directory I should see that my user still exists and my group still exists. But the user is no longer a member of the group.

/images/managing-azure-ad-users-and-groups-with-infrastructure-as-code-using-terraform/administrating_azure_ad_with_terraform_05.png

Conclusion

Terraform is a great tool for deploying anything to more or less any provider being a cloud provider or an on-premises provider such as VMware, Hyper-V, or Windows Active Directory. So if you are running a 100% cloud setup then deploying your entire environment with Terraform will be possible, but even if you are running a hybrid setup, you most probably will be able to keep everything in code.

The great thing about keeping all your configurations and your entire infrastructure in code, is that you can add it to source control, to be able to roll back quickly if anything happens, and see every little change that’s being made to your infrastructure. You will also be able to spin up new resources faster, just by copy/pasting the code blocks.

I definitely think that managing your infrastructure, but also your Identity provider such as Active Directory or Azure Active Directory is the way to go.