API GatewayをVPC内のプライベートアクセスのみに限定

AWSAPI Gatewayを通信がインターネットに出ていかずにVPCの中だけに限定するには、以下の設定が必要です。

  1. API Gateway用のVPCエンドポイント作成
  2. API GatewayのリソースポリシーでVPCエンドポイントからのアクセスのみに制限
  3. API GatewayのEndpoint TypeをPrivateに設定

1と2があればできると勘違いしていて、3を対応せずに接続できず、ハマっていました。

参考

3をせずにcurlコマンドでAPIアクセスすると、次のようなレスポンスになります。

> GET /Prod/hello HTTP/1.1
> Host: xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com
> User-Agent: curl/7.68.0
> Accept: */*
> 
< HTTP/1.1 403 Forbidden
< Server: Server
< Date: Tue, 08 Dec 2020 08:39:10 GMT
< Content-Type: application/json
< Content-Length: 23
< Connection: keep-alive
< x-amzn-RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
< x-amzn-ErrorType: ForbiddenException
< x-amz-apigw-id: XXXXXXXXXXXXXXXX

{"message":"Forbidden"}

API Gatewayが403を返すときには x-amzn-ErrorType を見て、AWSドキュメントでトラブルシューティングすればよいようです。

2と3をCloudFormationのテンプレートファイルで記述すると、次のようになります。

AWSTemplateFormatVersion: '2010-09-09'

Parameters:
  ApiGatewayVpce:
      Type: String # vpce-...

Resources:
  SampleApiGateway:
    Type: AWS::ApiGateway::RestApi
    Properties:

      ...

      EndpointConfiguration:
        Types:
          - PRIVATE
      Policy:
        Version: 2012-10-17
        Statement:
          - Effect: Deny
            Principal: "*"
            Action: execute-api:Invoke
            Resource: "execute-api:/*"
            Condition:
              StringNotEquals:
                "aws:sourceVpce": !Ref ApiGatewayVpce
          - Effect: Allow
            Principal: "*"
            Action: execute-api:Invoke
            Resource: "execute-api:/*"
  SampleApiGatewayDeployment:
    Type: AWS::ApiGateway::Deployment
    Properties:
      RestApiId: !Ref SampleApiGateway
      StageName: Prod

関連記事

最近API Gatewayの記事が続いています。