AWS My First Setup - 自分流初期設定の忘備録

# 目的
- コンソールで作業するための前準備を完了させる
- Terraformで作業するための前準備を完了させる

の2点です。アカウント開設直後はrootユーザーのみですが、rootユーザーで作業したくないですね。そのためアカウント開設から作業できる状態にするまでの下準備が結構あるのですが、毎回忘れがちなので記録しておきます。

# Assume Roleを活用する
安全な作業（デプロイ）に向けて、AssumeRoleを活用します。AssumeRoleの概念は以下の動画がわかりやすいです。

https://www.youtube.com/watch?v=LbZj68v4k8I

動画では
- `スイッチロール用ユーザー`→`デプロイRole（Cloud Formationでデプロイするポリシーのみ）`→`CloudFormation Role（デプロイのためのポリシー全てを持つ）`

の順で権限が移っていきますが、Terrafromの場合は

- `スイッチロール用ユーザー`→`デプロイRole（デプロイのためのポリシー全てを持つ）`

の順で権限移動で十分かと思います。

## 必要なエンティティ
Assume Roleを活用するために`スイッチロール用のIAMユーザー`、`デプロイ用のIAMロール`を作成します。

- スイッチロール用のIAMユーザー
    - デプロイ用の権限を持つロールを引き受ける器です。
    - アタッチするポリシーはAssumeRoleするためのポリシーのみでOKです。
- デプロイの権限を持つIAMロール
    - デプロイ用のIAMロール。信頼するエンティティにスイッチロール用のIAMユーザーを指定します。
    - AdministratorAccessポリシーを付与することで、ほとんどのリソース操作ができるようになります。
    - 今後の作業（デプロイ）でAWSのリソースを操作する際はこちらのロールをAssumeRoleしたIAMユーザーを使用します。

# スイッチロール用IAMユーザーと、デプロイ用IAMロールの作成
ここは仕方がないのでrootユーザーでやるしかないです。基本的にはこの作業のみにrootユーザーを使用します。

## rootユーザーのベストプラクティス

https://docs.aws.amazon.com/accounts/latest/reference/best-practices-root-user.html

rootユーザーでは最初のIAMユーザーの作成、請求情報の変更など、rootユーザーでしかできないことをするときのみ使用して、それ以外はIAMユーザーを使用しての開発が推奨されています。安全なやり方を追求するのであれば、rootユーザーのアクセスキーは破棄してしまいましょう。CLIから作業をする場合はアクセスキーが必要になりますが、UIからのみ作業することにしておけばアクセスキーを持つ必要がなくなるためアクセスキーを削除できます。そのため管理する必要のあるものはログインパスワードのみで良くなります。自分は初回のIAMユーザー、IAMロール作成のみrootユーザーからUI操作で設定して、以降はほぼ使いません。
rootユーザーのアクセスキーを消すと、以下のようにAWSからセキュリティに関するレコメンデーションの項目をクリアすることができます。（MFAも設定推奨です）

![スクリーンショット 2022-12-25 14.04.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965436/ac70b0db-c811-5ac6-e620-8b6783b13ce1.png)

## スイッチ用IAMユーザーの作成

![スクリーンショット 2023-01-06 1.58.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965436/bab4c5c2-e5e1-a3fe-0f84-e760a109b7f9.png)

上記のように作成します。ChangePasswordポリシーは勝手についてきます。

## デプロイ用IAMロールの作成
最初の`信頼されたエンティティ`設定で、`カスタム信頼ポリシー`を選択後、以下のように記入する。
その後、`許可を追加`の設定で、`AdministratorAccess`ポリシーを追加します。

```json
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "Statement1",
			"Effect": "Allow",
			"Principal": {
			    "AWS": "arn:aws:iam::<account_id>:user/<switch_iam_user_name>"
			},
			"Action": "sts:AssumeRole"
		}
	]
}
```

## スイッチ用IAMユーザーがデプロイ用IAMロールを引き受けるためのポリシーの作成
ポリシーの作成から以下を記入して作成します。作成したポリシーをスイッチ用IAMユーザーにアタッチします。

```json
{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Allow",
    "Action": "sts:AssumeRole",
    "Resource": "arn:aws:iam::<account_id>:role/<deploy_iam_role_name>"
  }
}
```

# ロールの切り替えが可能になる
作成したスイッチ用のIAMユーザーでログイン後、コンソール画面右上のロールを切り替えをクリックで以下の設定画面になります。`ロール`に先ほど作成したデプロイ用IAMロールの名前を入力すればスイッチができるようになっているはずです。
これ以降コンソールで作業する必要が出てきた場合はこのロールで作業します。

