Creating AWS IAM Users and Applying Policies using Terraform
By: Tucker Clinton
Tags: Iam Policy, Aws Iam, Terraform

We can create users and groups with AWS Identity and Access Management (IAM) and manage their access to AWS services and resources through permissions.

IAM Users

Creating an IAM user:

To create a single IAM user in Terraform, create an aws_iam_user resource block and give it a name. If we only need to create one use, this is a relatively simple step.

resource "aws_iam_user" "demouser" { name = "tuckerdemo" }

Creating multiple IAM users:

There are different ways to create multiple IAM users.

We could copy and paste the resource block from our first user and give the subsequent blocks new names. However, this causes repetition of code and can be very inefficient for creating many users, as we would need to manually adjust the name for each user.

The count meta-argument can be used to copy and create a resource as many times as you define. In this case, 3.

resource "aws_iam_user" "demo" { count = 3 name = "tuckerdemo" }

The problem with using count in this way is that all 3 of the users would have the same name, “tuckerdemo”.

Using count.index after the name will give a distinct index number corresponding to each iteration of the resource block.

resource "aws_iam_user" "demo" { count = 3 name = "tuckerdemo.${count.index}" }

But, if our users need unique names that do not start the same and end with a number, this method will not be appropriate without further customization.

If we combine count.index with interpolation functions, we can customize each iteration of the count further. The interpolation functions length and element can be used for this.

element(list, index) — Returns a single element from a list at the given index. If the index is greater than the number of elements, this function will wrap using a standard mod algorithm. This function only works on flat lists.

length(list) — Returns the number of members in a given list or map, or the number of characters in a given string.

A list of unique usernames can be added to a variable in a separate file and then referenced in our resource block. Let’s create a username variable.

variable "username" { type = list(string) default = ["tucker","annie","josh"] }

For the following code, the length function will return a value of 3, for the 3 users in the username list. The element function will return the single name in the username list associated with the distinct index number of the count argument ([0]=”tucker”, [1]=”annie”, [2]=”josh”).

resource "aws_iam_user" "demo" { count = "${length(var.username)}" name = "${element(var.username,count.index )}" }

If we wanted to have an output of the arn of all the user we create, we can do that with an output file. Create an output block for “user_arn”. The “*” in the value line will indicate to output the arn for all of the aws_iam_user’s. If you only want to output a specific user’s arn, change the “*” to that users index number in the list (0, 1, 2, etc.).

output "user_arn" { value = aws_iam_user.demo.*.arn }

An alternative to using length and element is for_each.

If a resource or module block includes a for_each argument whose value is a map or a set of strings, Terraform will create one instance for each member of that map or set. In this case we use it for a set of strings, made up of the usernames.

resource "aws_iam_user" "example" { for_each = toset(["tucker", "annie", "josh"]) name = each.value }

It is important to note that for_each only supports sets and maps when used on a resource. We need to use toset to convert the list of usernames into a set. When for_each is used on a resource block, it becomes a map of resources rather than a list of resources as it does with count.

IAM Policies

An IAM policy grants IAM users access to AWS resources. AWS leverages a standard JSON Identity and Access Management (IAM) policy document format across many services to control authorization to resources and API actions.

IAM policies consist of one or more statements which include an effect (allow or deny), one or more actions (e.g., ec2:Describe*), and one or more resources (“*” refers to all resources, but to point to a specific resource we can enter the arn).

For this demo we’ll use simple policy shown below. When we run the plan command, you’ll see a “newemp_policy” will be created for each user specified in your var.tf file.

resource "aws_iam_user_policy" "newemp_policy" { count = length(var.username) name = "new" user = element(var.username,count.index) policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ec2:Describe*" ], "Resource": "*" } ] } EOF }

That wraps up this short demo on creating IAM users and policies with Terraform. There are several ways to create multiple users, so use the way that will be the most efficient for your needs. The AWS Policy Generator is a tool that can help you create JSON policy documents.