Terraform - How to create groups and users from YAML file

488 Views Asked by At

I want to create users and groups in AWS from the YAML file.

Currently, I have a YAML file like this:

Admins:
  - michael
  - jon
Developers:
  - raheem
  - kylian
Readers:
  - john
  - katy

Terraform code:

locals {
  user-group = yamldecode(file("${path.root}/groups-users.yaml"))["groups"]
  #Flatten, which crates structure like this for every user:
  #{
  #  "group" = "Admins"
  #  "user" = "michael"
  #},
  user-group-flt = flatten([
    for k1,v_groups in local.user-group : [
      for k2,v_group in v_groups : [
        for k3,v_user in v_group : {
          group = k2
          user  = v_user
        }
      ]
    ]
  ])
  #List of groups
  groups = [for d in local.user-group-flt: d.group]
  #List of users
  users  = [for d in local.user-group-flt: d.user]
  
}

module "aws_groups" {
  source = "../modules/iam/group"

  for_each = toset(local.groups)

  name = each.value
}

module "aws_users" {
  source = "../modules/iam/user"

  for_each = toset(local.users)

  name = each.value
}

I already have modules to create groups and users.

I want to loop through groups first, to create all groups listed in the YAML file (Admins, Developers, Readers), and also to loop through users, and assign them to the proper group.

Do you have an idea, of how to achieve this, or maybe even change the structure of the YAML file? Am I overcomplicating this?

Thank you

1

There are 1 best solutions below

0
Marko E On

I suspect that the example from the question is not the latest one as there are no groups for filtering. However, I think I managed to achieve what you want. In order to get the list of maps with users and groups, you would have to edit the for loop:

locals {
  user-group-flt = flatten([
    for g, members in local.user-group : [
      for u in members : {
        group = g
        user  = u
      }
    ]
  ])
}

This creates the following list:

> local.user-group-flt
[
  {
    "group" = "Admins"
    "user" = "michael"
  },
  {
    "group" = "Admins"
    "user" = "jon"
  },
  {
    "group" = "Developers"
    "user" = "raheem"
  },
  {
    "group" = "Developers"
    "user" = "kylian"
  },
  {
    "group" = "Readers"
    "user" = "john"
  },
  {
    "group" = "Readers"
    "user" = "katy"
  },
]

Then, the subsequent for loops will work as well. For users:

> [for user in local.user-group-flt: user.user ]
[
  "michael",
  "jon",
  "raheem",
  "kylian",
  "john",
  "katy",
]

And for groups:

> [for group in local.user-group-flt: group.group ]
[
  "Admins",
  "Admins",
  "Developers",
  "Developers",
  "Readers",
  "Readers",
]

However, since you want to get all the elements of this list of mappings, there is a shorthand syntax which you can use instead of using the for loop:

groups = distinct(local.user-group-flt[*].group)
users  = local.user-group-flt[*].user

The last two examples are using the wildcard or splat expression in Terraform terminology [1] to fetch all the elements of a list. Additionally, the distinct built-in function [2] will remove any duplicates from the list which will be there.


[1] https://developer.hashicorp.com/terraform/language/expressions/splat

[2] https://developer.hashicorp.com/terraform/language/functions/distinct