AWSのIAMユーザー作成・グループへの追加をTerraformで実装する

# やりたいこと
TerraformでまとめてIAMユーザーをバーッと作り、ユーザーグループへバスンと放り込んで大勝利！🤗

# きっかけ
アカウントの払い出しや棚卸しを安全かつ楽に実施したい
→ 手始めにIAMユーザーの作成（とユーザーグループへの追加）をTerraformでやってみる

IAMユーザーの数だけTerraformリソース（`aws_iam_user`と`aws_iam_group_membership`）が必要になる？やだな〜と思ってましたが、`module`と`for_each/each`を使うとすっきり書けて嬉しかった

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_group_membership

# 環境と構成
Terraformのバージョンやファイル構成は下記の通りです

```
❯ terraform version
Terraform v1.0.8
on darwin_amd64
```

```
terraform/
　├ envs/
　│　└ test/
　│　　　├ main.tf
　│　　　├ outputs.tf
　│　　　├ variables.tf
　│　　　└ provider.tf
　├ modules/
　│　└ iam/
　│　　　├ main.tf
　│　　　├ outputs.tf
　│　　　└ variables.tf
　└ src/
　　　└ user.yml
```

```envs/test/provider.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "3.62.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}
```

# 関連リソース
## ユーザー
ここでは`dev`と`ops`という2つのロール（IAMのロールではない）があると仮定して、各ロールのユーザーを3人ずつ作成します
以下のようなyamlファイルにロールとユーザー名を書きます

```src/user.yaml
dev:
  - dev_tarou_1st
  - dev_tarou_2nd
  - dev_tarou_3rd
ops:
  - ops_hanako_1st
  - ops_hanako_2nd
  - ops_hanako_3rd
```

## ユーザーグループ
今回は作成済みのユーザーグループへユーザーを追加していきます
`dev`ロールのユーザーは`dev_member_group`, `ops`ロールのメンバーは`ops_member_group`にといった感じで何も考えずぶち込みます
![screenshot 2021-10-14 0.51.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463957/c2dab8cb-7b53-92c2-30cf-80177e215409.png)

``` envs/test/main.tf
locals {
  users               = yamldecode(file("../../src/user.yaml"))
  dev_users           = local.users.dev
  ops_users           = local.users.ops
  dev_groupname       = "dev_member_group"
  dev_membership_name = "dev_members"
  ops_groupname       = "ops_member_group"
  ops_membership_name = "ops_members"
}

module "dev" {
  source          = "../../modules/iam"
  group_users     = toset(local.dev_users)
  membership_name = local.dev_membership_name
  groupname       = local.dev_groupname
}

module "ops" {
  source          = "../../modules/iam"
  group_users     = toset(local.ops_users)
  membership_name = local.ops_membership_name
  groupname       = local.ops_groupname
}
```

```module/iam/main.tf
resource "aws_iam_user" "user" {
  for_each = var.group_users
  name     = each.value
}

resource "aws_iam_group_membership" "group_assotiation" {
  depends_on = [aws_iam_user.user]
  name  = var.membership_name
  users = var.group_users
  group = var.groupname
}
```

```module/iam/variables.tf
variable "group_users" {}
variable "groupname" {}
variable "membership_name" {}
```

ユーザー作成は各ロールのユーザーごとに`each`でループさせ、ユーザーグループへの追加は`toset`を使ってユーザー名のコレクション(set)を渡します
ユーザーがいないとグループ追加がこけるので、`depends_on`で明示的に依存関係を書きます

# terraform plan
してみます

<details><summary>terraform plan実行結果</summary><div>

```
❯ terraform plan

Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # module.dev.aws_iam_group_membership.group_assotiation will be created
  + resource "aws_iam_group_membership" "group_assotiation" {
      + group = "dev_member_group"
      + id    = (known after apply)
      + name  = "dev_members"
      + users = [
          + "dev_tarou_1st",
          + "dev_tarou_2nd",
          + "dev_tarou_3rd",
        ]
    }

  # module.dev.aws_iam_user.user["dev_tarou_1st"] will be created
  + resource "aws_iam_user" "user" {
      + arn           = (known after apply)
      + force_destroy = false
      + id            = (known after apply)
      + name          = "dev_tarou_1st"
      + path          = "/"
      + tags_all      = (known after apply)
      + unique_id     = (known after apply)
    }

  # module.dev.aws_iam_user.user["dev_tarou_2nd"] will be created
  + resource "aws_iam_user" "user" {
      + arn           = (known after apply)
      + force_destroy = false
      + id            = (known after apply)
      + name          = "dev_tarou_2nd"
      + path          = "/"
      + tags_all      = (known after apply)
      + unique_id     = (known after apply)
    }

  # module.dev.aws_iam_user.user["dev_tarou_3rd"] will be created
  + resource "aws_iam_user" "user" {
      + arn           = (known after apply)
      + force_destroy = false
      + id            = (known after apply)
      + name          = "dev_tarou_3rd"
      + path          = "/"
      + tags_all      = (known after apply)
      + unique_id     = (known after apply)
    }

  # module.ops.aws_iam_group_membership.group_assotiation will be created
  + resource "aws_iam_group_membership" "group_assotiation" {
      + group = "ops_member_group"
      + id    = (known after apply)
      + name  = "ops_members"
      + users = [
          + "ops_hanako_1st",
          + "ops_hanako_2nd",
          + "ops_hanako_3rd",
        ]
    }

  # module.ops.aws_iam_user.user["ops_hanako_1st"] will be created
  + resource "aws_iam_user" "user" {
      + arn           = (known after apply)
      + force_destroy = false
      + id            = (known after apply)
      + name          = "ops_hanako_1st"
      + path          = "/"
      + tags_all      = (known after apply)
      + unique_id     = (known after apply)
    }

  # module.ops.aws_iam_user.user["ops_hanako_2nd"] will be created
  + resource "aws_iam_user" "user" {
      + arn           = (known after apply)
      + force_destroy = false
      + id            = (known after apply)
      + name          = "ops_hanako_2nd"
      + path          = "/"
      + tags_all      = (known after apply)
      + unique_id     = (known after apply)
    }

  # module.ops.aws_iam_user.user["ops_hanako_3rd"] will be created
  + resource "aws_iam_user" "user" {
      + arn           = (known after apply)
      + force_destroy = false
      + id            = (known after apply)
      + name          = "ops_hanako_3rd"
      + path          = "/"
      + tags_all      = (known after apply)
      + unique_id     = (known after apply)
    }

Plan: 8 to add, 0 to change, 0 to destroy.
```
</div></details>

良さそう！！！！！！！！！！applyすっぞ！！！！！！！！！！！！

# terraform apply
しました
![screenshot 2021-10-14 2.22.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463957/4b55282f-2349-e45a-59d7-1dedc6ea60ae.png)
ええやん🤗

# まとめ
やりたかったことができてにっこりです
が、初期パスワードの設定などほかにも色々必要なのでたくさん頑張ります