0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

API Gateway REST API の Lambda オーソライザーで発生する主要エラーと解決方法

0
Posted at

概要

API Gateway REST APIでLambdaオーソライザーを実装する際、401 Unauthorized、403 Forbidden、500 Internal Server Errorなどのエラーが発生することがあります。本記事では、これらのエラーの原因と解決方法を、実践的な観点から解説します。CloudWatchログの有効化からキャッシュ設定、IAMポリシーの構成まで、トラブルシューティングに必要な知識を体系的にまとめました。

目次

  1. Lambdaオーソライザーとは
  2. 主要なエラーパターン
  3. 401 Unauthorized エラー
  4. 403 Forbidden エラー
  5. 500 Internal Server Error
  6. CloudWatchログによるデバッグ
  7. ベストプラクティス
  8. 終わりに
  9. 参考文献・参考サイト

Lambdaオーソライザーとは

Lambdaオーソライザー(旧称:カスタムオーソライザー)は、API Gatewayへのアクセスを制御するための仕組みです。クライアントがAPIメソッドを呼び出すと、API Gatewayは指定されたLambda関数を実行し、その応答に基づいてアクセス許可を判断します。

image.png

Lambdaオーソライザーには2つのタイプがあります。

タイプ 説明 使用場面
TOKENベース Authorizationヘッダーなど単一のトークンで認証 JWT、OAuth トークンによる認証
REQUESTベース ヘッダー、クエリ文字列、ステージ変数など複数の要素で認証 より細かい制御が必要な場合

AWSは、複数のIDソースに基づいたアクセス制御が可能なREQUESTオーソライザーの使用を推奨しています。

主要なエラーパターン

API Gateway REST APIでLambdaオーソライザーを使用する際、以下の3つのエラーが最も頻繁に発生します。

エラーコード 主な原因 Lambda関数の呼び出し
401 Unauthorized トークンの欠落、検証式の不一致、IDソースの欠落 されない
403 Forbidden IAMポリシーによる明示的または暗黙的な拒否 される
500 Internal Server Error Lambda呼び出し権限の欠落、レスポンス形式の誤り 試行されるが失敗

401エラーは通常、必須トークンが欠落している場合や、オーソライザーのトークンが検証式に適合しない場合に発生します。

401 Unauthorized エラー

発生するケース

401エラーは、API Gatewayがオーソライザーを呼び出す前の段階で発生します。これは以下の状況で起こります。

TOKENベースオーソライザーの場合

  • 必須のトークンヘッダーが欠落している
  • トークンが検証式(Token Validation)に適合していない

REQUESTベースオーソライザーの場合

  • 設定されたIDソース(Identity Sources)が欠落、null、空文字、または無効

解決方法

ステップ1:オーソライザーの設定を確認

TOKENベースオーソライザーの場合、Token Sourceの値を確認します。例えば、Token SourceがAuthorizationに設定されている場合、リクエストには必ずAuthorizationヘッダーを含める必要があります。

# 正しいリクエスト例(Token Sourceが"Authorization"の場合)
curl -H "Authorization: your-token-value" \
  https://your-api-id.execute-api.ap-northeast-1.amazonaws.com/prod/your-resource

ステップ2:Token Validationを確認

Token Validationに正規表現を設定している場合、API Gatewayはこの式に対してトークンを検証します。例えば、正規表現として「\w{5}」を設定すると、5文字の英数字文字列のトークン値のみが正常に検証されます。

// Token Validation: \w{5}
// 有効なトークン例
Authorization: abcd5

// 無効なトークン例(401エラーになる)
Authorization: abc123  // 6文字のため不一致
Authorization: abc-1   // ハイフンが含まれるため不一致

ステップ3:テストコンソールでの確認

AWS Management Consoleから、オーソライザーをテストできます。

  1. API Gatewayコンソールを開く
  2. APIを選択し、「Authorizers」を選択
  3. テストしたいオーソライザーを選択
  4. 「Test Authorizer」セクションでトークン値を入力してテスト

403 Forbidden エラー

403エラーは、Lambda オーソライザーが呼び出された後、IAMポリシーの評価段階で発生します。これは401エラーと異なり、認証情報自体は正しいものの、アクセスが拒否される状況です。

発生するケース

