WindowsのWSL上Ubuntuでterraformを実行する

## 前提条件
Description    : Ubuntu 22.04.1 LTS

## TerraformとTfenvのインストール
今回はTfenvを利用してTerraformをインストールします。

### Tfenvのインストール
```bash
# unzipのインストール(tfenvでterraformをインストールするときにunzipがないと失敗します。)
$sudo apt-get install zip unzip

# tfenvをClone
$git clone --depth=1 https://github.com/tfutils/tfenv.git ~/.tfenv

# Pathをに追加
$echo 'export PATH=$PATH:$HOME/.tfenv/bin' >> ~/.bashrc

# シンボリックリンクを追加
$ln -s ~/.tfenv/bin/* /usr/local/bin
```

### Tfenvを利用してTerraformをインストール
```bash
# 最新版をインストール(バージョンを指定する場合は`latest`の部分を変更してください)
$tfenv install latest

# インストールしたバージョンを表示
$tfenv list
  1.4.6
No default set. Set with 'tfenv use <version>'

# インストールしたバージョンを有効化
$tfenv use 1.4.6
Switching default version to v1.4.6
Default version (when not overridden by .terraform-version or TFENV_TERRAFORM_VERSION) is now: 1.4.6
```

## TerraformからAWSへのアクセス設定
今回はアクセスキーを直接利用する形ではなく、スイッチロールを利用します。

### IAMロールの作成
スイッチロールを行うためのIAMロールを以下のCloudFormationテンプレートから作成します。
```yaml
AWSTemplateFormatVersion: "2010-09-09"
Resources:
  IAMUser:
    Type: "AWS::IAM::User"
    Properties:
      UserName: "CodeDeveloper"

  IAMUserPolicy:
    Type: "AWS::IAM::Policy"
    Properties:
      PolicyName: "CodeDeveloperAssumeRolePolicy"
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Action: "sts:AssumeRole"
            Resource: !GetAtt SwitchRole.Arn
      Users:
        - Ref: "IAMUser"


  IAMUserAccessKey:
    Type: 'AWS::IAM::AccessKey'
    Properties:
      UserName: !Ref IAMUser
      
  SwitchRole:
    Type: "AWS::IAM::Role"
    Properties:
      RoleName: "SwitchRole"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              AWS:
                - !GetAtt IAMUser.Arn
            Action: "sts:AssumeRole"
  S3AccessPolicy:
    Type: "AWS::IAM::Policy"
    Properties:
      PolicyName: "S3AccessPolicy"
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Action:
              - "s3:GetObject"
              - "s3:CreateBucket"
              - "s3:GetBucketPolicy"
              - "s3:PutBucketPolicy"
              - "s3:GetBucketAcl"
              - "s3:GetBucketCors"
              - "s3:PutBucketCors"
              - "s3:GetBucketVersioning"
              - "s3:GetBucketAcl"
              - "s3:PutBucketAcl"
              - "s3:GetAccelerateConfiguration"
              - "s3:GetBucketRequestPayment"
              - "s3:GetBucketLogging"
              - "s3:GetLifecycleConfiguration"
              - "s3:GetReplicationConfiguration"
              - "s3:GetEncryptionConfiguration"
              - "s3:GetBucketObjectLockConfiguration"
              - "s3:GetBucketWebsite"
              - "s3:PutBucketWebsite"
              - "s3:PutObject"
              - "s3:ListBucket"
              - "s3:ListAllMyBuckets"
              - "s3:DeleteObject"
              - "s3:DeleteBucket"
              - "s3:GetBucketTagging"
              - "s3:PutBucketTagging"
            Resource: "*"
      Roles:
        - Ref: "SwitchRole"

Outputs:
  AccessKeyId:
    Value: !Ref IAMUserAccessKey
    Description: IAM User Access Key ID

  SecretAccessKey:
    Value: !GetAtt IAMUserAccessKey.SecretAccessKey
    Description: IAM User Secret Access Key

  SwitchRoleArn:
    Value: !GetAtt SwitchRole.Arn
    Description: SwitchRole Arn
```

### 詳細説明
1. まず以下の箇所でIAMユーザを作成し、作成したIAMユーザーに次に作成するIAMロールにSwitchする権限を割り当てます。またTerraformが作成したユーザでAWSに接続するためのAccessKeyを設定します。
    ```yaml
      IAMUser:
        Type: "AWS::IAM::User"
        Properties:
          UserName: "CodeDeveloper"
    
      IAMUserPolicy:
        Type: "AWS::IAM::Policy"
        Properties:
          PolicyName: "CodeDeveloperAssumeRolePolicy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action: "sts:AssumeRole"
                Resource: !GetAtt SwitchRole.Arn
          Users:
            - Ref: "IAMUser"
    
      IAMUserAccessKey:
        Type: 'AWS::IAM::AccessKey'
        Properties:
          UserName: !Ref IAMUser
    ```
