API Key付きのAPI Gateway、LambdaをCDK(Python)で立ち上げた

#AWS
#API Gateway
#API Key
#CDK
#Python

API Gatewayを使ってREST APIを構築し、Lambdaを動かす処理をCDK(Python)で実装していきたいと思います。

また、API GatewayにはAPI Keyという鍵を設定し、httpリクエストのヘッダーに追加することでAPI Keyを知る人のみにリクエストを制限させる機能があるので今回はそれも追加しました。

作りたいパス: GET/user/{id}/token

$ npm install -g aws-cdk $ cd python $ mkdir cdk && cd cdk $ cdk init --language python $ source .venv/bin/activate $ pip install -r requirements.txt

一部編集して以下のように構成

python/ ├ cdk/ │ ├ .venv │ ├ stacks/ │ │ ├ __init__.py │ │ └ api_gateway_stack.py │ └ app.py └ lambda/src/test_api/ └ index.py

CDKを実行するファイルです

ここにスタックを生やしていきます

#!/usr/bin/env python3 import aws_cdk as cdk from stacks.api_gateway_stack import ApiGatewayStack app = cdk.App() ApiGatewayStack(app, "ApiGatewayStack") app.synth()

 

from aws_cdk import ( Duration, Stack, aws_logs as logs, aws_lambda as lambda_, aws_apigateway as apigateway ) from constructs import Construct class ApiGatewayStack(Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) api_test_func = lambda_.Function( self, "test_apiLambda", runtime=lambda_.Runtime.PYTHON_3_9, code=lambda_.Code.from_asset("../lambda/src/test_api"), handler="index.handler", environment={}, timeout=Duration.seconds( 29), memory_size=512 ) logs.LogGroup(self, "apiTestFunctionLogGroup", log_group_name="/aws/lambda/" + api_test_func.function_name, retention=logs.RetentionDays.TWO_MONTHS ) api = apigateway.RestApi(self, "SampleApiGateway") user_univ_token_api = api.root.add_resource( "user").add_resource("{universal_id}").add_resource("token") user_univ_token_api.add_method( "GET", apigateway.LambdaIntegration(api_test_func), api_key_required=True) api_key = apigateway.ApiKey(self, "apiKey") plan = api.add_usage_plan("UsagePlan") plan.add_api_key(api_key) plan.add_api_stage(stage=api.deployment_stage)

「GET/user/{id}/token」というパスのAPIを設定しています

LogGroupのリソースを設定しなくても自動でLambdaのロググループは生成されますが、別途LogGroupを宣言することでretentionを変更することが出来ます。(デフォルトではずっと保持されてしまいます)

API Keyを設定するためには、UsagePlanを作成(add_usage_plan)して、そこに作成したkeyを関連づけします(add_api_key)

Stagesはdeployment_stageを使用することで最新のdeploymentが適用されます(名称はprodになるようです)

 

def handler(event, context): print(event) universal_id = event["pathParameters"]["universal_id"] return { 'statusCode': 200, 'body': f'response: {universal_id}' }

eventのpathParametersの中身を返すLambdaを実装します

$ cd cdk $ cdk deploy

API Gatewayのコンソールを開いて確認します。

 

・Resources -> method選択 -> Method Request イメージ図1

 

・API Keys -> 作成したkeyを選択 イメージ図2

 

・Stages -> prod -> methodを選択 -> Invoke URL:

ここからリクエストに必要なURLを取得できます イメージ図3

  • ・x-api-keyなし
$ curl https://hogehoge.execute-api.ap-northeast-1.amazonaws.com/prod/user/yyyy1234/token

 

レスポンスはこちら、

リクエストが拒否されています

{"message":"Forbidden"}
  • ・x-api-keyあり
$ curl https://hogehoge.execute-api.ap-northeast-1.amazonaws.com/prod/user/yyyy1234/token -H 'x-api-key:<生成したAPI Key>'

 

レスポンスはこちら、

今度は成功しました。

response: yyyy1234

eventの中身を展開すると以下のようになっていました

