Hi,
Although the example below works, it feels like I am duplicating for_each
in two different resources. I looked at Chaining for_each
Between Resources but not sure if I can apply to mine. The question is, am I using for_each
right here or could I improve the whole thing?
Thanks
locals {
people = [
{
name : "developer-1",
pgp_key : "mQEN......qpBmjUPkzW"
}
]
}
resource "aws_iam_user" "user" {
for_each = { for item in local.people : item.name => item }
name = each.value.name
}
resource "aws_iam_access_key" "user" {
for_each = { for item in local.people : item.name => item }
user = each.value.name
pgp_key = each.value.pgp_key
depends_on = [
aws_iam_user.user
]
}
output "access_keys" {
value = {
for name, user in aws_iam_access_key.user : name => "ID: ${user.id} => SECRET: ${user.encrypted_secret}"
}
}
Hi @wevovib720,
This is indeed a more complicated case of chaining because the downstream resource aws_iam_access_key
needs to access both attributes of the upstream resource and the map the upstream resource was using for its for_each
.
I think there are a few different ways to reorganize this, and the one I’m about to show is just the one that seems the smallest change from what you’re already doing, but hopefully it also illustrates some new language features that you can combine in some different ways if you prefer to think about the problem a little differently.
First, I think it will make things easier to factor out the construction of the map of “people” in terms of the list of people (which I assume in your real example is an input variable and so you can’t just change it inline to be a map) so that we can use it in multiple locations without recalculating it:
locals {
people_map = { for item in local.people : item.name => item }
}
With that in place, local.people_map
gives a way to look up a person definition given a username.
With that in place, we can change the definition of resource "aws_iam_access_key" "user"
to chain from the aws_iam_user
resource but to still refer to the original map to get the PGP key, which wouldn’t otherwise be available through the user object:
resource "aws_iam_user" "user" {
for_each = local.people_map
name = each.value.name
}
resource "aws_iam_access_key" "user" {
for_each = aws_iam_user.user
user = each.value.name
pgp_key = local.people_map[each.key].pgp_key
}
Note that it’s also no longer necessary to specify depends_on
, because the for_each
expression includes a reference to aws_iam_user.user
which establishes that dependency automatically.
1 Like
This is an excellent explanation with a working example. Not only answers the question but also teaches why. Much appreciated.