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

时间:2016-11-16 12:16:33

标签: 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}"
}

当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用户的工作原理/正确方法是什么?

2 个答案:

答案 0 :(得分:9)

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

  

这里讨论的问题是当你对数组变量使用“count”时,Terraform并没有真正“看到”数组中的项与资源之间的关系,所以当从中间删除一个值时列出该点之后的所有内容突然“一个接一个”,Terraform将要全部替换它们。

     

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

答案 1 :(得分:3)

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" ]
}

然后,我们可以使用 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的映射变量中的每个项目,这些项目都必须具有相同的类型。我们不能混合使用地图和列表。这就是为什么我将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_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"
}

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