

# AWS Lambda オーソライザーを使用して HTTP API へのアクセスを制御する
<a name="http-api-lambda-authorizer"></a>

Lambda オーソライザーを使用し、Lambda 関数を使用して HTTP API へのアクセスを制御します。次に、クライアントが API を呼び出すと、API Gateway が Lambda 関数を呼び出します。API Gateway は、Lambda 関数からのレスポンスを使用して、クライアントが API にアクセスできるかどうかを判断します。

## ペイロード形式バージョン
<a name="http-api-lambda-authorizer.payload-format"></a>

オーソライザーの’ペイロード形式バージョンでは、API Gateway が Lambda 認証に送信するデータの形式と、API Gateway が Lambda からのレスポンスをどのように解釈するかを指定します。ペイロード形式バージョンを指定しない場合、AWS マネジメントコンソール はデフォルトで最新バージョンを使用します。AWS CLI、CloudFormation、または SDK を使用して Lambda オーソライザーを作成する場合は、`authorizerPayloadFormatVersion` を指定する必要があります。サポートされる値は `1.0` と `2.0` です。

 REST APIとの互換性が必要な場合は、バージョン `1.0` を使用してください。

次の例は、各ペイロード形式バージョンの構造を示しています。

------
#### [ 2.0 ]

```
{
  "version": "2.0",
  "type": "REQUEST",
  "routeArn": "arn:aws:execute-api:us-east-1:123456789012:abcdef123/test/GET/request",
  "identitySource": ["user1", "123"],
  "routeKey": "$default",
  "rawPath": "/my/path",
  "rawQueryString": "parameter1=value1&parameter1=value2&parameter2=value",
  "cookies": ["cookie1", "cookie2"],
  "headers": {
    "header1": "value1",
    "header2": "value2"
  },
  "queryStringParameters": {
    "parameter1": "value1,value2",
    "parameter2": "value"
  },
  "requestContext": {
    "accountId": "123456789012",
    "apiId": "api-id",
    "authentication": {
      "clientCert": {
        "clientCertPem": "CERT_CONTENT",
        "subjectDN": "www.example.com",
        "issuerDN": "Example issuer",
        "serialNumber": "1",
        "validity": {
          "notBefore": "May 28 12:30:02 2019 GMT",
          "notAfter": "Aug  5 09:36:04 2021 GMT"
        }
      }
    },
    "domainName": "id.execute-api.us-east-1.amazonaws.com",
    "domainPrefix": "id",
    "http": {
      "method": "POST",
      "path": "/my/path",
      "protocol": "HTTP/1.1",
      "sourceIp": "IP",
      "userAgent": "agent"
    },
    "requestId": "id",
    "routeKey": "$default",
    "stage": "$default",
    "time": "12/Mar/2020:19:03:58 +0000",
    "timeEpoch": 1583348638390
  },
  "pathParameters": { "parameter1": "value1" },
  "stageVariables": { "stageVariable1": "value1", "stageVariable2": "value2" }
}
```

------
#### [ 1.0 ]

```
{
  "version": "1.0",
  "type": "REQUEST",
  "methodArn": "arn:aws:execute-api:us-east-1:123456789012:abcdef123/test/GET/request",
  "identitySource": "user1,123",
  "authorizationToken": "user1,123",
  "resource": "/request",
  "path": "/request",
  "httpMethod": "GET",
  "headers": {
    "X-AMZ-Date": "20170718T062915Z",
    "Accept": "*/*",
    "HeaderAuth1": "headerValue1",
    "CloudFront-Viewer-Country": "US",
    "CloudFront-Forwarded-Proto": "https",
    "CloudFront-Is-Tablet-Viewer": "false",
    "CloudFront-Is-Mobile-Viewer": "false",
    "User-Agent": "..."
  },
  "queryStringParameters": {
    "QueryString1": "queryValue1"
  },
  "pathParameters": {},
  "stageVariables": {
    "StageVar1": "stageValue1"
  },
  "requestContext": {
    "path": "/request",
    "accountId": "123456789012",
    "resourceId": "05c7jb",
    "stage": "test",
    "requestId": "...",
    "identity": {
      "apiKey": "...",
      "sourceIp": "...",
      "clientCert": {
        "clientCertPem": "CERT_CONTENT",
        "subjectDN": "www.example.com",
        "issuerDN": "Example issuer",
        "serialNumber": "a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1",
        "validity": {
          "notBefore": "May 28 12:30:02 2019 GMT",
          "notAfter": "Aug  5 09:36:04 2021 GMT"
        }
      }
    },
    "resourcePath": "/request",
    "httpMethod": "GET",
    "apiId": "abcdef123"
  }
}
```

