【めっちゃ小ネタ】AWS CDK を使って API Gateway のリソースポリシーで IP アドレス制限を実装する方法

# はじめに

こんにちは〜

AWS CDK を使って API Gateway にリソースポリシーを適用する方法を学んで、アクセス制御を実現する方法をシェアします。

今回は TypeScript のコードで AWS CDK を使って API Gateway のリソースポリシーを設定してみました。

手軽に IP アドレス制限ができたので備忘録的にまとめます。

# リソースポリシーを使ってアクセス制御

まず、API Gateway にリソースポリシーを適用することで、アクセスできる IP アドレスを制限することができます。

以下のコードは、AWS CDK を使って API Gateway にリソースポリシーを適用する例です：

```typescript
import { Stack, StackProps, aws_apigateway as apigw } from "aws-cdk-lib";
import { PolicyDocument, PolicyStatement, Effect, AnyPrincipal } from "aws-cdk-lib/aws-iam";

export class SampleStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const resourcePolicy = new PolicyDocument({
      statements: [
        new PolicyStatement({
          effect: Effect.ALLOW,
          actions: ["execute-api:Invoke"],
          principals: [new AnyPrincipal()],
          resources: ["execute-api:/*/*/*"],
        }),
        new PolicyStatement({
          effect: Effect.DENY,
          actions: ["execute-api:Invoke"],
          principals: [new AnyPrincipal()],
          resources: ["execute-api:/*/*/*"],
          conditions: {
            NotIpAddress: {
              // ここで許可したい IP アドレスを指定する
              "aws:SourceIp": ["192.0.2.1", "198.51.100.1", "203.0.113.1"]
            },
          },
        }),
      ],
    });

    const restApi = new apigw.RestApi(this, "sample-api-gateway", {
      restApiName: "sample-api-gateway",
      policy: resourcePolicy
    });

    // .....
  }
}
```

ポリシードキュメントの内容については[こちら](https://repost.aws/ja/knowledge-center/api-gateway-resource-policy-access)を参考にしました。

あとは、CDK のドキュメントを読みながら、Typescript のコードに直していった形ですね。

# リソースポリシーの確認

実際に作られたリソースポリシーを AWS Console で確認すると以下のようになります。リソースポリシーが正しく設定されていることがわかります。（隠したい情報は`~~~~~`と記載させていただきました）

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:ap-northeast-1:~~~~~:~~~~~/*/*/*"
        },
        {
            "Effect": "Deny",
            "Principal": {
                "AWS": "*"
            },
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:ap-northeast-1:~~~~~:~~~~~/*/*/*",
            "Condition": {
                "NotIpAddress": {
                    "aws:SourceIp": [
                        "192.0.2.1",
                        "198.51.100.1",
                        "203.0.113.1"
                    ]
                }
            }
        }
    ]
}
```

ちなみにですが、Resourceのところが、実際に適用した REST API の ARN が適切に設定されていました。

AWS がよしなにやってくれてるのだろうか？？？ CDK の知識不足な気がしています:frowning2:

# アクセス制御の動作確認

次に、実際に curl を使ってリクエストを送ってみてアクセス制御が機能しているか確認しましょう。

```
$ curl -i -X POST https://~~~~~.execute-api.ap-northeast-1.amazonaws.com/dev/~~~~~
HTTP/2 403 
content-type: application/json
content-length: 187
date: Wed, 03 May 2023 13:30:20 GMT
x-amzn-requestid: 15b78ace-adf9-4cd3-ae50-86675c3f7606
x-amzn-errortype: AccessDeniedException
x-amz-apigw-id: ~~~~~
x-cache: Error from cloudfront
via: 1.1 ~~~~~.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT12-C2
x-amz-cf-id: 3UYEUIBrjVm88vQPBB4jlH_HONitQ4eiF0DiO19eyZZVa_2ge4nypg==

{"Message":"User: anonymous is not authorized to perform: execute-api:Invoke on resource: arn:aws:execute-api:ap-northeast-1:~~~~~:~~~~~
```

結果として、IP アドレス制限は正しく機能していることが確認できました！

ただし、レスポンスボディに API Gateway の詳細情報（多少マスクされていましたが）が含まれてしまっています。

このレスポンスの内容を変更したいと考え、Gateway Response をカスタマイズします。

# Gateway Response のカスタマイズ

以下のように CDK のコードに Gateway Response を追加することで、エラーレスポンスの内容を改善できます。

```typescript
		restApi.addGatewayResponse('backlog-mention-notifier-gateway-response', {
			type: apigw.ResponseType.ACCESS_DENIED,	
			templates: {
				'application/json': '{"statusCode": "403", "type": "$context.error.responseType"}'
			}
		});
```

こうすると、エラーレスポンスボディは以下のようになります。

```
{"statusCode": "403", "type": "ACCESS_DENIED"}
```

うん、とてもスッキリしていますね♪

# まとめ

今回は、AWS CDK を使って API Gateway のリソースポリシーを適用し、IP アドレス制限を実現する方法をまとめました。

リソースポリシーによるアクセス制御は、セキュリティを向上させる上で非常に有用です。
また、Gateway Response のカスタマイズによって、エラーレスポンスの内容を適切にすることができました。

皆さんもぜひ、AWS CDK を活用して API Gateway のリソースポリシーを設定し、アクセス制御を実現してみてください。

# 参考

- https://repost.aws/ja/knowledge-center/api-gateway-resource-policy-access
- https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_condition_operators.html#Conditions_IPAddress
- https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway-readme.html