403 Forbiddenエラーは以下の理由で発生する可能性があります:Lambdaオーソライザー関数が返すIAMポリシードキュメントが呼び出し元へのアクセスを明示的に拒否している、IAMポリシードキュメントが呼び出し元へのアクセスを許可していないか暗黙的に拒否している、APIに添付されたリソースポリシーも呼び出し元へのアクセスを許可していないか暗黙的に拒否している、APIに呼び出し元へのアクセスを明示的に拒否するリソースポリシーが添付されている。

特に注意が必要なのは、キャッシュが有効な場合に発生する間欠的な403エラーです。

キャッシュによる403エラーの典型例

以下のような状況で発生します:

  1. /users/123へのGETリクエストが成功(オーソライザーが呼び出され、IAMポリシーがキャッシュされる)
  2. 同じAuthorizationヘッダーで/orders/456へのPOSTリクエストを実行
  3. キャッシュされたIAMポリシーが適用されるが、リソースパスが一致しないため403エラー

image.png

解決方法

方法1:ワイルドカードリソースを返す(推奨)

この問題を解決するには、Lambdaオーソライザー関数のコードを変更して、代わりに出力にワイルドカード(/)リソースを返すことができます。

// Node.js での実装例
exports.handler = function(event, context, callback) {
    const token = event.authorizationToken;
    const tmp = event.methodArn.split(':');
    const apiGatewayArnTmp = tmp[5].split('/');
    
    // ワイルドカードリソースの作成
    const resource = tmp[0] + ":" + tmp[1] + ":" + tmp[2] + ":" + 
                    tmp[3] + ":" + tmp[4] + ":" + 
                    apiGatewayArnTmp[0] + '/*/*';
    
    // トークン検証ロジック
    if (isValidToken(token)) {
        callback(null, generatePolicy('user', 'Allow', resource));
    } else {
        callback(null, generatePolicy('user', 'Deny', resource));
    }
};

function generatePolicy(principalId, effect, resource) {
    return {
        principalId: principalId,
        policyDocument: {
            Version: '2012-10-17',
            Statement: [{
                Action: 'execute-api:Invoke',
                Effect: effect,
                Resource: resource
            }]
        }
    };
}
# Python での実装例
def lambda_handler(event, context):
    token = event['authorizationToken']
    method_arn = event['methodArn']
    
    # ワイルドカードリソースの作成
    tmp = method_arn.split(':')
    api_gateway_arn_tmp = tmp[5].split('/')
    resource = f"{':'.join(tmp[:5])}:{api_gateway_arn_tmp[0]}/*/*"
    
    # トークン検証ロジック
    if is_valid_token(token):
        return generate_policy('user', 'Allow', resource)
    else:
        return generate_policy('user', 'Deny', resource)

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
                }
            ]
        }
    }

方法2:キャッシュを無効化する

開発・テスト環境では、キャッシュを無効化することで問題を回避できます。

AWS CLIでの実装:

# キャッシュの一時的なフラッシュ
aws apigateway flush-stage-authorizers-cache \
  --rest-api-id your-api-id \
  --stage-name prod \
  --region ap-northeast-1

方法3:キャッシュキーを変更する

TOKENベースオーソライザーの場合は「Token Source」、REQUESTベースオーソライザーの場合は「Identity Sources」を変更することで、キャッシュがクリアされます。変更後は必ずAPIを再デプロイしてください。

CloudWatchログでの確認方法

API Gatewayのレスポンスで、エラーログメッセージを確認します。ログには以下のような情報が含まれます:

Starting authorizer: vf0zk6 for request: f23990ba-c1a4-4c71-9427-d28697735735
Using valid authorizer policy for principal: ************************f8069d
Successfully completed authorizer execution
The client is not authorized to perform this operation.
Gateway response type: ACCESS_DENIED with status code: 403

このログから、オーソライザー自体は正常に実行されているが、ポリシー評価でアクセスが拒否されたことがわかります。

500 Internal Server Error

500エラーは、API GatewayがLambdaオーソライザーを呼び出せない場合、またはLambda関数が無効な形式のレスポンスを返した場合に発生します。

