目次

Lambdaオーソライザーを理解してみる

ようやくLambdaオーソライザーが理解できました(多分)

簡単に言うと、Lambdaオーソライザーは、後続のAPIを実行するポリシードキュメントを返す仕組みです。
ポリシードキュメントを返す際、キー/値ペアを含む context マップも含まることがあります。
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html

下記は、認証に成功した場合のフロー図です。

はじめに

APIの統合リクエストは、eventをLambdaに渡したかったので「Lambda プロキシ統合の使用」を有効にしています。

気にしたことが無かったのですが、下図のメソッドリクエストの認可で、オーソライザーに設定した名前を選択しないとオーソライザーが有効にならないんですね。
オーソライザーに設定したLambdaは実行されるので、有効になっているものだと思いました・・・。※CloudWatchlogsにログ出てたら有効と思うじゃん!!!

クライアントからのAPIの呼び出しは、下記の通りcurlコマンドでAuthorizationヘッダーを指定して呼び出しています。

curl -v https://XXX.execute-api.ap-northeast-1.amazonaws.com/test -H "Authorization:1"

設定値

APIGateway

■オーソライザー
・名前:LambdaAuth
・タイプ:Lambda
・Lambda関数:LambdaAuthorization
・Lambda イベントペイロード:リクエスト
・ID ソース:Authorization
・認可のキャッシュ:無効

■API
・タイプ:REST API
・エンドポイントタイプ:パブリック
・メソッド:GET
・メソッドリクエスト(認可):LambdaAuth
・Lambda プロキシ統合の使用:有効
・統合タイプ:Lambda関数(AllowResponse)
・ドメイン:https://XXX.execute-api.ap-northeast-1.amazonaws.com
・ステージ:test

Lambda(オーソライザー用)サンプル

・event情報(headersのIDソースなど)を元に、認証判定
・許可の場合:プリンシンバルID、後続処理のポリシードキュメント(資格情報)、ContexをReturn
・拒否の場合:プリンシンバルID、後続処理のポリシードキュメント(資格情報)をReturn

Contexはkey-valueで定義できて、返却した値はAPIで指定したLambda関数のevent['requestContext']['authorizer']に格納されます。

def lambda_handler(event, context):

    token = event['headers']['Authorization']
    if token == '1':  

        return {
            'principalId' : "LambdaAuthorization",
            'policyDocument' : {
                'Version' : '2012-10-17',
                'Statement' : [
                    {
                        "Action": "execute-api:Invoke",
                        "Effect": "Allow",
                       #下記の形式を許可しますが、汎用的なオーソライザーにすると思うので*を用いています。
                       #"Resource": "arn:aws:execute-api:ap-northeast-1:{アカウントID}:{api-id}/{{stageNameOrWildcard}}/{{httpVerbOrWildcard}}/{{resourcePathOrWildcard}}"
                        "Resource": "arn:aws:execute-api:ap-northeast-1:*"
                    }
                ]
            },
            'context': {
                    "sukina": "KeyValue",
                    "wo": "settei",
                    "dekiru": "YO"
            }
        }

    return {
        'principalId' : "LambdaAuthorization",
        'policyDocument' : {
            'Version' : '2012-10-17',
            'Statement' : [
                {
                    #公式ではexecute-api:Invokeに対してDenyしていますが、全てのアクションDenyで良いかなと思って下記のようにしています。
                    "Action": "*",
                    "Effect": "Deny",
                    "Resource": "*"   
                }
            ]
        }
    }

Lambda(API用)サンプル

受取ったeventをbodyに渡すだけの関数です。

import json
   
def lambda_handler(event, context):
    jsn_str = json.dumps(event, ensure_ascii=False, indent=2)
    return {
        'isBase64Encoded': False,
        'statusCode': 200,
        'headers': {},
        'body': jsn_str
    }

豆知識

Lambdaオーソライザのタイムアウトと、後続の統合リクエストで呼び出すLambdaは、タイムアウトの最大値はそれぞれ29秒のようです。(Lambdaオーソライザは動作仕様で確認)
なお、Lambdaオーソライザで28秒、統合リクエストで28秒かかるLambda関数を設定してみましたが、56秒程で応答が返ってきましたのでAPIGateway全体で29秒以内となるわけでは無いようです。

クライアントにエラーが返る場合のフロー図

下図は、Lambdaオーソライザーの関数で拒否(Deny)された場合のフロー図になります。
※ポリシードキュメント(資格情報)に、APIの実行権限が無いためエラーとなる。

Lambdaオーソライザーの関数で拒否(Deny)された場合

下記コマンドのように、オーソライザーのLambda関数で拒否(Deny)される値の場合は、クライアント側にはエラー(403 Forbidden)がレスポンスされる。

curl -v https://XXX.execute-api.ap-northeast-1.amazonaws.com/test -H "Authorization:2"

定義されたヘッダーがない場合

下記コマンドのように、ヘッダーにイベントソース(Authorization)が無い場合は、クライアント側にはエラー(401 Unauthorized)がレスポンスされる。

curl -v https://XXX.execute-api.ap-northeast-1.amazonaws.com/test -H "Auth:1"

Lambdaオーソライザーの関数がエラーの場合

クライアント側にはエラー(500 Internal Server Error)がレスポンスされる。