【API Gateway】IPアドレスによるアクセス制限を実装・設定する方法

API Gatewayで実装したAPIにおいてIPアドレスによるアクセス制限をする必要が出てきたため、その方法を調査・実装した。

# 結論
API GatewayのLambdaタイプオーソライザーを作成し、特定のIPアドレスにのみ認可を与えることでアクセス制限をかけることができる。

# 実装内容
まず、オーソライザーの本体となるLamnda関数を実装する。

```javascript
exports.handler = async (event) => {
    if(event.authorizationToken){
        // X-forwarded-forの内容がトークンに設定されるので、
        // カンマで区切りで取得したIPアドレスの一番最初の要素がアクセス元のIPアドレスになる
        ip = event.authorizationToken.split(',')[0].trim();
    }
    else{
        return generatePolicy('user', 'Deny', event.methodArn);
    }
    
    // 許可するIPアドレスのリスト
    const allowIps = [
        '（許可するIPアドレス）'
    ];

    // 許可するIPアドレスに含まれているか確認
    if(allowIps.includes(ip)){
        return generatePolicy('user', 'Allow', event.methodArn);
    }

    return generatePolicy('user', 'Deny', event.methodArn);
}

const generatePolicy = (principalId, effect, resource) => {
    const policyDocument = {
        Version: '2012-10-17',
        Statement: [
            {
                Action: 'execute-api:Invoke',
                Effect: effect,
                Resource: resource
            }
        ]
    };

    return {
        principalId: principalId,
        policyDocument: policyDocument
    };
}
```
IPアドレスの内容をチェックして、リストに含まれているのであれば認可を出す、という単純なものです。
ここでは許可IPアドレスをハードコーティングしていますが、実際の運用では環境変数を使うなど外部に切り出すと使い勝手が良くなると思います。

次にこの関数をデプロイするので、SAMテンプレートに下記のように定義します。
HandlerやCodeUriのあたりは各々の環境に合わせて変更をする必要があります。
```yml
IpAddressAuthorizationFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: checkIpAddressAuthorization/index.handler
      Runtime: nodejs18.x
      CodeUri: ./public      
```
次はAPI Gatewayにオーソライザーを登録します。
```yml
Api:
    Type: AWS::Serverless::Api
    Properties:
      Auth:
        Authorizers:
          IpAddressAuthorizer:
            FunctionArn:
              Fn::GetAtt:
                - IpAddressAuthorizationFunction
                - Arn
            Identity:
              Header: x-forwarded-for
```
これでx-forwarded-forヘッダーの内容がトークンとして設定され、オーソライザーの処理がIpAddressAuthorizationFunctionで実行される設定になります。

最後に、IPアドレス制限をするAPIにこのオーソライザーを使うように設定をします。
```yml
XXXXFunction:
    Type: AWS::Serverless::Function
    Properties:
      Events:
        XXXXApi:
          Type: Api
          Properties:
            Auth:
              Authorizer: IpAddressAuthorizer
              OverrideApiAuth: true
```
また、API個別に設定するのではなく、全体で設定をする場合はデフォルトオーソライザーに設定しておくこともできます
```yml
Api:
    Type: AWS::Serverless::Api
    Properties:
      Auth:
        DefaultAuthorizer: IpAddressAuthorizer    
        Authorizers:
          IpAddressAuthorizer:
            FunctionArn:
              Fn::GetAtt:
                - IpAddressAuthorizationFunction
                - Arn
            Identity:
              Header: x-forwarded-for
```
## コンソール上で設定する場合
コンソール上ではAPI Gateway > 該当のAPI > オーソライザー > オーソライザーを作成でオーソライザーを作成できます。
![スクリーンショット 2024-03-24 17.27.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/164b9974-938a-a9ed-ee66-5e8f09bab5a2.png)

オーソライザーを使う設定はリソース > 該当のメソッド > メソッドリクエストの設定の編集と進んだ先で設定できます。
![スクリーンショット 2024-03-24 17.30.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/9883d226-56c1-6a89-f922-84012fd97b76.png)