はじめに
今回は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.認可ロジックを柔軟に実装できる
- ヘッダー、クエリ、IPアドレス、JWT など任意の情報を使って認可処理ができる(リクエストベース)
- ロールベース・属性ベースなど細かな制御にも対応可能(リクエストベース)
2.外部サービスや社内システムと連携できる
- Auth0、Firebase、社内ID基盤などと組み合わせて使える
- Cognitoに依存しないため、既存の認証基盤との統合がしやすい
- 個別の利用制御ができる
- API キーごとに 使用量プラン(Usage Plan) を設定し、アクセス回数制限(レート、クォータ)を行える。
- APIキー単位でアクセス制御や分析が可能(誰がどれだけ使ったか把握できる)。
3.ポリシーキャッシュが使える
- 認可結果を最大1時間キャッシュできる
- 同一トークンの連続アクセス時にパフォーマンスを向上できる
4.複数API Gatewayで再利用できる
- 共通のLambda Authorizerを複数APIに適用可能
- コードの一元管理がしやすくなる
デメリット
1.レイテンシが増加する
- Lambda起動による遅延が発生する
- 高レスポンス性能が求められるAPIでは注意が必要
2.リクエスト数に応じてコストが増える
- APIリクエストごとにLambdaが実行される
- 大量アクセス時は費用がかさむ可能性がある
3.実装と運用が複雑
- IAMポリシーの組み立てやトークン検証などの責任が開発者側にある
- セキュリティの考慮点が多く、ミスが起きやすい
4.エラー原因の特定が難しい
- 失敗時は "Unauthorized" のみ返される
- 詳細確認には CloudWatch ログの確認が必須
使いどころ
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 Manager
やSSM 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の費用削減にもなるので、まずはこちらを考えてみるのがよさそうです。