発生するケース

  1. Lambda呼び出し権限の欠落
    API Gateway HTTP APIがLambda呼び出し権限なしでLambda関数を呼び出そうとすると、API Gatewayは「Internal Server Error」メッセージを返します。

  2. レスポンス形式の誤り
    Lambda オーソライザーが規定の形式でレスポンスを返さない場合

解決方法

ステップ1:Lambda呼び出し権限を追加

AWS CLIでの設定:

aws lambda add-permission \
  --function-name your-authorizer-function \
  --source-arn "arn:aws:execute-api:ap-northeast-1:123456789012:api-id/authorizers/authorizer-id" \
  --principal apigateway.amazonaws.com \
  --statement-id apigateway-invoke-authorizer \
  --action lambda:InvokeFunction \
  --region ap-northeast-1

CloudFormationでの設定:

AuthorizerPermission:
  Type: AWS::Lambda::Permission
  Properties:
    Action: lambda:InvokeFunction
    FunctionName: !Ref AuthorizerFunction
    Principal: apigateway.amazonaws.com
    SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiGatewayApi}/authorizers/${Authorizer}"

ステップ2:レスポンス形式の確認

TOKENベースオーソライザーの正しいレスポンス形式:

{
  "principalId": "user-identifier",
  "policyDocument": {
    "Version": "2012-10-17",
    "Statement": [
      {
        "Action": "execute-api:Invoke",
        "Effect": "Allow",
        "Resource": "arn:aws:execute-api:ap-northeast-1:123456789012:api-id/*/*/*"
      }
    ]
  },
  "context": {
    "stringKey": "value",
    "numberKey": 123,
    "booleanKey": true
  }
}

REQUESTベースオーソライザーも同様の形式ですが、usageIdentifierKeyを追加できます。

ステップ3:CloudWatchログの有効化

エラーをトラブルシューティングするには、APIステージのアクセスログを有効にします。ログ形式に$context.authorizer.error ログ変数を含めます。

# CloudWatchロググループの作成
aws logs create-log-group \
  --log-group-name /aws/apigateway/your-api-name \
  --region ap-northeast-1

# API Gatewayステージのログ設定
aws apigateway update-stage \
  --rest-api-id your-api-id \
  --stage-name prod \
  --patch-operations \
    op=replace,path=/accessLogSettings/destinationArn,value=arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/apigateway/your-api-name \
    op=replace,path=/accessLogSettings/format,value='$context.requestId $context.authorizer.error' \
  --region ap-northeast-1

CloudWatchログによるデバッグ

効果的なトラブルシューティングには、CloudWatchログの有効化が不可欠です。

ログの有効化手順

  1. IAMロールの作成

API Gatewayに CloudWatch Logsへの書き込み権限を付与します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:DescribeLogGroups",
        "logs:DescribeLogStreams",
        "logs:PutLogEvents",
        "logs:GetLogEvents",
        "logs:FilterLogEvents"
      ],
      "Resource": "*"
    }
  ]
}
  1. API Gatewayの設定

AWS Management Consoleから:

  • API Gatewayコンソールを開く
  • 対象のAPIを選択
  • 「Settings」を選択
  • 「CloudWatch log role ARN」に作成したIAMロールのARNを設定
  1. ステージのログ設定
  • 対象のステージを選択
  • 「Logs/Tracing」タブを選択
  • 「CloudWatch Settings」で「Enable CloudWatch Logs」をチェック
  • Log levelを「INFO」に設定(すべてのリクエストの実行ログを生成)

ログの確認と分析

CloudWatchロググループ名はAPI-Gateway-Execution-Logs_<api-id>/<stage-name>の形式になります。

重要なログエントリ:

# オーソライザー開始
Starting authorizer: <authorizer-id> for request: <request-id>

# 入力IDの受信
Incoming identity: ************

# オーソライザー実行完了
Successfully completed authorizer execution

# エラーの場合
Execution failed due to configuration error: Invalid permissions on Lambda function

ベストプラクティス

1. REQUESTベースオーソライザーを優先

複数のIDソースに基づいた制御が可能で、よりきめ細かいキャッシュキー設定ができます。

2. ワイルドカードリソースの使用

キャッシュを有効にする場合は、必ずワイルドカード(/)リソースを返すようにします。これにより、すべてのメソッドとリソースパスに適用可能なポリシーが生成されます。

