はじめに
API GatewayとLambdaを使用して、リクエスト元のIPアドレスを取得する方法を紹介します。
AWS Serverless Application Model(SAM)のテンプレートを使用して、API Gatewayを設定し、OpenAPI(Swagger)を使用してAPIのスキーマを定義します。Lambda関数をデプロイして、API Gatewayに統合します。そして、Lambda関数のコードで、リクエスト元のIPアドレスを取得します。
普通にリクエストを送ってもAPI Gatewayを通してしまうとリクエスト元のIPアドレス取れないので、マッピングテンプレートを使います。その定義も含めてSAMテンプレートに記述します。
SAM template
まず、SAMテンプレートを使用して、API GatewayとLambda関数を設定します。以下は、SAMテンプレートの例です。
Resources:
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: prod
OpenApiVersion: 3.0.2
DefinitionBody:
Fn::Transform:
Name: AWS::Include
Parameters:
Location: ./apigateway.yaml
MyFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: .
Handler: app.lambda_handler
Runtime: python3.8
Policies:
- AmazonAPIGatewayInvokeFullAccess
Environment:
Variables:
STAGE: prod
Events:
MyApiEvent:
Type: Api
Properties:
RestApiId: !Ref MyApi
Path: /myresource
Method: GET
このSAMテンプレートでは、AWS::Serverless::ApiリソースとAWS::Serverless::Functionリソースが定義されています。API Gatewayの定義には、OpenAPIスキーマが使用されています。x-amazon-apigateway-integrationオブジェクトで、Lambda関数との統合が定義されています。Lambda関数は、AWS::Serverless::Functionリソースで定義され、API Gatewayによって呼び出されます。このLambda関数のコードで、リクエスト元のIPアドレスを取得します。
OpenAPI
SAMテンプレートのAPI Gateway定義には、OpenAPI(Swagger)を使用しています。OpenAPIは、APIのスキーマを定義するためのフレームワークです。以下は、このSAMテンプレートで使用されるOpenAPIの例です。
swagger: "2.0"
info:
title: "My API"
paths:
/myresource:
get:
responses:
'200':
description: "Success"
content:
application/json:
schema:
type: object
properties:
content:
type: string
x-amazon-apigateway-integration:
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations
passthroughBehavior: when_no_templates
httpMethod: GET
requestTemplates:
application/json: '{"body": $input.json("$"), "headers": { "X-Forwarded-For": "$context.identity.sourceIp" }}'
type: aws_proxy
このOpenAPIスキーマでは、/myresource
エンドポイントのGET
リクエストが定義されています。このエンドポイントは、API GatewayからLambda関数に統合されています。x-amazon-apigateway-integration
オブジェクトで、Lambda関数の呼び出し方法が定義されています。味噌は"headers": { "X-Forwarded-For": "$context.identity.sourceIp"
で、ここでリクエスト元のIPアドレスを渡しています。
Lambda側でevent.requestContext.identity.sourceIp
で取得できます。
まとめ
SAM templateって意外に資料が少なくて困ること多いので備忘録的に残しておきます。
ちなみにこの記事はChatGPT3.5使って書いて、ちょっと直しただけなので結構すぐ書けました(便利)
最初はマッピングテンプレートだけコンソールで追加しようと思ったんですが、マッピングテンプレートを追加する場所がわからず、結局templateで書くことにしました。