Using foreach and referencing the created resources

I am just beginning my terraform journey and was starting with what I considered to be a simple task, creating 4 users and assigning them to a group.

In the documentation for for_each there is this example:

resource "aws_iam_user" "the-accounts" {
  for_each = toset( ["Todd", "James", "Alice", "Dottie"] )
  name     = each.key
}

This works great. but I cannot figure out how to apply that to this:

resource "aws_iam_group_membership" "developers" {
  name = "developer-group-membership"
  users = ????
  group = aws_iam_group.developers.name
}

What is the proper way to create users and then add those users to a group? As a newb, this seems more complicated than it should be so I assume I am missing something.

Thanks in advance!

Hi @api-mike,

From the docs it looks like this users argument wants a set of IAM usernames. With what you showed here the usernames will all match the instance keys of your aws_iam_user.the-accounts instances anyway, and so a relatively easy answer would be to use keys(aws_iam_user.the-accounts), but that’s not really robust because it doesn’t fully describe to Terraform that the group memberships depend on the users, and so I would suggest something like this instead:

resource "aws_iam_group_membership" "developers" {
  name  = "developer-group-membership"
  users = [for u in aws_iam_user.the-accounts : u.name]
  group = aws_iam_group.developers.name
}

The above is a for expression, which is a general mechanism for deriving one collection from another. In this case, it’s deriving a list of usernames from a map of objects representing the aws_iam_user instances.

Because this expression includes a reference to aws_iam_user.the-accounts, Terraform can see that it must create the user objects before it tries to create the group membership object.

I also made this refer to the name attribute of each user, rather than taking the key, because then if you were to refactor in future so that the instance keys and the usernames are not equal then this would still select the name that IAM expects, rather than the name that Terraform is using for its own tracking. (They happen to be the same today because you assigned each.key to name, but that isn’t required to be so.)

3 Likes

Thanks so much for your response and detailed explanation. I appreciate the help, have been going in circles trying to figure out the right way to do this!