Amazon API GatewayでAPIキー利用者の情報をbackendに渡す

以下ユースケースを実現する設定, 実装をする

## ユースケース
外部のA社とB社にAmazon API Gateway(以下API Gateway)のREST APIを使用してAPIを公開している
認証方法はA社とB社それぞれにAPI Gatewayで発行したAPIキーを利用してもらう
backendでどの会社からのリクエストかを判定して認可処理をする

## アーキテクチャ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481044/babcdead-a486-d41c-5a5c-df7add57c799.png)
Lambda Authorizerを使用する

## 設定手順
1. backendを用意する
今回はローカルで立てたexpressサーバーをngrokでpublicに公開する  

    1. HTTPリクエストヘッダー"x-company"の値をそのままレスポンスするexpressサーバーを起動する
        ```javascript:node.js
        const express = require('express');
        const app = express();
        
        app.get('/', (req, res) => {
          res.send(req.headers['x-company']);
        });
        
        app.listen(80, () => { });
        ```
    1. ngrokを起動する
        ```script
        ngrok http 80
        ```
1. API Gateway REST APIを作成する  
    1. 適当な設定値でREST APIを作成する
    1. 以下のパラメータでメソッドを作成する
        - 統合タイプ: HTTP
        - エンドポイント URL: \<ngrokのURL\>
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481044/455207ec-972e-854c-6dbe-4e4c443087eb.png)
    1. [メソッドリクエスト]で[API キーの必要性]をtrueに設定する
1. APIキーを作成する
    1. company Aとcompany B用のAPIキーを作成する
      IDはあとで使用する
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481044/e1df1b7e-60fd-c162-7cd9-6cf9f39a38bc.png)
1. Lambda Authorizerを作成する
    1. Node.jsでLambda関数を作成する
    1. 以下コードを入力する
        ```javascript:node.js
        import { APIGatewayClient, GetApiKeyCommand } from '@aws-sdk/client-api-gateway';
        
        export const handler = async function(event, context) {
            const client = new APIGatewayClient();
            
            // API GatewayにあるAPIキーの値を取得する
            const apiKeyCompanyA = (await client.send(new GetApiKeyCommand({apiKey: '<company AのAPIキーのID>', includeValue: true}))).value;
            const apiKeyCompanyB = (await client.send(new GetApiKeyCommand({apiKey: '<company BのAPIキーのID>', includeValue: true}))).value;
            
            // ヘッダーに付与されたAPIキーを取得
            const requestedApiKey = event.headers['x-api-key'];
            
            let xCompany = '';
            
            switch (requestedApiKey) {
              case apiKeyCompanyA:
                xCompany = 'companyA';
                break;
              case apiKeyCompanyB:
                xCompany = 'companyB';
                break;
            }
        
            let authResponse = {};
            authResponse.principalId = 'me';
            let policyDocument = {};
            policyDocument.Version = '2012-10-17';
            policyDocument.Statement = [];
            let statementOne = {};
            statementOne.Action = 'execute-api:Invoke';
            statementOne.Effect = 'Allow';
            statementOne.Resource = event.methodArn;
            policyDocument.Statement[0] = statementOne;
            authResponse.policyDocument = policyDocument;
            // どの会社かを記録
            authResponse.context = {
                'xCompany': xCompany,
            };
            
            return authResponse;
        }
        ```
    1. LambdaからAPIキーを取得するため、LambdaのIAMロールに"apigateway:GET"できるIAMポリシーを追加する
1. REST APIにLambda Authorizerを設定し、Authorizerで設定した変数をbackendに渡す
    1. 以下のパラメータでLambda Authorizerを作成する
        - Lambda イベントペイロード: リクエスト
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481044/e4319031-0d68-8997-074c-9656aa481ae4.png)
    1. REST API -> [メソッドリクエスト] -> [認可]　で作成したLambda Authorizerを設定する
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481044/0c26071c-eb72-2b04-7a79-a1d03e0fce38.png)
    1. REST API -> [統合リクエスト] -> [HTTP ヘッダー]　で以下設定をする
        - 名前： x-company
        - マッピング元: context.authorizer.xCompany
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481044/8c94ed6b-ab74-bcf6-14a5-ab9337ce6491.png)
1. REST APIをデプロイする
1. REST APIと使用量プランとAPIキーを紐づける

## 動作確認
```script
$ curl <REST APIのURL> -H "x-api-key: <company AのAPIキー>"    
companyA%                                                                                

$ curl <REST APIのURL> -H "x-api-key: <company BのAPIキー>"    
companyB%
```