AWS API Gateway - サーバーレス構成のフロントエンドから API Gateway へのアクセスを IAM で制御する

## はじめに
バックエンドのサービス間認証は以下の IAM と API Gateway を使用したアクセス制御で良いですが、フロントエンドから APサーバー（BFF） を挟まず、直接 API Gateway にリクエストを行うサーバレスの要件が上がってきました。いいや、降りてきました。
その場合、 cognito を使用して AWS リソースへのアクセス許可を取得するのが一般的なようで、そのとき行った設定をメモしておきます。

https://qiita.com/ishiyama0530/items/e4fc6e33c435375ea85e

## やりたいこと
フロントエンドから直接…

- cognito（IDプール） から未認証ユーザーのロールを付与してもらい、ゲストユーザーとして未認証ユーザー用の API が実行できる。
- cognito 認証後、認証済みユーザー用の API が実行できる。

## Cognito

##### 1. ユーザープールの作成

デフォルトの設定を使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62209/ebe608cc-2f41-fb9b-5413-6a7484865c1d.png)

##### 2. アプリクライアントの追加

「クライアントシークレットの生成」を解除し、SRP認証を有効にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62209/9ad2865a-762e-37f7-569b-72a343439913.png)

**USER_SRP_AUTH**

SRP 認証に関しては以下の記事で投稿してたりします。

https://qiita.com/ishiyama0530/items/426dc3f76f68bf586c28

##### 3. IDプールの作成

未認証のユーザーに対してもアクセス制御（許可）を行いたいので 「認証されていない ID に対してアクセスを有効にする」 をチェック。
また、認証プロバイダーに先程作成したユーザープールを設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62209/8b4fef48-8824-020c-01cd-698c4505a8f1.png)

## API Gateway

##### 1. API を作成
「REST API」 を選択。

##### 2.リソースの作成
未認証ユーザーに公開する`/public` 
認証済みユーザーに公開する`/private`
を同じ設定で作成します。

フロントエンドから直接リクエストするので CORS を有効にしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62209/4d270f9e-1383-5603-b0a4-9bf3d15e4041.png)

##### 3. HTTPメソッドの作成
どちらもモックデータをを返すように設定しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62209/865a2db4-ab06-45c9-e5a8-2ec4a161d421.png)

##### 4. モックレスポンスの設定
`/public` と `/private` どちらかを判別できるレスポンスにしておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62209/b4af7d86-5887-727b-7193-6357a91faf14.png)

##### 5. 動作確認
一度デプロイして動作確認をしてみます。何も設定していないのでどちらにもリクエストが通ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62209/3d5d9974-4111-0fb6-49a4-d5e84496dd33.png)

##### 6. アクセス制御の設定
未認証ユーザーに公開する`/public`
認証済みユーザーに公開する`/private` 
どちらも同じく 「AWS IAM」 を設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62209/508c3760-f0fa-9640-d221-b181303711a6.png)

##### 7. 動作確認
デプロイし直します。
著名が付与されていないリクエストがブロックされることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62209/6f141058-be4a-02be-1af2-32bcdcfe370f.png)

## IAM

##### 1. IAM ロールの確認

ID プールを作成したときに一緒に作った 「認証されていないロール」 「認証されたロール」 に対して API Gateway のアクセス許可を設定していきます。
設定されている IAM ロールは ID プールの管理画面 「ID プールの編集」 から確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62209/023ce452-4f8d-96dc-76ca-d3e4b6216f6a.png)

##### 2. IAM ポリシーの設定
「認証されていないロール」 は `/public` に
「認証されたロール」 は `/public` `/private`の両方に対して以下のように設定していきます。

※ インラインポリシー、ビジュアルエディタ どちらも 「認証されたロール」 に対して設定を行ったときのキャプチャです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62209/e3ea6a4c-6855-4f82-9021-09f65dd54c64.png)

ビジュアルエディタから登録する場合は以下のように
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62209/0bf0fae0-455c-606b-e53f-d18756375616.png)

## フロントエンド

フロントエンドを作成していきます。

```bash
$ npx create-react-app aws-hello --template typescript
```

[著名の作成](https://docs.aws.amazon.com/ja_jp/general/latest/gr/signature-version-4.html) がとても面倒ですが `aws-amplify`のパッケージを使用することで、その工程を意識せずに認証を行うことができます。

```bash
$ npm i aws-amplify
```

## 力尽きました。

長々と書いていて力尽きました。笑
amplify と React.js を使用した SRP 認証の実装は以下を参照していただくと…

https://qiita.com/ishiyama0530/items/426dc3f76f68bf586c28#user_srp_auth-%E3%83%95%E3%83%AD%E3%83%BC%E3%81%AB%E3%82%88%E3%82%8B%E8%AA%8D%E8%A8%BCreactjs

ログイン前は IDプールから未認証の IAM ロールが付与され `/public` のみ実行でき、
ログイン後は認証済みの IAM ロールが付与されて `/public` と `/private` どちらの URL もフロントエンドから直接リクエストできるようになります。
アドレスバーなどから `/public` を実行しても未認証用の IAM ロールが付与されていないため、リクエストは通りません。

そして、ログインするためのユーザーは cognito の管理画面で作っておきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62209/648b4a07-2b83-b37d-a6d8-6515777de598.png)

## まとめ

AWS の認証をうまく使って、機能開発から認証を切り離して開発効率上げたいですね 😇