------

## Lambda オーソライザーのレスポンス形式
<a name="http-api-lambda-authorizer.payload-format-response"></a>

ペイロード形式バージョンによって、Lambda 関数から返す必要のあるレスポンスの構造も決まります。

### Lambda 関数レスポンス形式 1.0
<a name="http-api-lambda-authorizer.v1"></a>

`1.0` 形式バージョンを選択した場合、Lambda オーソライザーは API ルートへのアクセスを許可または拒否する IAM ポリシーを返す必要があります。ポリシーでは、標準の IAM ポリシー構文を使用できます。IAM ポリシーの例については、「[API を呼び出すためのアクセスの制御](api-gateway-control-access-using-iam-policies-to-invoke-api.md)」を参照してください。`$context.authorizer.property` を使用して、コンテキストプロパティを Lambda 統合に渡したり、ログにアクセスしたりできます。`context` オブジェクトはオプションです。`claims` は予約されたプレースホルダーであり、コンテキストオブジェクトとしては使用できません。詳細については[HTTP API アクセスログをカスタマイズする](http-api-logging-variables.md)を参照してください。

**Example**    
****  

```
{
  "principalId": "abcdef", 
  "policyDocument": {
    "Version":"2012-10-17",		 	 	 
    "Statement": [
      {
        "Action": "execute-api:Invoke",
        "Effect": "Allow|Deny",
        "Resource": "arn:aws:execute-api:{regionId}:{accountId}:{apiId}/{stage}/{httpVerb}/[{resource}/[{child-resources}]]"
      }
    ]
  },
  "context": {
    "exampleKey": "exampleValue"
  }
}
```

### Lambda 関数レスポンス形式 2.0
<a name="http-api-lambda-authorizer.v2"></a>

`2.0` 形式バージョンを選択した場合は、Lambda 関数から、ブール値を返すか、標準の IAM ポリシー構文を使用する IAM ポリシーを返すことができます。ブール値を返すには、オーソライザーの簡易レスポンスを有効にします。以下の例では、Lambda 関数から返すようにコーディングする必要のある形式を示しています。`context` オブジェクトはオプションです。`$context.authorizer.property` を使用して、コンテキストプロパティを Lambda 統合に渡したり、ログにアクセスしたりできます。詳細については、「[HTTP API アクセスログをカスタマイズする](http-api-logging-variables.md)」を参照してください。

------
#### [ Simple response ]

```
{
  "isAuthorized": true/false,
  "context": {
    "exampleKey": "exampleValue"
  }
}
```

------
#### [ IAM policy ]

****  

```
{
  "principalId": "abcdef", 
  "policyDocument": {
    "Version":"2012-10-17",		 	 	 
    "Statement": [
      {
        "Action": "execute-api:Invoke",
        "Effect": "Allow|Deny",
        "Resource": "arn:aws:execute-api:{regionId}:{accountId}:{apiId}/{stage}/{httpVerb}/[{resource}/[{child-resources}]]"
      }
    ]
  },
  "context": {
    "exampleKey": "exampleValue"
  }
}
```

------

## Lambda オーソライザー関数の例
<a name="http-api-lambda-authorizer.example-code"></a>

以下のサンプルの Node.js Lambda 関数では、`2.0` ペイロード形式バージョンの場合に Lambda 関数から返す必要のあるレスポンスの形式を示しています。

------
#### [ Simple response - Node.js ]

```
export const handler = async(event) => {
    let response = {
        "isAuthorized": false,
        "context": {
            "stringKey": "value",
            "numberKey": 1,
            "booleanKey": true,
            "arrayKey": ["value1", "value2"],
            "mapKey": {"value1": "value2"}
        }
    };
    
    if (event.headers.authorization === "secretToken") {
        console.log("allowed");
        response = {
            "isAuthorized": true,
            "context": {
                "stringKey": "value",
                "numberKey": 1,
                "booleanKey": true,
                "arrayKey": ["value1", "value2"],
                "mapKey": {"value1": "value2"}
            }
        };
    }

    return response;

};
```

------
#### [ Simple response - Python ]