2. 次に実際にSwitchされて利用されるIAMロールを作成します。Terraformが実行可能な操作範囲はここで指定した範囲に限られます。

    ```yaml
      SwitchRole:
        Type: "AWS::IAM::Role"
        Properties:
          RoleName: "SwitchRole"
          AssumeRolePolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Principal:
                  AWS:
                    - !GetAtt IAMUser.Arn
                Action: "sts:AssumeRole"
      S3AccessPolicy:
        Type: "AWS::IAM::Policy"
        Properties:
          PolicyName: "S3AccessPolicy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - "s3:GetObject"
                  - "s3:CreateBucket"
                  - "s3:GetBucketPolicy"
                  - "s3:PutBucketPolicy"
                  - "s3:GetBucketAcl"
                  - "s3:GetBucketCors"
                  - "s3:PutBucketCors"
                  - "s3:GetBucketVersioning"
                  - "s3:GetBucketAcl"
                  - "s3:PutBucketAcl"
                  - "s3:GetAccelerateConfiguration"
                  - "s3:GetBucketRequestPayment"
                  - "s3:GetBucketLogging"
                  - "s3:GetLifecycleConfiguration"
                  - "s3:GetReplicationConfiguration"
                  - "s3:GetEncryptionConfiguration"
                  - "s3:GetBucketObjectLockConfiguration"
                  - "s3:GetBucketWebsite"
                  - "s3:PutBucketWebsite"
                  - "s3:PutObject"
                  - "s3:ListBucket"
                  - "s3:ListAllMyBuckets"
                  - "s3:DeleteObject"
                  - "s3:DeleteBucket"
                  - "s3:GetBucketTagging"
                  - "s3:PutBucketTagging"
                Resource: "*"
          Roles:
            - Ref: "SwitchRole"
    ```

3. Terraformで指定するための情報をOutputで出力します。
    ```yaml
    Outputs:
      AccessKeyId:
        Value: !Ref IAMUserAccessKey
        Description: IAM User Access Key ID
    
      SecretAccessKey:
        Value: !GetAtt IAMUserAccessKey.SecretAccessKey
        Description: IAM User Secret Access Key
    
      SwitchRoleArn:
        Value: !GetAtt SwitchRole.Arn
        Description: SwitchRole Arn
    ```
    上記の結果がCloudFormationの出力タブの値列に出力されます。(下の画像では値列を非表示にしています。)

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223700/a2a74327-8b64-d001-338f-2e2229f122ee.png)

## AWS CLIを利用して接続用のProfileを作成
AWS CLIのインストールについては公式ページのLinuxの手順を参考にしてください

https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html

1. aws configureコマンドを利用してプロファイルを作成します。`vi ~/.aws/credentials`で直接Credentialを変更しても問題ありません。また今回はDefaultの設定を変更していますが別でも大丈夫です。

```bash
aws configure --profile default
AWS Access Key ID : 
AWS Secret Access Key : 
Default region name : 
Default output format :
```

## Terraformテンプレートの作成
S3バケットを作成するTerraformテンプレートを作成します。

1. providers.tfに接続情報を記載します。一つ前の手順でdefault以外でプロファイルを作成した場合は以下の`profile`に作成したプロファイル名を指定してください。

    providers.tf
    ```tf
    provider "aws" {
      region = "ap-northeast-1"
      assume_role {
        role_arn = "arn:aws:iam::<アカウントID>:role/SwitchRole"
      }
        profile = "default"
    }
    ```

2. main.tfにS3の作成情報を記載します。今回はBackendやrequired_versionなどを指定していません。
    ```tf
    # Create s3 bucket
    resource "aws_s3_bucket" "my_bucket" {
        bucket = "my-bucket-da0s9uf08ua083u"
    
        tags = {
            Name        = "My bucket"
            Environment = "Dev"
        }
    }
    ```

## Terraform を実行する
terraformの`init` `plan` `apply` コマンドを順に実行しS3バケットを作成します。
```bash
terraform init
terraform plan
terraform apply
```

## S3バケットの作成を確認
Management ConsoleからS3にアクセスしバケットが作成されていることを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223700/90c53c8f-1245-91d4-2b94-1d86528863f5.png)

## 作成したS3バケットを削除する。
最後に今回作成たS3バケットを削除して作業完了とします。
```bash
terraform destroy
```


## 参考
- [tfenv(github)_manualインストール手順](https://github.com/tfutils/tfenv#manual)
- [Amazon S3 のアクション、リソース、条件キー](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/list_amazons3.html)
- [Terraform用のAWSアクセスキーの権限管理を、スイッチロール形式で最適化する方法](https://blog.mmmcorp.co.jp/2021/01/27/terraform_with_assume_role/)
- [TerraformDocument リソース: aws_s3_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket)