0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

API GatewayにLamba Authorizerを組み込む

Posted at

はじめに

API GatewayにLambda Authorizerを組み込んで、以下のことを実施しました。

  • Headerにセットされている値をチェックする認証処理の実装。
  • 後続のバックエンド(Lambda)に渡すデータをセット。

一応前回までで構築しているPubSubの仕組みにAuthorizerを追加した構成になりますが、Authorizerについては前提構成なしで本記事だけで内容を追っていけると思います。
image.png
前回までの構成は以下記事で投稿しています↓

以下順序で整理していこうと思います。

  1. Authorizer用のLambdaの作成。
  2. コンソールからAPI GatewayにAuthorizerを設定する。
  3. 後続Lambdaに追加データを引渡すようにAuthorizer Lambdaを修正。

Authorizer用のLambdaの作成

関数名をAuthForPubSubとし、Authorizer用の関数をpythonで作成していきます。
今回はリクエストヘッダーを確認したいのでチェックするtokenevent['headers']['Authorization']を指定します。値がabcであれば後続Lambdaを呼び出すポリシーを返却します。

import json
from logging import getLogger, INFO

logger = getLogger(__name__)
logger.setLevel(INFO)

def lambda_handler(event, context):
    print("============ output event =================")
    logger.info(json.dumps(event))
    
    token = event['headers']['Authorization']
    effect = 'Deny'
    if token == 'abc':
        effect = 'Allow'
        
    return_policy = {
        'principalId': '*',
        'policyDocument': {
            'Version': '2012-10-17',
            'Statement': [
                {
                    'Action': '*',
                    'Effect': effect,
                    'Resource':  event['methodArn']
                }    
            ]
        }
    }
    
    logger.info(json.dumps(return_policy))
    return return_policy

API Gatewayコンソールにて、Authorizerの設定

API Gatewayのコンソールから対象のAPIを選択し、Authorizers>>Create New AuthorizerからAuthorizerを選択します。
Lambda関数は先ほど作成した関数を指定します。Event PayloadをRequestとし、HeaderAuthorizationが含まれている前提で認証ロジックを実施したいので、以下のように設定します。
また、リクエスト毎にAuthorizerを起動させたいので、キャッシュはしません。
image.png

ここで少し躓いたのですが、今回はコンソールからAuthorizerを設定しているため、以下の箇所でもAuthorizerの設定が必要です。(CloudFormationとかを利用していれば意識しなくてよいのかも)
image.png
image.png

そして更に忘れがち(実際に忘れていて、テスト実行したらエラーとなって焦りました)なのが、このようにAuthorizerを設定したら再度APIをデプロイすることです。忘れずに実施しましょう。
image.png

動作確認テスト

PostmanからRESTリクエストを実施します。まずは正常系から確認します。ヘッダーにAuthorizationをKeyとしてValueにabcをセットします。bodyは適当にセット。
image.png
image.png
リクエストをSendすると、無事にステータス200が返却され、バックエンドLambdaで設定していた返却値が確認できました。
image.png
また、今回は事前に作成していたバックエンドの仕組みでDynamoDBに新規Itemも格納しています。そちらでも無事にbodyにセットした値が格納されているのを確認できました。
image.png

次に異常系も確認していきます。まずはHeaderがセットされていないバージョン。
401Unauthorizedが返ってきました。Authorizerの設定の際に指定したHeaderがそもそもセットされていないので、Authorizer Lambdaに渡されるより前にAPI Gatewayではじかれています。
image.png

次にHeaderのValueが異常値のケース。
こちらは403Forbiddenが返ってきました。AuthorizerのLambdaに渡った後に、ロジックの制御にてDenyのポリシーが返却されていることが分かります。
image.png
このような違いを見てみると、Authorizerの動作なども細かく確認できます。

後続Lambdaにデータを引渡すようにAuthorizer Lambdaを修正。

次に、Authorizer側で所定の値(もしくはDBなどから取得したリクエストに適した値など)をセットするような使い方を検証してみます。

Authorizer Lambdaの更新

以下のように修正します。

import base64
import json
from logging import getLogger, INFO

logger = getLogger(__name__)
logger.setLevel(INFO)

def lambda_handler(event, context):
    print("============ output event =================")
    logger.info(json.dumps(event))
    
    token = event['headers']['Authorization']
    effect = 'Deny'
    if token == 'abc':
        effect = 'Allow'
        
    context = {
        "overwrite_message": "this is override message from authorizer."
    }
    
    json_context = json.dumps(context)
    base64_context = base64.b64encode(json_context.encode('utf8'))
        
    return_policy = {
        'principalId': '*',
        'policyDocument': {
            'Version': '2012-10-17',
            'Statement': [
                {
                    'Action': '*',
                    'Effect': effect,
                    'Resource':  event['methodArn']
                }    
            ]
        },
        'context': {
            'overwrite_message': base64_context.decode('utf-8')
        }
        
    }
    
    logger.info(json.dumps(return_policy))
    return return_policy
  • returnデータに含まれているcontextに、overwrite_messageという名前でデータを渡しています。
  • contextにはJSONや配列を設定できないため、JSONをbase64でエンコードした文字列を返す様にしています。

バックエンド側のLambdaではoverwrite_messageを利用して、リクエスト時にbodyにセットされたメッセージを上書きするような内容に編集しました。

import base64
import boto3
from datetime import datetime
import json

client = boto3.client('sns')

def logging(errorLv, LambdaName, errorMsg):
    loggingDateStr=(datetime.now()).strftime('%Y%m%d %H:%M:%S')
    print(loggingDateStr + " " + LambdaName + " " + "[" + errorLv + "] " + errorMsg)
    return

def lambda_handler(event, context):
    
    logging("info", context.function_name, "lambda started")
    
    overwrite_message = event['requestContext']['authorizer']['overwrite_message']
    overwrite_message = base64.b64decode(overwrite_message)
    overwrite_message = json.loads(overwrite_message)
    print(overwrite_message)
    
    params = {
        'TopicArn': 'arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:myFirstTopic_std',
        'Subject' : 'Published From: deliverTopicToSNS_Test01',
        # 'Message' : event['body']
        'Message' : overwrite_message['overwrite_message']
    }
    
    try:
        response = client.publish(
            TopicArn = params['TopicArn'],
            Subject = params['Subject'],
            Message = params['Message']
        )
        
        print(json.dumps(response))
        return {
            'statusCode': 200,
            'body': json.dumps('A new message has been published')
        }
        

    except Exception as e:
        print(e)
        raise e

event['requestContext']['authorizer']['overwrite_message']からAuthorizer Lambdaでセットしたメッセージを取得しています。

再び動作確認

再度動作確認をPostmanから実施します。ヘッダーは正常値に戻し、リクエストを実施。
リクエストのbodyでは以下のようにメッセージをセットしていますが、、
image.png
DynamoDBに新規追加されたItemを確認すると、無事に上書きされたメッセージとなっていることを確認できました。
image.png

終わりに

今回API GatewayにLambda Authorizerを追加してみて、柔軟なAPIアクセス制限を実現できることが分かりました。そもそもバックエンド側へ渡したくないようなリクエストはAuthorizerではじけますし、Authorizerロジックとしてはリクエストの内容を確認してDBと参照させたり、後続バックエンドLambdaに渡すcontextをコントロールすることで、後続Lambda側でのパターン分けロジックなどにもつなげられそうです。

参考サイト

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?