```
import json


def lambda_handler(event, context):
    response = {
        "isAuthorized": False,
        "context": {
            "stringKey": "value",
            "numberKey": 1,
            "booleanKey": True,
            "arrayKey": ["value1", "value2"],
            "mapKey": {"value1": "value2"}
        }
    }

    try:
        if (event["headers"]["authorization"] == "secretToken"):
            response = {
                "isAuthorized": True,
                "context": {
                    "stringKey": "value",
                    "numberKey": 1,
                    "booleanKey": True,
                    "arrayKey": ["value1", "value2"],
                    "mapKey": {"value1": "value2"}
                }
            }
            print('allowed')
            return response
        else:
            print('denied')
            return response
    except BaseException:
        print('denied')
        return response
```

------
#### [ IAM policy - Node.js ]

```
export const handler = async(event) => {
  if (event.headers.authorization == "secretToken") {
    console.log("allowed");
    return {
      "principalId": "abcdef", // The principal user identification associated with the token sent by the client.
      "policyDocument": {
        "Version": "2012-10-17",		 	 	 
        "Statement": [{
          "Action": "execute-api:Invoke",
          "Effect": "Allow",
          "Resource": event.routeArn
        }]
      },
      "context": {
        "stringKey": "value",
        "numberKey": 1,
        "booleanKey": true,
        "arrayKey": ["value1", "value2"],
        "mapKey": { "value1": "value2" }
      }
    };
  }
  else {
    console.log("denied");
    return {
      "principalId": "abcdef", // The principal user identification associated with the token sent by the client.
      "policyDocument": {
        "Version": "2012-10-17",		 	 	 
        "Statement": [{
          "Action": "execute-api:Invoke",
          "Effect": "Deny",
          "Resource": event.routeArn
        }]
      },
      "context": {
        "stringKey": "value",
        "numberKey": 1,
        "booleanKey": true,
        "arrayKey": ["value1", "value2"],
        "mapKey": { "value1": "value2" }
      }
    };
  }
};
```

------
#### [ IAM policy - Python ]

```
import json


def lambda_handler(event, context):
    response = {
        # The principal user identification associated with the token sent by
        # the client.
        "principalId": "abcdef",
        "policyDocument": {
            "Version": "2012-10-17",		 	 	 
            "Statement": [{
                "Action": "execute-api:Invoke",
                "Effect": "Deny",
                "Resource": event["routeArn"]
            }]
        },
        "context": {
            "stringKey": "value",
            "numberKey": 1,
            "booleanKey": True,
            "arrayKey": ["value1", "value2"],
            "mapKey": {"value1": "value2"}
        }
    }

    try:
        if (event["headers"]["authorization"] == "secretToken"):
            response = {
                # The principal user identification associated with the token
                # sent by the client.
                "principalId": "abcdef",
                "policyDocument": {
                    "Version": "2012-10-17",		 	 	 
                    "Statement": [{
                        "Action": "execute-api:Invoke",
                        "Effect": "Allow",
                        "Resource": event["routeArn"]
                    }]
                },
                "context": {
                    "stringKey": "value",
                    "numberKey": 1,
                    "booleanKey": True,
                    "arrayKey": ["value1", "value2"],
                    "mapKey": {"value1": "value2"}
                }
            }
            print('allowed')
            return response
        else:
            print('denied')
            return response
    except BaseException:
        print('denied')
        return response
```

------

## ID ソース
<a name="http-api-lambda-authorizer.identity-sources"></a>

オプションで、Lambda オーソライザーの ID ソースを指定できます。ID ソースは、リクエストを認可するために必要なデータの場所を指定します。例えば、ヘッダーまたはクエリ文字列の値を ID ソースとして指定できます。ID ソースを指定する場合、クライアントはそれらのソースをリクエストに含める必要があります。クライアントのリクエストに ID ソースが含まれていない場合、API Gateway は Lambda オーソライザーを呼び出さず、クライアントは `401` エラーを受け取ります。

次の表は、Lambda オーソライザーでサポートされている ID ソースを示しています。


| **タイプ** | **例** | **注意事項** | 
| --- | --- | --- | 
| ヘッダー値 | \$1request.header.name | ヘッダー名では大文字と小文字は区別されません。 | 
| クエリ文字列値 | \$1request.querystring.name | クエリ文字列名では大文字と小文字が区別されます。 | 
| コンテキスト変数 | \$1context.variableName | サポートされている[コンテキスト変数](http-api-logging-variables.md)の値。 | 
| ステージ変数 | \$1stageVariables.variableName | [ステージ変数](http-api-stages.stage-variables.md)の値。 | 

Lambda 関数から直接 ` {"errorMessage" : "Unauthorized"}` を返し、クライアントに `401` エラーを返すこともできます。Lambda 関数からクライアントに直接 `401` エラーを返す場合は、Lambda オーソライザーの作成時に ID ソースを指定しないでください。

