Amazon API Gateway の Lambda オーソライザーで "User is not authorized to access this resource" と出たら - kakakakakku blog

kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Amazon API Gateway の Lambda オーソライザーで "User is not authorized to access this resource" と出たら

Amazon API Gateway の Lambda オーソライザー(旧カスタムオーソライザー)を使ってアクセス制御をするときに,Authorization ヘッダーは正しいはずなのに {"Message":"User is not authorized to access this resource"} というエラーが出てしまう場合,Lambda オーソライザーの設定「認可のキャッシュ (Authorization caching)」に関係してる場合がある💡

前提

今回はサンプルとして Amazon API Gateway に /users リソースを追加して POSTGET をサポートする.そしてどちらにも Lambda オーソライザー(トークンタイプ)によるアクセス制御を設定しておく👌

/users (POST)
/users (GET)

そして,Lambda オーソライザーの実装はドキュメントに載っている Python のサンプルコードをそのまま使う📝実装としては簡易的で Authorization ヘッダーに allow と設定すれば OK という仕組みになっている.

docs.aws.amazon.com

ポイントはこの Lambda オーソライザーの実装では以下のようなポリシーが生成されるところ💡(POST の場合)

Allow

{
    "principalId": "user",
    "policyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": "execute-api:Invoke",
                "Effect": "Allow",
                "Resource": "arn:aws:execute-api:ap-northeast-1:111111111111:xxxxxxxxxx/Prod/POST/users"
            }
        ]
    },
    "context": {
        "stringKey": "stringval",
        "numberKey": 123,
        "booleanKey": true
    }
}

Deny

{
    "principalId": "user",
    "policyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": "execute-api:Invoke",
                "Effect": "Deny",
                "Resource": "arn:aws:execute-api:ap-northeast-1:111111111111:xxxxxxxxxx/Prod/POST/users"
            }
        ]
    },
    "context": {
        "stringKey": "stringval",
        "numberKey": 123,
        "booleanKey": true
    }
}

動作確認

Amazon API Gateway の /users リソースに POST リクエストを送信した後すぐに GET リクエストを送信する.すると {"Message":"User is not authorized to access this resource"} というエラーが返ってくる🔥キャッシュの仕組みを理解してないと「なぜー?」となってしまう.キャッシュの TTL はデフォルトで「300秒」に設定されている👀

$ curl -X POST -H 'Authorization: allow' ${ENDPOINT}/users
$ curl -X GET -H 'Authorization: allow' ${ENDPOINT}/users
{"Message":"User is not authorized to access this resource"}

対策

選択肢は大きく2つあると思う👌

選択肢1

Lambda オーソライザーで生成するポリシーの条件を緩和する選択肢がある.AWS re:Post の記事にも Resource/*/* にすれば OK という解決策が紹介されている💡もちろんワイルドカードで許可できない場合もあると思うし,最小権限の原則を考慮すると闇雲にワイルドカードっていう判断が危険なこともあると思う.

repost.aws

ちなみに前に紹介記事を書いた Powertools for AWS Lambda (Python)Event Source Data ClassesAPIGatewayAuthorizerResponse を使ってポリシーを生成する場合,allow_all_routes() を使うと以下のようにワイルドカードでポリシーが生成される.allow_route() を使うと HTTP メソッド・リソースを細かく指定できる.

{
    "principalId": "user",
    "policyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": "execute-api:Invoke",
                "Effect": "Allow",
                "Resource": "arn:aws:execute-api:ap-northeast-1:111111111111:xxxxxxxxxx/Prod/*/*"
            }
        ]
    }
}

kakakakakku.hatenablog.com

選択肢2

次にキャッシュの TTL を短くする(もしくはキャッシュを無効化する)選択肢がある.キャッシュによる影響はなくなるけど,毎回 Lambda オーソライザーを呼び出すことになるため,パフォーマンスなどの観点で検討が必要になる.

デフォルトで 300 秒、API 所有者が 0~3600 の範囲で設定可能。

docs.aws.amazon.com