Movatterモバイル変換


[0]ホーム

URL:


developersIOproduced by Classmethod

API GatewayのLambda オーソライザーから後続のLambdaにデータを引き渡す

API GatewayのLambda オーソライザーから後続のLambdaにデータを引き渡す

API GatewayのLambdaオーソライザー(カスタムオーソライザー)から後続処理にデータを引渡す方法について調査してみました。
2018.05.25

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

サーバーレス開発部@大阪の岩田です。

API GatewayのLambda オーソライザー (以前のカスタムオーソライザー)について調べる機会があったので、調査したことをまとめます。

Lambdaオーソライザーとは?

以前はカスタムオーソライザーと呼ばれていた機能で、Lambdaを使用してAPIメソッドへのアクセスを制御する機能です。

以前こちらの記事でも紹介されています。

Amazon API Gateway で Custom Authorization を使ってクライアントの認可を行う

現在開発しているアプリの中で、単なる認可処理だけではなく

  • 処理の中で取得した情報を後続のLambdaに引き渡したい
  • Lambdaオーソライザーで認証が失敗した場合のエラーメッセージをカスタマイズしたい

という要件があり、実現方法について調査しました。

手順

まずはSAMを使って簡単なAPIと裏で動くLambdaを作成します。なお、ランタイムにはpython3.6を使用しています。

template.yaml

AWSTemplateFormatVersion: '2010-09-09'Transform: AWS::Serverless-2016-10-31Description: LambdaAuthorizer TestResources:  Hello:    Type: AWS::Serverless::Function    Properties:      CodeUri: .      Handler: hello.lambda_handler      Runtime: python3.6      Events:        HelloWorld:          Type: Api          Properties:            Path: /            Method: get

ソースコードはこれだけです。

hello.py

def lambda_handler(event, context):    return {        "statusCode": 200,        "body": 'hello'    }

デプロイしてみます。

aws cloudformation package --template-file template.yaml --output-template-file output.yaml --s3-bucket xxxxxaws cloudformation deploy --template-file output.yaml --stack-name lambda-authorizer-test --capabilities CAPABILITY_IAM

デプロイできたので、動作を確認してみます。

curl https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Stage/hello

まずは動作確認OKです。

Lambdaオーソライザーの設定

先程作成したAPIにLambdaオーソライザーを設定していきます。まずは認可処理に使うLambdaを実装します。Authorizationヘッダに1が入ってたら認証OKとするだけのプログラムです。

authorizer.py

def lambda_handler(event, context):    token = event["headers"]["Authorization"]    if token == "1":            return {            "principalId" : 1,            "policyDocument" : {                "Version" : "2012-10-17",                "Statement" : [                    {                        "Action": "*",                        "Effect": "Allow",                        "Resource": "arn:aws:execute-api:*:*:*/*/*/"                       }                ]            }        }    return {        "principalId" : 1,        "policyDocument" : {            "Version" : "2012-10-17",            "Statement" : [                {                    "Action": "*",                    "Effect": "Deny",                    "Resource": "arn:aws:execute-api:*:*:*/*/*/"                   }            ]        }    }

SAMテンプレートは下記の様に修正しました。template.yaml

AWSTemplateFormatVersion: '2010-09-09'Transform: AWS::Serverless-2016-10-31Description: LambdaAuthorizer TestResources:  Hello:    Type: AWS::Serverless::Function    Properties:      CodeUri: .      Handler: hello.lambda_handler      Runtime: python3.6  Authorizer:    Type: AWS::Serverless::Function    Properties:      CodeUri: .      Handler: authorizer.lambda_handler      Runtime: python3.6  LambdaPermissionHello:    Type: "AWS::Lambda::Permission"    Properties:      Action: lambda:InvokeFunction      FunctionName: !Ref Hello      Principal: apigateway.amazonaws.com  LambdaPermissionAuthorizer:    Type: "AWS::Lambda::Permission"    Properties:      Action: lambda:InvokeFunction      FunctionName: !Ref Authorizer      Principal: apigateway.amazonaws.com  HelloAPI:    Type: AWS::Serverless::Api    Properties:      StageName: Dev      DefinitionBody:        swagger: "2.0"        info:          version: "1.0.0"          title: "lambda authorizer test"        basePath: "/"        schemes:        - "http"        paths:                /:            get:              summary: "lambda authorizer test"              description: "lambda authorizer test"              produces:              - "application/json"              responses:                "200":                  description: "successful operation"              x-amazon-apigateway-integration:                uri:                  Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Hello.Arn}/invocations                passthroughBehavior: "when_no_match"                httpMethod: "POST"                contentHandling: "CONVERT_TO_TEXT"                type: "aws_proxy"                responses:                  default:                    statusCode: "200"              security:                - test-authorizer: []        securityDefinitions:          test-authorizer:            type: apiKey            name: Authorization            in: header            x-amazon-apigateway-authtype: custom            x-amazon-apigateway-authorizer:              type: request              identitySource: method.request.header.Authorization              authorizerUri:                Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Authorizer.Arn}/invocations

再度デプロイして動作を確認します。※最初に作成したAPI Gatewayは削除されます。

curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Dev/{"message":"Unauthorized"}curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Dev/ -H Authorization:1hellocurl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Dev/ -H Authorization:2{"Message":"User is not authorized to access this resource with an explicit deny"}

Authorizationヘッダに1を設定した場合だけ正常応答が返ってきています。

後続処理へのデータの引き渡し

ここからが本題です。Lambdaオーソライザーの中で取得した情報を後続処理に引き渡します。authorizer.pyを下記の様に修正します。

import base64import jsondef lambda_handler(event, context):    token = event['headers']['Authorization']    if token == '1':          context = {          "parent1": "val1",          "parent2":{            "child1": "val1",            "child2": "val2",            }        }         json_context = json.dumps(context)        base64_context = base64.b64encode(json_context.encode('utf8'))        return {            'principalId' : 1,            'policyDocument' : {                'Version' : '2012-10-17',                'Statement' : [                    {                        "Action": "*",                        "Effect": "Allow",                        "Resource": "arn:aws:execute-api:*:*:*/*/*/"                       }                ]            },            'context': {                'additional_info': base64_context.decode('utf-8')            }        }    return {        'principalId' : 1,        'policyDocument' : {            'Version' : '2012-10-17',            'Statement' : [                {                    "Action": "*",                    "Effect": "Deny",                    "Resource": "arn:aws:execute-api:*:*:*/*/*/"                   }            ]        }    }

処理の中で取得した情報をレスポンスとして返却する辞書の['context']['additional_info']に設定しています。注意点として、AWSのドキュメントに記載されている様にcontextにはJSONや配列を設定できないため、JSONをbase64でエンコードした文字列を返す様にしています。

動作検証のため、hello.pyを下記の様に修正します。

import base64import jsondef lambda_handler(event, context):    additional_info = event['requestContext']['authorizer']['additional_info']    additional_info = base64.b64decode(additional_info)    additional_info = json.loads(additional_info)    return {        "statusCode": 200,        "body": json.dumps(additional_info)    }

Lambdaオーソライザーで設定したcontextの中身が、event['requestContext']['authorizer']の中に入っているのでデコードしてそのままレスポンスに返します。

デプロイ後に動作検証してみます。

curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Dev/ -H Authorization:1{"parent1": "val1", "parent2": {"child1": "val1", "child2": "val2"}}

OKです!Lambdaオーソライザー内で取得した情報が後続のLambdaから参照できています!実際の業務では、この情報を元に、権限レベルの低いユーザーに対しては後続のLambdaのレスポンスから特定の項目を削るといった利用方法が考えられます。

エラーメッセージのカスタマイズ

次に、認可処理でエラーになった場合のエラーメッセージをカスタマイズしてみます。authorizer.pyを修正します。

#...略    return {        "principalId" : 1,        "policyDocument" : {            "Version" : "2012-10-17",            "Statement" : [                {                    "Action": "*",                    "Effect": "Deny",                    "Resource": "arn:aws:execute-api:*:*:*/*/*/"                   }            ]        },        "context" : {            "message": "custom error message from lambda"        }    }

Authorizationヘッダが"1"でなかった場合に、返却するポリシーの["context"]["message"]にエラーメッセージを設定しています。

最後に、API GatewayがLambdaオーソライザーで設定されたエラーメッセージを返却する様に、API Gatewayレスポンスの本文マッピングテンプレートを設定します。SAMテンプレートに以下の記述を追加します。

  #...略  GatewayResponse:    Type: "AWS::ApiGateway::GatewayResponse"    Properties:      ResponseTemplates:         application/json: >          {"message":"$context.authorizer.message"}      ResponseType: DEFAULT_4XX      RestApiId: !Ref HelloAPI

デプロイ後に動作検証してみます。

curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Dev/ -H Authorization:2{"Message":"User is not authorized to access this resource with an explicit deny"}

ここで何故か期待したレスポンスが返却されませんでした。マネジメントコンソールから確認したところ、本文マッピングテンプレートは正しく更新できていたので、手動でAPIの再デプロイを試したところ、期待通りのレスポンスが返却される様になりました。

curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Dev/ -H Authorization:2{"message":"custom error message from lambda"}

まとめ

最後に手動の再デプロイが必要な理由がどうしても分からなかったのですが、無事にLambdaオーソライザーと後続のLambdaを連携させることができました!個々のLambdaの中で認証・認可処理を実装することもできますが、Lambdaオーソライザーを有効活用することで、システムをよりマイクロサービス化させることができ、メリットが出せるのではないでしょうか?誰かの参考になれば幸いです。

この記事をシェアする

FacebookHatena blogX

EVENTS

セミナー一覧会社説明会一覧勉強会一覧

関連記事

TOON を使ってプロンプトのトークン数を削減してみる
かわい
2025.12.15
Kiro CLIのLSP対応をPythonで試してみた
quiver
2025.12.15
AWS Lambda durable functionsで並列操作parallelをためしてみた #AWSreInvent
kobayashi.m
2025.12.04
【AWS re:Invent 2025】Agentic AI ft. Dynatrace(GameDay)に参加してきた:AWS Bedrock AgentCoreを使ったAIエージェントの作り方
tomozou
2025.12.03

[8]ページ先頭

©2009-2025 Movatter.jp