以下の内容はhttps://timtoronto634.hatenablog.com/entry/2024/08/12/174430より取得しました。


API Gateway V2 の Lambda Authorizer でとりあえずの自分用認可を実装

前回に引き続き、手探りで API Gateway を設定している.

今回は認証を追加する。といっても実装中の Lambda が外部から好き勝手に叩かれなければそれでいいので、決め打ちの key の値があるかどうか、くらいの設定をする。

API GatewayAPI Key を利用しようと思ったが、 API Key は API Gateway v1 (REST API) で利用できる機能で、今使っている v2 では適用できなかった。

v2 の HTTP Request では Authorization の実現に 2 つの選択肢がある。 JWT と lambda だ。

JWT を選べば、必要な parameter を入れておくだけで、OIDC に準拠した IdP Provider と勝手に連携してくれると思われる(推測。実装はしていない)。

今回は IdP や Cognito を使うほどではないので、lambda で簡単に済ませたい。

terraform 実装

シンプルな lambda 関数を定義

exports.handler = async (event) => {
    const apiKey = event.headers['x-api-key'];

    // APIキーの検証
    if (apiKey !== API_KEY) {
        return {
            isAuthorized: true,
            context: {
                user: 'authorized'
            }
        };
    } else {
        return {
            isAuthorized: false
        };
    }
};

見ての通り、決め打ちの値が header に含まれているか、で判定を行っている。自分用の開発であれば、これで十分だろう。

lambda 関数のリソースを作成

resource "aws_lambda_function" "api_authorizer" {
  architectures    = ["x86_64"]
  description      = "API Authorizer"
  filename         = data.archive_file.authorizer.output_path
  function_name    = "ApiAuthorizer"
  role             = aws_iam_role.lambda_role.arn
  handler          = "authorizer.handler"
  runtime          = "nodejs20.x"
  source_code_hash = data.archive_file.authorizer.output_base64sha256
}

data "archive_file" "authorizer" {
  type        = "zip"
  source_dir  = "functions/authorizer"
  output_path = "functions/authorizer.zip"
}

authorizer resource を定義

resource "aws_apigatewayv2_authorizer" "temporal_authorizer" {
  api_id                            = aws_apigatewayv2_api.lambda.id
  authorizer_type                   = "REQUEST"
  authorizer_uri                    = aws_lambda_function.api_authorizer.invoke_arn
  identity_sources                  = ["$request.header.Authorization"]
  name                              = "temporal-authorizer"
  authorizer_payload_format_version = "2.0"
  enable_simple_responses           = true # isAuthorized: true 形式のレスポンスを利用
}

enable_simple_responses がポイント。false の場合は、IAM 形式の response を返す必要がある

route を update して、lambda authorizer を使うように指定

resource "aws_apigatewayv2_route" "hello_world" {
  api_id             = aws_apigatewayv2_api.lambda.id
  authorization_type = "CUSTOM"
  authorizer_id      = aws_apigatewayv2_authorizer.temporal_authorizer.id
  ...
}

動かしてみる

authorization header をつける

デプロイした後、該当の endpoint に curl request すると、Unauthorized が帰ってきてしまった。

% curl "$(terraform output -raw base_url)/hello?Name=Terraform" -H "x-api-key: API_KEY"
{"message":"Unauthorized"}%                      

色々調査したり試行錯誤した結果、 authorization header をつけてあげる必要があった。

 -H "authorization: abc"

aws_apigatewayv2_authorizer で定義した↓の部分が、request にそもそも含まれていないということで、 Unauthorized になってしまっていた。

  identity_sources                  = ["$request.header.Authorization"]

cache が効いてるかも

curl request すると、意図した通りに本来の結果が返された。認可処理を無事通過できたことがわかる。

% curl "$(terraform output -raw base_url)/hello?Name=Terraform" -H "x-api-key: XXX" -H "authorization: abc" 
{"message":"Hello, Terraform!"}%                  

ここで、 API_KEY を誤った値に変えたらどうなるかを試してみた

% curl "$(terraform output -raw base_url)/hello?Name=Terraform" -H "x-api-key: WRONG" -H "authorization: abc" 
{"message":"Hello, Terraform!"}%          

すると、認可された時と同じ response が帰ってきた。

疑問に思って調べると、以下の記述を見つけた。

For HTTP APIs, identity sources are also used as the cache key when caching is enabled.

https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-authorizers-authorizerid.html

identity_sources の値(ここでは、 authorization header の値)がキャッシュのkeyに使われているとのことだった。

ということで、キャッシュが効かない別の値でリクエストすると、以下のように意図した通り Forbidden が帰ってきた

% curl "$(terraform output -raw base_url)/hello?Name=Terraform" -H "x-api-key: WRONG" -H "authorization: different" 
{"message":"Forbidden"}%                         

終わりに

これで最低限の認可がある状態でデプロイされた環境で開発を進められるようになった




以上の内容はhttps://timtoronto634.hatenablog.com/entry/2024/08/12/174430より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14