上記のようなAPIGatewayで構築したAPIにLambdaオーソライザーを適用した際に、正しい認証情報、正しいAWSリソースへのアクセス権限を設定しているにも関わらず「User is not authorized to access this resource」エラーが発生することがあります。
本記事ではその原因と対応を記載します。
原因
Lambdaオーソライザーから返却される認可情報のキャッシングが原因です。
以下のようなアクセスポリシーを返却するコードを記述した際に発生します。
...
statementOne.Action = 'execute-api:Invoke';
statementOne.Effect = 'Allow';
// ↓ 以下のアクセス承認するリソースを指定するコードが原因
statementOne.Resource = event.methodArn;
...
ポイントはevent.methodArn
です。
ここでは呼び出しされたAPIのみのArnが含まれています。
例: arn:aws:execute-api:ap-northeast-1:xxxxxxxxxxx:xxxxxxxxx/stg/GET/users/43/info
このArnへのアクセス権限を許可したポリシーを返却すると、初回のアクセスはうまくいきます。
しかし同じLambdaオーソライザーが適用されている他のAPIを呼び出した際に、上記のArnが含まれたポリシーがキャッシュとして返却されてしまい、初回アクセスとは別の認可されていないリソースにアクセスすると「User is not authorized to access this resource」エラーが発生します。
対応
2パターンの対応方法があります。
パターン1Lambdaオーソライザーの認可のキャッシュのTTL値を0に設定
API Gatewayのオーソライザーから対象のオーソライザーを選択して、
TTLを0に変更すると、毎回認証を実行するためevent.methodArn
をアクセス承認リソースとして返却しても、問題なく認可が通ります。
ただ毎回認証処理が走るため、パフォーマンス的には優れません。
その点が気になる場合は、後述のパターン2を利用することを推奨します。
※ AWS CloudFormation, AWS SAMを利用する場合の注意点
CloudFormation、SAMを利用してLambdaオーソライザーを設定した場合、デフォルトでは認可のキャッシュのTTL値は300秒です。
認可キャッシュのTTL値を変更せずにデプロイしたオーソライザーの設定値をマネジメントコンソールから確認すると...
こんな感じでundefined
となっており、キャッシュが無効になっているように見えます。
しかし実際には300秒のキャッシュ設定が有効になっています。
(これに1時間くらいハメられました...)
TTLを0に設定する際には、ReauthorizeEvery
を0に設定しましょう。
TestApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prd
Auth:
AddDefaultAuthorizerToCorsPreflight: false
DefaultAuthorizer: MyLambdaCustomAuthorizer
Authorizers:
MyLambdaCustomAuthorizer:
FunctionPayloadType: REQUEST
FunctionArn:
Fn::GetAtt:
- RestApiAuthFunction
- Arn
Identity:
QueryStrings:
- authToken
ReauthorizeEvery: 0
パターン2 Lambdaオーソライザー側で返却するリソースポリシーを変更
Lambdaオーソライザー側でevent.methodArn
を指定するのではなく、ワイルドカードを指定して対応する方法です。
...
statementOne.Action = 'execute-api:Invoke';
statementOne.Effect = 'Allow';
// ↓ ワイルドカード指定に変更
statementOne.Resource = 'arn:aws:execute-api:*';
...
上記例では、全Lambdaの実行権限を返却しています。
こうすることでポリシーのキャッシュが行われていても、ワイルドカードで許可されたリソースは問題なくコールすることが可能です。
どこまでをワイルドカード指定にするかは、自身のセキュリティポリシーと相談してみてください。
キャッシュと併用することができるため、パターン1よりもパフォーマンス的に優れていますが、ワイルドカード指定になる分、セキュリティとトレードオフです。
まとめ
- 1つのオーソライザーを複数のリソースで共有した際に、オーソライザーの認可キャッシュが有効になっていると「User is not authorized to access this resource」が発生する。
- オーソライザーの認可情報のキャッシュが原因であるため、TTLを0にするか認可リソースを拡大することで対応可能
記載情報に誤りがあったらご指摘いただけると助かります。
参考リンク
- AWS公式 : API Gateway コンソールを使用して Lambda オーソライザーを設定する
- [stackoverflow : AWS API Gateway custom Authorizer strange showing error]
(https://stackoverflow.com/questions/50331588/aws-api-gateway-custom-authorizer-strange-showing-error)