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

use*_*785 9 amazon-iam terraform

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}"
}
Run Code Online (Sandbox Code Playgroud)

当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
Run Code Online (Sandbox Code Playgroud)

似乎在terraform aws_iam_user中没有用户存在检查,在terraform中管理IAM用户的工作方式/正确方法是什么?

Mar*_*ley 13

Terraform 0.12.6在资源上添加了for_each,这对于解决所描述的问题非常有用。

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

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" ]
}
Run Code Online (Sandbox Code Playgroud)

然后我们可以使用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" ]
}
Run Code Online (Sandbox Code Playgroud)

请注意,user_names 和 group_memberships 的映射变量中的每个项目,这些项目必须都是相同的类型。我们不能混合使用地图和列表。这就是我将 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
  }
}
Run Code Online (Sandbox Code Playgroud)

结果输出将是一个以 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"
}
Run Code Online (Sandbox Code Playgroud)

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

  • 从 Terraform v0.12.x 开始,人们正在寻找准确的答案,这就是!另请注意,在 v0.12.10 中,我可以将组成员身份列表嵌套在 user_names 映射内。 (3认同)
  • @aalimovs 请参阅此要点以获取可用的 IAM 用户模块,包括组成员身份。https://gist.github.com/kerr-bighealth/1e11b379f29e8aedc94826abd4a282cd (2认同)

use*_*785 9

感谢Martin Atkins在hashicorp-terraform gitter室的回答/建议:

"这里讨论的问题是当你使用数组变量"count"时,Terraform并没有真正"看到"数组中的项与资源之间的关系,所以当从列表中间删除一个值时在那之后突然"被一个人关闭",Terraform将要更换它们

这是一种可以从Terraform中的第一类迭代功能中受益的用例,但遗憾的是我们还没有这样做,我建议不要试图将用户列表作为变量传递,而是最强大的方法现在是有一个单独的程序从某个地方读取用户列表,并为每个用户写出一个包含单独的aws_iam_user块的.tf.json文件.这样Terraform将了解哪个块属于哪个用户,因为本地标识符可以是用户名或某种用户ID,允许保持相关性"