## オーソライザーのレスポンスのキャッシュ
<a name="http-api-lambda-authorizer.caching"></a>

[authorizerResultTtlInSeconds](https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-authorizers.html#apis-apiid-authorizers-prop-createauthorizerinput-authorizerresultttlinseconds) を指定することで、Lambda オーソライザーのキャッシュを有効にすることができます。オーソライザーのキャッシュが有効になっていると、API Gateway はオーソライザーの ID ソースをキャッシュキーとして使用します。クライアントが設定済みの TTL 内の ID ソースで同じパラメータを指定した場合、API Gateway は、Lambda 関数を呼び出すのではなく、キャッシュされたオーソライザーの結果を使用します。

キャッシュを有効にするには、オーソライザーに 1 つ以上の ID ソースが必要です。

オーソライザーの簡易レスポンスを有効にすると、オーソライザーのレスポンスは、キャッシュされた ID ソース値に一致するすべての API リクエストを完全に許可するか、拒否するかになります。より詳細なアクセス許可が必要な場合は、簡易レスポンスを無効にし、IAM ポリシーが返されるようにします。オーソライザーによっては、IAM ポリシーが複数のアクセスを制御する必要がある場合があります。

デフォルトでは、API Gateway は、オーソライザーを使用する API のすべてのルートに対して、キャッシュされたオーソライザーのレスポンスを使用します。ルートごとにレスポンスをキャッシュするには、オーソライザーの ID ソースに `$context.routeKey` を追加します。

## Lambda オーソライザーの作成
<a name="http-api-lambda-authorizer.example-create"></a>

Lambda オーソライザーを作成するときは、API Gateway で使用する Lambda 関数を指定します。関数のリソースポリシーまたは IAM ロールを使用して Lambda 関数を呼び出すには、API Gateway のアクセス許可を付与する必要があります。次の [create-authorizer](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-authorizer.html) コマンドは、Lambda オーソライザーを作成します。

```
aws apigatewayv2 create-authorizer \
    --api-id abcdef123 \
    --authorizer-type REQUEST \
    --identity-source '$request.header.Authorization' \
    --name lambda-authorizer \ 
    --authorizer-uri 'arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:my-function/invocations' \
    --authorizer-payload-format-version '2.0' \
    --enable-simple-responses
```

次の [add-permission](https://docs.aws.amazon.com/cli/latest/reference/lambda/add-permission.html) コマンドは、API Gateway に Lambda 関数を呼び出すためのアクセス許可を付与するように、その関数のリソースポリシーを更新します。API Gateway に関数を呼び出すアクセス許可がない場合、クライアントは `500 Internal Server Error` を受け取ります。

```
aws lambda add-permission \
    --function-name my-authorizer-function \
    --statement-id apigateway-invoke-permissions-abc123 \ 
    --action lambda:InvokeFunction \
    --principal apigateway.amazonaws.com \
    --source-arn "arn:aws:execute-api:us-west-2:123456789012:api-id/authorizers/authorizer-id"
```

オーソライザーを作成し、呼び出すアクセス許可を API Gateway に付与したら、オーソライザーを使用するようにルートを更新します。次の [update-route](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-route.html) コマンドは、Lambda オーソライザーをルートに追加します。Lambda オーソライザーがポリシーキャッシュを使用している場合は、追加ルートのアクセスを制御するようにポリシーを更新してください。

```
aws apigatewayv2 update-route \
    --api-id abcdef123 \
    --route-id abc123 \
    --authorization-type CUSTOM \
    --authorizer-id def123
```

## Lambda オーソライザーのトラブルシューティング
<a name="http-api-lambda-authorizer.troubleshooting"></a>

API Gateway が Lambda オーソライザーを呼び出せない場合、または Lambda オーソライザーが無効な形式のレスポンスを返す場合、クライアントは `500 Internal Server Error` を受け取ります。

エラーのトラブルシューティングを行うには、API ステージの[アクセスログを有効にします](http-api-logging.md)。ログ形式に `$context.authorizer.error` ログ記録変数を含めます。

API Gateway に関数を呼び出すアクセス許可がないことがログに示されている場合は、関数のリソースポリシーを更新するか、IAM ロールを提供して API Gateway にオーソライザーを呼び出すアクセス許可を付与します。

Lambda 関数が無効なレスポンスを返すことがログに示されている場合は、Lambda 関数が[必要な形式](#http-api-lambda-authorizer.payload-format-response)でレスポンスを返すことを確認してください。