Terraformで初期パスワードとシークレットアクセスキーを持つIAMユーザを作成する

# はじめに

Terraformで複数のtfファイルを定期的にapply, destroyする必要があり、スクリプトを使って楽をしたいなぁという話になりました。

以下の流れをそれぞれスクリプトに分けて自動化したいです。

1. IAMユーザーを作成
2. 1. のユーザーでリソースを作成
3. 1. のユーザーでリソースを削除

まずは、手動での実行がどのようなものか自分自身が理解する必要がありそうだなと。
ということで、TerraformとGnuPGを使って初期パスワードとアクセスキーを持つIAMユーザを作成してみます。

1. IAMユーザを作成
2. 1. のユーザーでリソースを作成

## 環境

```shell
$ sw_vers
ProductName:	macOS
ProductVersion:	11.1
BuildVersion:	20C69

$ terraform -version
Terraform v0.14.4

$ gpg --version
gpg (GnuPG) 2.2.27
libgcrypt 1.8.7
```

## やること

1. IAMユーザ作成のtfファイルを準備
2. GnuPGを使って、公開鍵を作成。 `gpg_key` に公開鍵を設定
3. Administrator権限を持つユーザで `terraform apply`
4. 3. で作成されたパスワードやシークレットアクセスキーを複合化
5. EC2インスタンス作成のtfファイルを準備
6. 複合化したシークレットアクセスキーをもとに、 `terrafom apply`

## 1. IAMユーザ作成のtfファイルを準備

```shell
$ tree
.
├── main.tf
├── outputs.tf
├── terraform.tfvars
├── variables.tf
└── version.tf
```

最低限EC2に関するポリシーがあれば良いので、以下のように各ファイルを作成。

```terraform:main.tf

resource "aws_iam_user" "ec2_execution_user" {
  name = "ec2_execution_user"

  tags = {
    tag-key = "qiita"
  }
}

resource "aws_iam_access_key" "user_access_key" {
  user = aws_iam_user.ec2_execution_user.name
  pgp_key = var.pgp_key
}

resource "aws_iam_user_policy" "ec2_execution_user_role" {
  name = "ec2_execution_user_role"
  user = aws_iam_user.ec2_execution_user.name

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "ec2:*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
EOF
}

resource "aws_iam_user_login_profile" "ec2_user_profile" {
    user = aws_iam_user.ec2_execution_user.name
    pgp_key = var.pgp_key
    password_reset_required = false
    depends_on = [aws_iam_user.ec2_execution_user]
}
```

```terraform:version.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 3.24.0"
    }
  }
  required_version = ">= 0.14.0"
}
```

```terraform:outputs.tf
output "first_password" {
  value = aws_iam_user_login_profile.ec2_user_profile.encrypted_password
  description = "IAMユーザの暗号化されたパスワード"
}

output "secret_access" {
  value = aws_iam_access_key.user_access_key.encrypted_secret
  description = "IAMユーザの暗号化されたシークレットキー"
}
```

```terraform:variables.tf
variable "pgp_key" {
  description = "IAMユーザーのパスワード生成で利用するpgpの公開鍵(base64形式)"
  type        = string
}
```

`terraform.tfvars` については空欄にしておきます。

```terraform:terraform.tfvars
pgp_key = ""
```

## 2. GnuPGを使って、公開鍵を作成

IAMユーザを作成するにあたって、初期パスワードを暗号化して出力する必要があるため公開鍵を作成していきます。

[公開鍵設定について](https://gitlab.com/eponas/epona/-/blob/master/guide/patterns/aws/users.md#公開鍵設定について)

また、日本語の公式サイトもあったのでこちらも見つつ進めます。

http://gnupg.hclippr.com/documents/howto/

1. gpgのインストール

    ```shell
    $ brew install gpg
    ```

2. 鍵の出力
    `name` は任意の値を入力しています。

    ```shell
    $ gpg -o ./name.public.gpg  --export name
    $ gpg -o ./name.private.gpg --export-secret-key name
    ```

3. Base64エンコード

    公開鍵を[Base64](https://ja.wikipedia.org/wiki/Base64)エンコードする必要があるようです。
    この辺りも見る限り、AWSではBase64エンコードされたデータを扱っていると理解すれば良いのかな。
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user_login_profile#attributes-reference

    ```shell
    $ cat name.public.gpg | base64 | tr -d '\n' > name.public.gpg.base64
    $ cat name.public.gpg.base64
    ```

4. 出力された値を設定

    catで出力された値をコピーし、 `terraform.tfvars` に設定する。

    ```terraform:terraform.tfvars
    pgp_key = "mQGNBGAEO6cBDADVf3FBHM…"
    ```

## 3. Administrator権限を持つユーザで `terraform apply`

```shell
$ export AWS_ACCESS_KEY_ID=xxxx
$ export AWS_SECRET_ACCESS_KEY=xxxxxxx
$ aws sts get-caller-identity --query Account --output text
[Administrator権限を持つユーザ]
$ terraform init
$ terraform apply
  …
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Outputs:

first_password = "xxx"
secret_access = "xxx"
```

## 4. 3. で作成されたパスワードやシークレットアクセスキーを複合化

まずは初期パスワードである `first_password` を複合化します。

```shell
$ export GPG_TTY=$(tty)
$ echo "[first_password]" | base64 -d | gpg -r name
gpg: *警告*: コマンドが指定されていません。なにを意味しているのか当ててみます ...
gpg: 3072-ビットRSA鍵, ID 503Fxxxxx, 日付2021-01-17に暗号化されました
      "name <xxxx@icloud.com>"
xxxxxxxxxx
```

同様に、シークレットアクセスキーを複合化します。

```shell
$ echo "[secret_access]" | base64 -d | gpg -r name
gpg: *警告*: コマンドが指定されていません。なにを意味しているのか当ててみます ...
gpg: 3072-ビットRSA鍵, ID 503xxxxxxx, 日付2021-01-17に暗号化されました
      "name <xxxxx@icloud.com>"
xxxxxxx
```

## 5. EC2インスタンス作成のtfファイルを準備

`t2.micro` を構築するtfファイルを作成します。

```shell
$ tree
.
├── main.tf
└── version.tf
```

```terraform:main.tf
resource "aws_instance" "ec2_instance_t2" {
  ami           = "ami-0cc75a8978fbbc969"
  instance_type = "t2.micro"

  tags = {
    tag_key = "qiita"
  }
}
```

```terraform:version.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 3.24.0"
    }
  }
  required_version = ">= 0.14.0"
}
```

## 6. 複合化したシークレットアクセスキーをもとに、 `terrafom apply`

以前の手順で複合化したシークレットアクセスキーとアクセスキーを使ってユーザを切り替えます。

```shell
$ export AWS_ACCESS_KEY_ID=xxxx
$ export AWS_SECRET_ACCESS_KEY=xxxxxxx
$ aws sts get-caller-identity --query Account --output text
[新しく作成したIAMユーザ]
```

無事切り替えできました。よかった！
では `terraform apply` をします。

```shell
$ terraform init
$ terraform apply
  …
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
```

こちらも無事に作成できました！

このようにGnuPGを使った暗号化・複合化の手順も自動化する必要がありそうだということがわかったので、今回の目的は達成。