3. 適切なキャッシュTTLの設定

セキュリティと性能のバランスを考慮してTTL(Time To Live)を設定します。

用途 推奨TTL 理由
開発環境 0秒(無効) デバッグを容易にする
本番環境(高セキュリティ) 300秒(5分) セキュリティを優先
本番環境(高パフォーマンス) 3600秒(1時間) コスト削減と性能向上

4. CloudWatchアラームの設定

オーソライザーの異常を早期に検知するため、以下のメトリクスにアラームを設定します:

# Lambda関数のエラー率アラーム
aws cloudwatch put-metric-alarm \
  --alarm-name authorizer-error-rate \
  --alarm-description "Alert when authorizer error rate exceeds 5%" \
  --metric-name Errors \
  --namespace AWS/Lambda \
  --statistic Average \
  --period 300 \
  --evaluation-periods 2 \
  --threshold 0.05 \
  --comparison-operator GreaterThanThreshold \
  --dimensions Name=FunctionName,Value=your-authorizer-function \
  --region ap-northeast-1

5. テスト戦略

本番環境にデプロイする前に、以下のテストシナリオを実施します:

  • トークン欠落時の動作確認(401エラー)
  • 無効なトークンでの動作確認(403エラー)
  • 有効なトークンで異なるリソースへのアクセス(キャッシュ動作確認)
  • Lambda関数のタイムアウト(30秒以内に設定)
  • 同時実行数の上限確認

6. セキュリティ考慮事項

  • トークン検証は必ずLambda関数内で実施する
  • Token Validationの正規表現は、必要最小限の制約とする
  • シークレットキーはAWS Secrets Managerに保存する
  • CloudWatchログには機密情報を出力しない

料金について

API Gateway REST APIとLambdaオーソライザーの使用には、以下の料金が発生します(2025年10月時点、ap-northeast-1リージョン)。

Amazon API Gatewayでは、APIが使用されている場合にのみ支払います。HTTP APIとREST APIの場合、受信したAPI呼び出しと転送されたデータ量に対してのみ支払います。

サービス 料金 備考
REST API 最初の3億リクエスト:$3.50/100万リクエスト
Lambda実行 100万リクエスト:$0.20
GB秒あたり:$0.0000166667
オーソライザー関数の実行に対して
CloudWatch Logs 取り込み:$0.76/GB
保存:$0.033/GB/月
ログ量により変動
データ転送 インターネットへの転送:$0.114/GB 最初の10TBまで

無料利用枠(新規AWSアカウント作成後12か月間):

  • REST API:月間100万リクエスト
  • Lambda:月間100万リクエスト、400,000 GB秒のコンピューティング時間

料金は変動する可能性があるため、最新情報は以下の公式料金ページでご確認ください:

コスト最適化のヒント

  1. キャッシュの活用:適切なTTLを設定することで、Lambda呼び出し回数を削減
  2. Lambda関数の最適化:メモリ割り当てを適切に設定し、実行時間を短縮
  3. 不要なログの削減:本番環境ではERRORレベルのみをログ出力

終わりに

API Gateway REST APIでLambdaオーソライザーを使用する際のエラーは、原因を理解すれば適切に対処できます。本記事で紹介した以下のポイントを押さえることで、安定したAPI認証基盤を構築できます。

  • 401エラー:トークンやIDソースの欠落が原因。オーソライザー設定とリクエスト形式を確認
  • 403エラー:IAMポリシーまたはキャッシュが原因。ワイルドカードリソースの使用を検討
  • 500エラー:Lambda呼び出し権限またはレスポンス形式が原因。権限設定とレスポンス形式を確認
  • CloudWatchログ:効果的なデバッグのために必ず有効化

次のステップとして、以下の実装を検討してください。

  1. JWTトークンを使用した本格的な認証システムの構築
  2. Amazon Cognito User Poolsとの統合
  3. API Gateway HTTP APIへの移行検討(コスト削減のため)
  4. マルチリージョン構成での高可用性の実現

AWS公式ドキュメントやコミュニティのベストプラクティスを参考にしながら、セキュアで効率的なAPI基盤を構築していきましょう。

参考文献・参考サイト

AWS公式ドキュメント

AWS Knowledge Center / re:Post

技術ブログ・記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?