サイトアイコン 協栄情報ブログ

【API Gateway】トークンベースのLambda Authorizerを使用した認可を実装してみた

はじめに

今回はAPI GatewayでLambda Authorizerを使用した、認可の実装をしていきます。
curlコマンドでPOSTしてみてAPI Gatewayの背後にあるLambdaからのレスポンスを受け取れるか検証をしてみました。

Lambda Authorizerとは

Lambda Authorizerとは、API Gateway にアクセスするリクエストを許可するかどうかを、任意のロジックで判定できる AWS Lambda 関数です。
リクエストの Authorization ヘッダーやクエリ文字列、IPアドレスなどを元に、認可可否を判断し、許可する場合は IAM ポリシーを生成して返します。これにより、CognitoやIAM以外の柔軟な認可が可能になります。

Lambda Authorizerのメリットとデメリット

メリット

1.認可ロジックを柔軟に実装できる

2.外部サービスや社内システムと連携できる

  1. 個別の利用制御ができる
    • API キーごとに 使用量プラン(Usage Plan) を設定し、アクセス回数制限(レート、クォータ)を行える。
    • APIキー単位でアクセス制御や分析が可能(誰がどれだけ使ったか把握できる)。

3.ポリシーキャッシュが使える

4.複数API Gatewayで再利用できる

デメリット

1.レイテンシが増加する

2.リクエスト数に応じてコストが増える

3.実装と運用が複雑

4.エラー原因の特定が難しい

使いどころ

Cognitoなどのマネージド認証を使わず、Auth0や独自のトークン認証を行いたい場合に有効です。ユーザーの属性やIPアドレスなどに応じた柔軟な認可ロジックが必要なケースや、複数のAPIで共通の認可処理を使い回したいときにも適しています。また、外部の認証基盤やセッション管理と連携した高度なアクセス制御を行いたい場合にも選択肢となります。

テスト用Lambdaの作成

下記のような簡単なLambdaを作成しておきます。

import json

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

Authorizer用 Lambdaの作成

トークンの内容はSecrets ManagerSSM Parameter Store等に格納して安全に保管するのがよいと思います。

import json

def lambda_handler(event, context):
    token = event.get('authorizationToken')

    # トークンがない場合は拒否
    if not token:
        return generate_policy('user', 'Deny', event['methodArn'])

    # ここでトークン検証
    if token == "トークンの内容":
        return generate_policy('user', 'Allow', event['methodArn'])
    else:
        return generate_policy('user', 'Deny', event['methodArn'])

def generate_policy(principal_id, effect, resource):
    return {
        "principalId": principal_id,
        "policyDocument": {
            "Version": "2012-10-17",
            "Statement": [{
                "Action": "execute-api:Invoke",
                "Effect": effect,
                "Resource": resource
            }]
        }
    }

APIの作成

メソッドの作成

ここからAPI GatewayでAPIの設定をしていきます。
メソッドはPOST、Lambda関数は先ほど作成したテスト用Lambdaを指定します。
(他の設定はいったんデフォルトでOKです。後々設定します。)

一度デプロイしてcurlを試してみましょう。Hello from Lambda!が返ってくればOKです。

curl -X POST https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/test/

オーソライザーの作成

次にオーソライザーの作成をしていきます。
オーソライザーのタイプLambda、Lambda 関数は先ほど作成したAuthorizer用 Lambdaを指定します。
Lambda イベントペイロード
今回はヘッダーにトークンを指定するだけなので、トークンを選択します。
リクエストでは複数のヘッダーやクエリを元に認可判断したいとき等で使用します。

トークンのソース
Authorizationヘッダーが一般的だと思います。

トークンの検証
TokenタイプのオーソライザーにはToken Validationに正規表現を設定することで、トークンを検証できます。
この項目を設定し、正規表現にマッチしない場合、オーソライザーは実行されませんでした。
オプションなので、なしでもOKです。
トークンの検証については本ページ下部を参照。

作成が完了すると、Authorizer用 Lambdaにリソースベースのポリシーが自動でアタッチされます。

オーソライザーをメソッドリクエストに設定

次にメソッドリクエストに先ほど作成したオーソライザーを設定します。

デプロイ後、先ほどのcurlを実行すると{"message":"Unauthorized"}になればOKです。

テスト

ではヘッダーを乗せてテストしてみましょう。
トークン内容はAuthorizer用 Lambdaで指定したものを記述してください。

curl -X POST \
https://4wsmtcnjee.execute-api.ap-northeast-1.amazonaws.com/test/ \
-H "Authorization: トークン内容"

Hello from Lambda!が確認できれば成功です。

オプション

Authorizer用 Lambdaに渡されるイベント

下記のようにauthorizationTokenにAuthorizer用 Lambdaに渡されるトークンの内容が入ります。

トークンの検証について

トークンベースオーソライザーの場合はトークンの検証機能を利用することが出来ます。
トークンの検証では正規表現を設定することで、Lambda Authorizer実行前に簡単な入力チェックを行うことが可能です。

先頭がallowでないと401になりますね。

先頭がallowで始まる場合はLambda Authorizerが呼び出され、認可を判断しています。

終わりに

トークンベースのほかにリクエストベースのLambda Authorizerがありますが、複数のヘッダーや複雑な認証をする際は、リクエストベースを検討する必要があるかと思います。
Lambdaに渡ってくるイベント量が多いようです。
(参考:https://dev.classmethod.jp/articles/lambda-authorizer-toke-request/#toc-2

トークンベースでは、シンプルかつAuthorizer用 Lambdaの費用削減にもなるので、まずはこちらを考えてみるのがよさそうです。

モバイルバージョンを終了