AWSのAPI Gatewayを通信がインターネットに出ていかずにVPCの中だけに限定するには、以下の設定が必要です。
- API Gateway用のVPCエンドポイント作成
- API GatewayのリソースポリシーでVPCエンドポイントからのアクセスのみに制限
- 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