API GatewayのOPTIONSメソッド(CORS)でAPIキーを不要にする(AWS SAM)
API Gatewayを利用すればAPIを簡単に作成できます。 そして、APIキーの設定も簡単にできます。 このとき、CORS用のOPTIONSメソッドでAPIキー設定を次のようにしたかったので、試してみました。
- OPTIONSメソッド: APIキーは不要でよい
- 他のメソッド: APIキーが必須である
おすすめの方
- API Gateway と Lambda の組み合わせでCORSに対応したい方
- API GatewayのOPTIONSメソッド(CORS)でAPIキーを不要にしたい方
まずは、普通にAPIキーが必要なメソッドを作成する
sam init
sam init \ --runtime python3.11 \ --name api-gateway-no-required-api-key-in-options-method-sample \ --app-template hello-world \ --no-tracing \ --no-application-insights \ --structured-logging \ --package-type Zip
SAMテンプレート
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: api-gateway-no-required-api-key-in-options-method-sample Resources: MyApi: Type: AWS::Serverless::Api Properties: StageName: v1 OpenApiVersion: 3.0.1 ApiKeySourceType: HEADER Auth: ApiKeyRequired: true UsagePlan: CreateUsagePlan: PER_API UsagePlanName: no-required-api-key-in-options-method-usage-plan Quota: Limit: 500 Period: MONTH Throttle: BurstLimit: 100 RateLimit: 50 Cors: AllowMethods: "'DELETE,POST,GET,OPTIONS,PUT,PATCH'" AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" AllowOrigin: "'https://www.example.com'" # 実験のため、適当に設定しています。適切な値を設定してください。 HelloWorldFunction: Type: AWS::Serverless::Function Properties: CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.11 Architectures: - x86_64 Events: HelloWorld: Type: Api Properties: Path: /hello Method: get RestApiId: !Ref MyApi HelloWorldFunctionLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub /aws/lambda/${HelloWorldFunction}
Lambdaコード
今回の実験ではブラウザからアクセスしないので不要ですが、「headers」も返しておきます。
import json def lambda_handler(event, context): <pre><code>return { "statusCode": 200, "headers": { "Access-Control-Allow-Methods": "DELETE,POST,GET,OPTIONS,PUT,PATCH", "Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token", "Access-Control-Allow-Origin": "https://www.example.com", }, "body": json.dumps( { "message": "hello world", } ), } </code></pre>
デプロイ
sam deploy \ --guided \ --region ap-northeast-1 \ --stack-name api-gateway-no-required-api-key-in-options-method-sample-stack
OPTIONSメソッドでAPIキーが必須になっていることを確認する
上記の内容をデプロイしたとき、API Gatewayの動作は、APIキーが無いと403が返ってきます。
OPTIONSメソッド(APIキーなし)は、403が返ってくる
$ curl -X OPTIONS -I \ https://xxx.execute-api.ap-northeast-1.amazonaws.com/v1/hello HTTP/2 403
OPTIONSメソッド(APIキーあり)は、200が返ってくる
$ curl -X OPTIONS -I \ -H "x-api-key: valid-api-key" \ https://xxx.execute-api.ap-northeast-1.amazonaws.com/v1/hello HTTP/2 200
GETメソッド(APIキーなし)は、403が返ってくる
$ curl -X GET -I \ https://xxx.execute-api.ap-northeast-1.amazonaws.com/v1/hello HTTP/2 403
GETメソッド(APIキーあり)は、200が返ってくる
$ curl -X GET -I \ -H "x-api-key: valid-api-key" \ https://xxx.execute-api.ap-northeast-1.amazonaws.com/v1/hello HTTP/2 200
OPTIONSメソッドは、APIキーを不要に設定する
SAMテンプレート
「AddApiKeyRequiredToCorsPreflight」を追加しました。未指定の場合は、デフォルトでtrueが設定されるのです。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: api-gateway-no-required-api-key-in-options-method-sample Resources: MyApi: Type: AWS::Serverless::Api Properties: StageName: v1 OpenApiVersion: 3.0.1 ApiKeySourceType: HEADER Auth: ApiKeyRequired: true AddApiKeyRequiredToCorsPreflight: false UsagePlan: CreateUsagePlan: PER_API UsagePlanName: no-required-api-key-in-options-method-usage-plan Quota: Limit: 500 Period: MONTH Throttle: BurstLimit: 100 RateLimit: 50 Cors: AllowMethods: "'DELETE,POST,GET,OPTIONS,PUT,PATCH'" AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" AllowOrigin: "'https://www.example.com'" # 実験のため、適当に設定しています。適切な値を設定してください。 HelloWorldFunction: Type: AWS::Serverless::Function Properties: CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.11 Architectures: - x86_64 Events: HelloWorld: Type: Api Properties: Path: /hello Method: get RestApiId: !Ref MyApi HelloWorldFunctionLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub /aws/lambda/${HelloWorldFunction}
デプロイ
sam deploy
OPTIONSメソッド(APIキーなし)は、200が返ってくる
目論見通り、403ではなく、200が返ってきました。
$ curl -X OPTIONS -I \ https://xxx.execute-api.ap-northeast-1.amazonaws.com/v1/hello HTTP/2 200
OPTIONSメソッド(APIキーあり)は、200が返ってくる
$ curl -X OPTIONS -I \ -H "x-api-key: valid-api-key" \ https://xxx.execute-api.ap-northeast-1.amazonaws.com/v1/hello HTTP/2 200
GETメソッド(APIキーなし)は、403が返ってくる
$ curl -X GET -I \ https://xxx.execute-api.ap-northeast-1.amazonaws.com/v1/hello HTTP/2 403
GETメソッド(APIキーあり)は、200が返ってくる
$ curl -X GET -I \ -H "x-api-key: valid-api-key" \ https://xxx.execute-api.ap-northeast-1.amazonaws.com/v1/hello HTTP/2 200