{ 'body': None, 'headers': {'Accept': '*/*', 'CloudFront-Forwarded-Proto': 'https', 'CloudFront-Is-Desktop-Viewer': 'true', 'CloudFront-Is-Mobile-Viewer': 'false', 'CloudFront-Is-SmartTV-Viewer': 'false', 'CloudFront-Is-Tablet-Viewer': 'false', 'CloudFront-Viewer-Country': 'JP', 'Host': 'co1xc43lxi.execute-api.ap-northeast-1.amazonaws.com', 'User-Agent': 'curl/7.64.1', 'Via': '2.0 1b688f7d4f90b6acf6d7774ff14f6eae.cloudfront.net ' '(CloudFront)', 'X-Amz-Cf-Id': 'LKpvaO8n-LRfrUYIpZ5JXaKTk16CENgvV14ijaDG0Qc0WCyfnJSSvQ==', 'X-Amzn-Trace-Id': 'Root=1-626ff6a9-71cdd36712ca7b5a37254b4a', 'X-Forwarded-For': '122.25.89.126, 70.132.55.90', 'X-Forwarded-Port': '443', 'X-Forwarded-Proto': 'https', 'x-api-key': 'hogehogehugahuge'}, 'httpMethod': 'GET', 'isBase64Encoded': False, 'multiValueHeaders': {'Accept': ['*/*'], 'CloudFront-Forwarded-Proto': ['https'], 'CloudFront-Is-Desktop-Viewer': ['true'], 'CloudFront-Is-Mobile-Viewer': ['false'], 'CloudFront-Is-SmartTV-Viewer': ['false'], 'CloudFront-Is-Tablet-Viewer': ['false'], 'CloudFront-Viewer-Country': ['JP'], 'Host': ['co1xc43lxi.execute-api.ap-northeast-1.amazonaws.com'], 'User-Agent': ['curl/7.64.1'], 'Via': ['2.0 ' '1b688f7d4f90b6acf6d7774ff14f6eae.cloudfront.net ' '(CloudFront)'], 'X-Amz-Cf-Id': ['LKpvaO8n-LRfrUYIpZ5JXaKTk16CENgvV14ijaDG0Qc0WCyfnJSSvQ=='], 'X-Amzn-Trace-Id': ['Root=1-626ff6a9-71cdd36712ca7b5a37254b4a'], 'X-Forwarded-For': ['122.25.89.126, 70.132.55.90'], 'X-Forwarded-Port': ['443'], 'X-Forwarded-Proto': ['https'], 'x-api-key': ['hogehogehugahuge']}, 'multiValueQueryStringParameters': None, 'path': '/user/yyyy1234/token', 'pathParameters': {'universal_id': 'yyyy1234'}, 'queryStringParameters': None, 'requestContext': {'accountId': '020595591797', 'apiId': 'co1xc43lxi', 'domainName': 'co1xc43lxi.execute-api.ap-northeast-1.amazonaws.com', 'domainPrefix': 'co1xc43lxi', 'extendedRequestId': 'RgN6fEcnNjMFosA=', 'httpMethod': 'GET', 'identity': {'accessKey': None, 'accountId': None, 'apiKey': 'hogehogehugahuge', 'apiKeyId': 'zicdyzt9b4', 'caller': None, 'cognitoAuthenticationProvider': None, 'cognitoAuthenticationType': None, 'cognitoIdentityId': None, 'cognitoIdentityPoolId': None, 'principalOrgId': None, 'sourceIp': '122.25.89.126', 'user': None, 'userAgent': 'curl/7.64.1', 'userArn': None}, 'path': '/prod/user/yyyy1234/token', 'protocol': 'HTTP/1.1', 'requestId': '1765058f-9f32-4cfd-9897-efb69657e6b6', 'requestTime': '02/May/2022:15:20:09 +0000', 'requestTimeEpoch': 1651504809354, 'resourceId': '4u2lm3', 'resourcePath': '/user/{universal_id}/token', 'stage': 'prod'}, 'resource': '/user/{universal_id}/token', 'stageVariables': None }