如何使用Terraform来维护/管理IAM用户

12

Terraform版本

Terraform v0.7.8 Terraform v0.7.11

受影响的资源

  • aws_iam_user

Terraform配置文件

我正在尝试使用列表来管理IAM用户:

variable "iam_user_list" { default = "aaa,bbb,ccc,ddd,eee,fff" }

resource "aws_iam_user" "iam_user" {
    count = "${length(split(",", var.iam_user_list))}"
    name = "${element(split(",", var.iam_user_list), count.index)}"
    force_destroy = true
}

output "user_list" {
  value = "VPC IAM Base Users: ${var.iam_user_list}"
}

当 AWS 账户为空时,用户可以正常创建。

当我从列表末尾删除用户(例如 fff),可以正常删除。但是当我从列表中间删除用户(例如 bbb)时,会出现错误:

Modifying...
  name: "bbb" => "ccc"
Error applying plan:

1 error(s) occurred:

* aws_iam_user.iam_user.1: Error updating IAM User bbb: EntityAlreadyExists: User with name ccc already exists.
    status code: 409, request id: ed0b4447-abf3-11e6-9b38-0fb23af37c82
似乎 terraform aws_iam_user 中没有用户存在性检查,有什么解决方法或在terraform中管理IAM用户的适当方式?
答案:

看起来 terraform aws_iam_user 没有用户存在性检查,有什么变通方法/在terraform中管理IAM用户的正确方式?


有人使用 Terraform 来维护他们的 IAM 用户吗? - user271785
2个回答

14

Terraform 0.12.6在资源上添加了for_each,此功能非常有用,可以解决所描述的问题。

假设我们编写了一个包含IAM用户名称和组成员身份的terraform.tfvars文件,如下所示:

user_names = {
  "test-user-1" = {
    path          = "/"
    force_destroy = true
    tag_email     = "nobody@example.com"
  }
  "test-user-2" = {
    path          = "/"
    force_destroy = true
    tag_email     = "nobody@example.com"
  }
}

group_memberships = {
  "test-user-1" = [ "SomeGroup", "AnotherGroup" ]
  "test-user-2" = [ "AndYetAnotherGroup" ]
}

然后我们可以使用 for_each 元参数来提取键和值,像这样:

resource "aws_iam_user" "user" {
  for_each = "${var.user_names}"

  name          = each.key
  path          = each.value["path"]
  force_destroy = each.value["force_destroy"]

  tags = "${map("EmailAddress", each.value["tag_email"])}"
}

resource "aws_iam_user_group_membership" "group_membership" {
  for_each = "${var.group_memberships}"

  user   = each.key
  groups = each.value

  depends_on = [ "aws_iam_user.user" ]
}

注意,对于user_names和group_memberships的map变量中的每个条目,所有条目必须是相同类型的。我们不能混合使用map和list。这就是为什么我将group_memberships与user_names分开的原因。如果不是这样,我们可以为每个用户定义另一个属性来指定组成员身份,但是Terraform当前不支持这样做。

如果您想把它制作成模块,并想输出有关每个用户的一些有用属性,可以按照以下方式完成:

output "user_ids" {
  value = {
    for user_name in aws_iam_user.user:
    user_name.name => user_name.unique_id
  }
}

output "user_arns" {
  value = {
    for user_name in aws_iam_user.user:
    user_name.name => user_name.arn
  }
}
输出结果将是以user_name为键的映射。
user_arns = {
  "test-user-1" = "arn:aws:iam::123456789012:user/test-user-1"
  "test-user-2" = "arn:aws:iam::123456789012:user/test-user-2"
}

user_ids = {
  "test-user-1" = "AB2DEDN2O2NMLMNT4KI7G"
  "test-user-2" = "AB1DEFG2O2NNLJQ9YKH7J"
}

有了这个,我们就可以添加、更新或删除用户和/或组成员,而不会影响 terraform 资源在 tfstate 中已知的映射和代码中的配置。这是因为每个资源的名称现在都包含用户名称作为资源名称本身的一部分,并允许我们引用特定的资源,而当使用“count=”时,我们具有 count.index,但无法轻松地将特定用户映射到特定资源。


4
如果您正在寻找 Terraform v0.12.x 的准确答案,那么这就是它!同时,请注意,使用v0.12.10,我能够将组成员列表嵌套在user_names映射内部。 - Kerr
@Kerr 你有例子吗? - aalimovs
3
@aalimovs,请查看此代码片段,其中包含可用的IAM用户模块,包括组成员身份。https://gist.github.com/kerr-bighealth/1e11b379f29e8aedc94826abd4a282cd - Kerr

10
感谢Martin Atkins在“hashicorp-terraform” Gitter聊天室中提供的答案/建议:
问题讨论的是当您使用数组变量的“count”时,Terraform实际上并不“看到”数组项与资源之间的关系,因此当从列表中删除一个值时,该点之后的所有内容突然“错了一位”,Terraform将要替换它们全部。
这是一种可以从Terraform的一流迭代功能中受益的用例,但很遗憾我们还没有这个功能。我建议现在最健壮的方法是有一个单独的程序从某个地方读取用户列表并编写一个包含每个用户的单独aws_iam_user块的.tf.json文件。这样,Terraform将理解哪个块属于哪个用户,因为本地标识符可以是用户名或某种用户ID,从而允许保持相关性。

我知道这是一个非常老的帖子,但也许对某些人有用,使用set来避免偏移一个问题。 - c4f4t0r

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接