Terraformでサーバーレスな会員制サイトを構築する

#はじめに
![builders_flash.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283246/73221c2a-c8f8-3567-a69a-0788bf3517f3.png)
本記事では、AWS のデベロッパー向けウェブマガジン[builders.flash](https://aws.amazon.com/jp/builders-flash) のサーバーレスの学習ガイドで紹介されていたAWSの環境を Terraformで構築する方法について記載しています。(初学者向け)

その学習ガイドの記事は、下記になります。
[はじめてのサーバーレス ~ サーバーレスな会員制サイトを作ってみよう ~ 第 1 回](https://aws.amazon.com/jp/builders-flash/202011/hajimete-serverless-handson/)
[はじめてのサーバーレス ~ サーバーレスな会員制サイトを作ってみよう ~ 第 2 回](https://aws.amazon.com/jp/builders-flash/202101/hajimete-serverless-handson-2/)
[（ラボ1まで）はじめてのサーバーレス ~ サーバーレスな会員制サイトを作ってみよう ~ 第 3 回](https://aws.amazon.com/jp/builders-flash/202102/hajimete-serverless-handson-3/)

管理コンソールを使って構築する手順を Step by Stepで確認したい場合は、こちらを参考にすると、より理解が深まるかと思います。

#学習ガイドで構築する構成図
![aws_serverless_diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283246/268ff779-124f-b11d-632b-bba77bffc0dc.png)

構築するAWSコンポーネント
[Lambda](https://aws.amazon.com/jp/lambda/)
[DynamoDB](https://aws.amazon.com/jp/dynamodb/)
[API Gateway](https://aws.amazon.com/jp/api-gateway/)
[Cognito](https://aws.amazon.com/jp/cognito/)
[IAM](https://aws.amazon.com/jp/iam/)

Terraformのコード

https://github.com/okubo-t/aws-terraform-beginner-serverless

#事前準備
・Terraform のインストール
・tfenv のインストール
・Terraform を実行するためのIAMのアクセスキーとシークレットキー

# Terraformの実行環境

```
$ terraform -version
Terraform v0.12.30
+ provider.archive v2.1.0
+ provider.aws v2.70.0
```

# Terrraformでサーバーレス環境を構築する

１. Terraformのコードをダウンロードします。

```
$ git clone https://github.com/okubo-t/aws-terraform-beginner-serverless.git
```

２. Terraformの環境とコードの構成は下記になります。

```
$ tree aws-terraform-beginner-serverless
aws-terraform-beginner-serverless
├── README.md
├── apigw.tf
├── aws.tf
├── cognito.tf
├── dynamodb.tf
├── iam-policy
│   ├── cognito_auth_policy.json
│   ├── cognito_unauth_policy.json
│   └── lambda_policy.json
├── iam-role.tf
├── lambda.tf
├── output.tf
├── src
│   ├── read
│   │   └── index.js
│   └── write
│       └── index.js
├── terraform.tfvars-
└── variables.tf
```

３. Terraform のコードがあるディレクトへ移動します。

```
$ cd aws-terraform-beginner-serverless/
```
     
４. terraform.tfvars ファイルを作成します。

```
$ cp -p terraform.tfvars- terraform.tfvars
```

５. 作成した terraform.tfvars の「アクセスキー」と「シークレットキー」と「リソース名のprefix」を環境に応じて、任意に変更します。(下記のキーはサンプルです。)

```terraform.tfvars
# アクセスキー
aws_access_key = "AKIAIOSFODNN7EXAMPLE"

# シークレットキー
aws_secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"

# リージョン
aws_region     = "ap-northeast-1"

# リソース名のPrefix
prefix = "prefix"

# リソースの環境
env = "demo"

# ステージ名
stage_name = "demo"
```

６. 下記コマンドで、Terraform の初期設定をします。

```
$ terraform init

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
```

７. 下記コマンドで、環境のデプロイを実行します。

```
$ terraform apply
```

８. デプロイ後に出力される Outputsの内容をメモします。

```
Apply complete! Resources: 39 added, 0 changed, 0 destroyed.

Outputs:

appClientId = XXXXXXXXXXXXXXXXXXXXXXX
identityPoolId = ap-northeast-1:XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX
userPoolId = ap-northeast-1_XXXXXXXXXX
```

これで、Terraformによる環境の構築は完了です。

下記コマンドで、構築されたAWS環境のコンポーネントを確認できます。

```
$ terraform state list
```

# フロント環境の準備
１. フロント用のzipファイルをダウンロードします。

ダウンロード先は[こちら](https://github.com/harunobukameda/AWS-Amplify-AWS-Lambda-Amazon-DynamoDB-AWS-API-Gateway-Amazon-Cognito/blob/master/Serverlesshandson.zip)です。

https://github.com/harunobukameda/AWS-Amplify-AWS-Lambda-Amazon-DynamoDB-AWS-API-Gateway-Amazon-Cognito/blob/master/Serverlesshandson.zip

２. ダウンロードしたzipを展開したフォルダの[Serverlesshandson]-[webpage]-[config.js]ファイルの内容を、メモした Outputsの内容に置換して下さい。 

```Serverlesshandson/webpage/config.js
// TODO: 作成したユーザープールおよびIDプールのIDに書き換えてください
const CognitoConfig = {
    region: 'ap-northeast-1',

    // User Pool
    userPoolId: 'ap-northeast-1_XXXXXXXXXXXXX',
    appClientId: 'XXXXXXXXXXXXXXXXXXXXXXXX',

    // Federated Identity
    identityPoolId: 'ap-northeast-1:XXXXXXXXXXXXXXXXXXXXXX',
}
```

３. API Gateway の管理コンソール にアクセスします。

４. Terraformで構築したAPI Gateway > ステージ > demo（ステージ名） > SDK の作成 タブ に遷移し、プラットフォーム で JavaScript を選択して、SDKの生成ボタン を押下してダウンロードします。
![apigw_sdk_create.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283246/4cc3cb5b-e1f6-a261-0605-6404c637ca62.png)

５. ダウンロードした [javascript_YYYY-MM-DD_HH-MMZ.zip] をzip展開し、作成されたフォルダ [apiGateway-js-sdk] の直下の [apigClient.js] ファイルを 2で、zip展開した[Serverlesshandson]-[webpage]-[lib]-[apigateway] フォルダの直下にコピーします。（既存のファイルと置き換えます。）

６. 2で、zip展開した[Serverlesshandson]-[webpage]-[443]フォルダ内の[apigateway.js] [login.html][mypage.html] の３つのファイルを [Serverlesshandson]-[webpage]フォルダ直下にコピーします。（既存のファイルと置き換えます。）

参考：
[1-3. Web ブラウザからの動作確認](https://aws.amazon.com/jp/builders-flash/202102/hajimete-serverless-handson-3/?awsf.filter-name=*all#01-03)

これで、サーバーレスの環境にアクセステストするフロント環境の準備は完了です。

# 動作検証してみる
１. [Serverlesshandson]-[webpage]内の[login.html]をクリックして、WebPageを表示します。
![00_first_page.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283246/4b4cc559-ebe7-ce4a-eb29-bfe80c45fac4.png)


２. Sign-in していない（Cognitoで認証されていない）ので、<font color="Red">認証されていない場合のロール</font>が使用されていることを確認できます。
![01_not_logged_in.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283246/01a02fdc-6b85-036f-77d3-554bab338185.png)

３. 認証されていない状態で、API Gateway Test の Post methodを実行すると、失敗することを確認できます。
![02_post_method_403.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283246/c3e365e6-8353-022e-87a9-d40b4439cdc6.png)

※もし動作しない場合は、念の為、API Gatewayの再デプロイをして確認してください。

４. 次に、Sign-upをして、ユーザを作成します。
![03_Sign-up.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283246/2d292efa-919b-33cd-588c-94446fd6b58a.png)

５. ユーザのアクティベーションを実行します。
![04_Activation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283246/37c9ccd5-6f97-e7a7-4ae8-dbfc9874f69f.png)

６. アクティベーションに成功したユーザで、Sign-in します。
![05_Sign-in.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283246/82487bb8-a043-6d5d-5386-08697d3a586f.png)

７. Sign-inが成功すると<font color="Red">Cognitoで認証された場合のロール</font>が使用されていることを確認できます。
![06_logged_in.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283246/ffa27167-03da-b453-3c38-353585b07c8d.png)

８. IDプールから<font color="Red">IDトークン</font>が発行されていることを確認できます。
![07_id_token.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283246/b9f11b13-61bd-556e-ee49-712fa2e9d09b.png)

９. IDプールから<font color="Red">アクセストークン</font>が発行されていることを確認できます。
![08_Access_token.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283246/a403b1f8-987e-b8fa-b2a7-24d3e06e702e.png)

１０. 認証された状態で、API Gateway Test の Post methodを実行すると、成功することを確認できます。
![09_post_method_200.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283246/92a5c925-a195-c2e2-7c8d-7e85e13a844b.png)

１１. API Gateway Test の Get methodを実行すると、Postしたデータを取得できることを確認できます。
![10_get_method_200.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283246/f0bd7403-819c-6e62-18b5-0a5bd112bccc.png)

環境の詳細や各動作の詳細は、Terraformのコードを参照していただければと思います。

#後片付け
下記コマンドで、Terraformで作成したAWS環境を削除します。

```
$ terraform destroy
```

#さいごに
少しでも初学者のサーバーレスの学習に役立てれば幸いです。

#参考サイト
[はじめてのサーバーレス ~ サーバーレスな会員制サイトを作ってみよう ~ 第 1 回](https://aws.amazon.com/jp/builders-flash/202011/hajimete-serverless-handson/)
[はじめてのサーバーレス ~ サーバーレスな会員制サイトを作ってみよう ~ 第 2 回](https://aws.amazon.com/jp/builders-flash/202101/hajimete-serverless-handson-2/)
[はじめてのサーバーレス ~ サーバーレスな会員制サイトを作ってみよう ~ 第 3 回](https://aws.amazon.com/jp/builders-flash/202102/hajimete-serverless-handson-3/)
[AWS再入門ブログリレー Amazon Cognito編](https://dev.classmethod.jp/articles/re-introduction-2020-amazon-cognito/)
[[AWS Black Belt Online Seminar] Amazon API Gateway](https://d1.awsstatic.com/webinars/jp/pdf/services/20190514_AWS-Blackbelt_APIGateway_rev.pdf)
[[AWS Black Belt Online Seminar]Amazon Cognito](https://d1.awsstatic.com/webinars/jp/pdf/services/20200630_AWS_BlackBelt_Amazon%20Cognito.pdf)