API Gateway での REST API へのアクセスの制御と管理

2023/01/05に公開

概要

AWS LambdaにアクセスするAPI Gatewayのエンドポイントを叩く際に、セキュアな認証をかける方法のうちAuthorizerを使用した認証方法をメモしておきたいと思います。

目次

  • 構成
  • 認証ワークフロー
  • オーソライザーの設定
  • まとめ
  • 参考

構成

aws-auth

認証ワークフロー


Lambda オーソライザーには、2種類存在します。

1.トークンベースの認証方法を検証します。 の Lambda オーソライザー (TOKEN オーソライザーとも呼ばれる) は、JSON ウェブトークン (JWT) や OAuth トークンなどのベアラートークンで発信者 ID を受け取ります。
2.リクエストパラメータベースの Lambda オーソライザー (REQUEST オーソライザーとも呼ばれます) は、ヘッダー、クエリ文字列パラメータ、stageVariables、および $context 変数の組み合わせで発信者 ID を受け取ります。

この記事では、トークンベースの認証方法を検証します。

オーソライザーの作成


1.任意の関数とエンドポイントを作成

まず認証検証用に、テスト関数を作成します。上記構成図で、最後にアクセスを受けるFunctionです。

exports.handler = async (event) => {
    const response = {
      statusCode: 200,
      body: JSON.stringify('I am called by authorized clients'),
    };
    return response;
};

関数を作成後、API Gatewayトリガーを設定しAPIを作成し、このエンドポイントへのGETリクエストに認証用のパラメータを含めます。

  • API
    api-gateway/{api-id}///demoAPI

  • Endpoint

https://{api-id}.execute-api.{region}.amazonaws.com/default/demo

  • API名

demoAPI

2.オーソライザー関数の作成

exports.handler =  function(event, context, callback) {
    //リクエストヘッダーに含まれる認証トークンを取得。
    //このトークンはAPIが発行する。
    var token = event.authorizationToken;
    // ヘッダーリクエストに含まれるauthorizationTokenがAllowなら、IAMポリシーの生成
    switch (token) {
        case 'allow':
            callback(null, generatePolicy('user', 'Allow', event.methodArn));
            break;
        case 'deny':
            callback(null, generatePolicy('user', 'Deny', event.methodArn));
            break;
        case 'unauthorized':
            callback("Unauthorized");   // Return a 401 Unauthorized response
            break;
        default:
            callback("Error: Invalid token"); // Return a 500 Invalid token response
    }
};

// Help function to generate an IAM policy
var generatePolicy = function(principalId, effect, resource) {
    var authResponse = {};

    authResponse.principalId = principalId;
    if (effect && resource) {
        var policyDocument = {};
        policyDocument.Version = '2012-10-17'; 
        policyDocument.Statement = [];
        var statementOne = {};
        statementOne.Action = 'execute-api:Invoke'; 
        statementOne.Effect = effect;
        statementOne.Resource = resource;
        policyDocument.Statement[0] = statementOne;
        authResponse.policyDocument = policyDocument;
    }

    // Optional output with custom properties of the String, Number or Boolean type.
    authResponse.context = {
        "stringKey": "stringval",
        "numberKey": 123,
        "booleanKey": true
    };
    return authResponse;
}

3.APIにオーソライザーを追加

1.で作成したAPIにオーソライザーを追加します。

スクリーンショット 2021-09-15 13.08.47

2.[タイプ] で [Lambda] を選択します。
スクリーンショット 2021-09-15 13.08.59

3.[Lambda 関数] で、Lambda オーソライザー関数を作成したリージョンを選択し、ドロップダウンリストで関数名を選択します。
スクリーンショット 2021-09-15 13.11.01
4.[Lambda 呼び出しロール] は空白のままにします。

5.[Lambda イベントペイロード] の場合は、[トークン] を選択します。

6.[Token Source (トークンのソース)] に「authorizationToken」と入力します。

7.[Create (作成)] を選択し、[Grant & Create (付与 & 作成)] を選択します

4.動作確認

  • トークンがallowの場合
$ curl -H "authorizationToken: allow" https://{api-id}.execute-api.{region}.amazonaws.com/demo
// response
"I am called by authorized clients"
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "execute-api:Invoke",
      "Effect": "Allow",
      "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/"
    }
  ]
}
  • トークンがdenyの場合
$ curl -H "authorizationToken: deny" https://{api-id}.execute-api.{region}.amazonaws.com/demo
// response
{"Message":"User is not authorized to access this resource with an explicit deny"}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "execute-api:Invoke",
      "Effect": "Deny",
      "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/"
    }
  ]
}

まとめ

AWSのIAMポリシーは、適切に使用しないとセキュリティ面で危ないです。Lambda関数へのアクセスには、オーソライザーを使用してセキュアな認証を常に設定するようにしたいです。

参考

AWS official
API Gateway Lambdaオーソライザーでアクセス制御する

Discussion