Create user group and membership in Azure from a map list

Greetings.
I’m trying to create a users groups from a map of list.

This is my files.

tfe.auto.tfvars

# Groups
groups = [
  {
  name = "admins"
  members = ["admin1@example.com","admin2@example.com"]
  },
  {
  name = "users"
  members = ["user1@example.com"]
  }
]

main.tf

module "groups" {
  source   = "./modules/groups"
  groups =  var.groups
}

/modules/groups/data.tf


data "azure_client_config" "current" {}

data "azuread_user" "readusers" {
  for_each = { for i, group in var.groups : group.name => group }
  user_principal_name = each.value.members[0]
}

/modules/groups/variables.tf

variable "groups" {
  type = list(object({
    name = string
    members = list (string)
  }))
}

/modules/groups/main.tf

resource "azuread_group" "example" {
  for_each = { for i, group in var.groups : group.name => group }
  display_name     = "test"
  owners           = [data.azuread_client_config.current.object_id]
  security_enabled = true

  members = [
    data.azuread_user.readusers[each.key].object_id,
  ]
}

The mainly problem is in te data source

data "azuread_user" "readusers" {
  for_each = { for i, group in var.groups : group.name => group }
  user_principal_name = each.value.members[0]
}

The property user_principal_name doesn’t accepts list, only strings.
Tried multiples situations but doesn’t works.
Whats wrong with this?
Reallly appreaciete any help

Thank you for your detailed presentation of your existing code, including full file paths, correctly enclosed in code blocks so that it is nicely readable :slight_smile:. It is so refreshing to see a post in these forums where the asker has made things easier for potential answerers.

The important point here is to consider what you actually want to be iterating over in the data source. Since you want to look up each user once, even if the same user occurs in multiple groups, a set of user names is ideal:

  for_each = toset(flatten(var.groups[*].members))
  user_principal_name = each.value


Separately to that, in

the i, is redundant - the expression can be written as { for group in var.groups : group.name => group } and work just the same.

1 Like

@maxb Really appreciated. Works as expected with this datasource.

Finally the datasource is:

data "azuread_client_config" "current" {}

data "azuread_user" "readusers" {
  for_each = toset(flatten(var.groups[*].members))
  user_principal_name = each.value
}

And the resource is:


resource "azuread_group" "example" {
  for_each = { for group in var.groups : group.name => group }
  display_name     = each.value.name
  owners           = [data.azuread_client_config.current.object_id]
  security_enabled = true

  members = [
    for member_email in flatten(each.value.members) : data.azuread_user.readusers[member_email].id
  ]
}

With the initial data. Both groups are created with their respective members.
Thanks.

I think the flatten is redundant here.

I finally settled on the following:

variable "vms" {
  type = map(object({
...
   security_group_name = set (string)
...
  }))

note the change to “set” from the “list”

data aws_security_group sg-name {
  for_each = toset( flatten( [ for i in var.vms: i.security_group_name ] ) )
  name = each.key
}

that produces:

> data.aws_security_group.sg-name 
{
  "DSsg" = {
... 
  }
  "EFSsg" = {
   ...
  }
}

and finally the lookup :

resource "aws_instance" "this" {

  for_each = var.vms

  ami                    = data.aws_ami.AM2[each.key].id
  instance_type          = each.value.instance_type
...
  vpc_security_group_ids = [  for i in each.value.security_group_name : data.aws_security_group.sg-name[i].id]
...
}

I wonder:

  • why data.aws_security_group.sg-name returns a set of map of objects. Why not a set of objects?

Thank you.

It doesn’t. You yourself have shown Terraform displaying its value as an object of objects:

1 Like

@maxb,
Right on. My bad. Thank you for your help!