![スクリーンショット 2023-01-05 23.20.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965436/e5435106-d56b-6d82-6db0-7dcc04ce3028.png)


# Terraformでの使用方法
ここまで作業した場合、AWSのリソースにアクセスできる認証情報は
- rootユーザーのログインパスワード
- スイッチロール用ユーザーのログインパスワード
- スイッチロール用ユーザーのシークレットアクセスキー

の3つです。

Terraformで使用するのは、スイッチロール用ユーザーのシークレットアクセスキーになります。
普通に使用しようとすると、`~/.aws/credentials`に保存してterraform実行時に参照してもらうことになりますが、もちろんそのまま参照するだけではスイッチロール用ユーザーは何の権限も持っていないため何もできません。
そこで、今回はAssumeRoleと`aws-vault`を組み合わせて実行環境を構築します。

`aws-vault`ではアクセスキーを`KeyChain`に保存する仕組みになっているため、自分のストレージ内の`~/.aws/credentials`保存するよりもいくぶん安全に運用ができます。`KeyChain`ではAppleさんがかなり強固な暗号化技術によってキーを保存＆管理しているようです。

### aws-vaultの使用方法
インストール
```sh 
brew cask install aws-vault
```

スイッチロール用ユーザーのシークレットアクセスキーを登録する。
```sh 
$ aws-vault add UHOUHO
Enter Access Key ID: <switch_role_user_access_key_id>
Enter Secret Access Key: <switch_role_user_secret_access_key>
```
このままだと何も実行できないため、以下のようにしてデプロイ用IAMロールを指定したprofileを`~/.aws/config`に記載します。

```config:~/.aws/config
[profile UHOUHOassumerole]
source_profile = UHOUHO
role_arn = arn:aws:iam::<account_id>:role/<deploy_iam_role_name>
```

以上の設定で完了です。
`aws-vault exec <profile> --`の後に実行したいコマンドを入力すると、一時的なAWSの認証情報が環境変数として渡された状態でコマンドが実行されます。例えば以下のコマンドを打つとそのことが確認できると思います。

```sh 
$ aws-vault exec <profile> -- env | grep '^AWS'
AWS_VAULT=hogehoge
AWS_DEFAULT_REGION=ap-northeast-1
AWS_REGION=ap-northeast-1
AWS_ACCESS_KEY_ID=uhouho
~~~~~~
```

そのため、以下コマンドを実行することで、デプロイ用IAMロールにスイッチしたIAMユーザーからTerraformを実行できるようになります。

```sh
aws-vault exec <profile_name> -- terraform plan/apply
```

:::note warn
このaws-vaultで発行される認証情報の有効期限は1時間です。
あまりないとは思いますが、`plan/apply`に1時間以上かかる場合は失敗してしまいます。
:::

### aws-vaultで発行される認証情報の有効期限を伸ばす
AWSでのスイッチロール（AssumeRole）により取得できる一時的な認証情報の有効期限はデフォルトで1時間となっているため、1時間以上のプロセスを実行することができません。
`aws-vault exec`時に`-d/--duration`オプションで一応有効期限（Time-To-Live）を設定することはできますが、2h以上を指定しようとすると↓のようなエラーが出てしまいます。

```sh 
$ aws-vault exec <profile> -d 2h -- aws s3 ls                                                                                                           
aws-vault: error: exec: Failed to get credentials for <profile>: operation error STS: AssumeRole, https response error StatusCode: 400, RequestID: <any_requestID>, api error ValidationError: The requested DurationSeconds exceeds the MaxSessionDuration set for this role.
```

しかし、これはAWS CLIの`iam role update`コマンドで延長させることができます。

以下コマンドを打ってみましょう。すると、デフォルトで1時間に設定されていることが確認できます。

```sh
$ aws-vault exec <profile> -- aws iam get-role --role-name <deploy_iam_role_name> --query Role.MaxSessionDuration
3600
```

これを`aws iam update`で3時間に延長してみます。このコマンドを実行した後に再度↑のコマンドを打つと10800と出力され、変更されたことが確認できます。

:::note warn
最大で12時間まで延長が可能ですが、それと同時に認証情報が漏れた際のリスクも増えてしまうため、必要な分だけ延長するように留意しましょう。
:::

```sh
$ aws-vault exec <profile> -- aws iam update-role --role-name <deploy_iam_role_name> --max-session-duration $((60*60*3))
```

以上の操作を行うと、`-d/--duration`オプションで1時間よりも長時間の有効期限を設定することができます。
```sh
$ aws-vault exec <profile> -d 2h -- aws s3 ls                                                                                                    
20XX-XX-XX HH:mm:ss my-bucket
```