API Gateway Lambda オーソライザーを使用する
Lambda オーソライザー (以前はカスタムオーソライザーと呼ばれていました) は、API へのアクセスを制御するために使用します。クライアントが API の メソッドをリクエストすると、API Gateway は Lambda オーソライザーを呼び出します。Lambda オーソライザーは、発信者の ID を入力として受け取り、IAM ポリシーを出力として返します。
Lambda オーソライザーを使用して、カスタム認証スキームを実装します。スキームでは、リクエストパラメータを使用して、発信者のアイデンティティを判断したり、OAuth や SAML などのベアラートークン認証戦略を使用したりできます。Lambda オーソライザーは、API Gateway REST API コンソール、AWS CLI、または AWS SDK を使用して作成します。
Lambda オーソライザーの認証ワークフロー
次の図は、Lambda オーソライザーの認証ワークフローを示しています。
API Gateway Lambda 認証ワークフロー
-
クライアントは、API Gateway API でメソッドを呼び出し、ベアラートークンまたはリクエストパラメータを渡します。
-
API Gateway は、メソッドリクエストが Lambda オーソライザーで設定されているかどうかを確認します。存在する場合、API Gateway は Lambda 関数を呼び出します。
-
Lambda 関数は発信者を認証します。関数は次の方法で認証できます。
-
OAuth プロバイダーを呼び出して OAuth アクセストークンを取得します。
-
SAML プロバイダーを呼び出して SAML アサーションを取得します。
-
リクエストパラメータ値に基づいて IAM ポリシーを生成します。
-
データベースから認証情報を取得します。
-
Lambda 関数は、IAM ポリシーとプリンシパル識別子を返します。Lambda 関数がこの情報を返さない場合、呼び出しは失敗します。
-
API Gateway は IAM ポリシーを評価します。
-
アクセスが拒否された場合、API Gateway は 403
ACCESS_DENIED
などの適切な HTTP ステータスコードを返します。
-
アクセスが許可されている場合、API Gateway はメソッドを呼び出します。
認可のキャッシュを有効にすると、API Gateway でポリシーがキャッシュされるため、Lambda オーソライザー関数は再度呼び出されません。
403
ACCESS_DENIED
または 401 UNAUTHORIZED
ゲートウェイレスポンスはカスタマイズできます。詳細については、「API Gateway での REST API のゲートウェイレスポンス」を参照してください。
Lambda オーソライザーのタイプの選択
Lambda オーソライザーには 2 種類あります。
- リクエストパラメータベースの Lambda オーソライザー (
REQUEST
オーソライザー)
-
REQUEST
オーソライザーは、発信者 ID をヘッダー、クエリ文字列パラメータ、stageVariables、$context 変数の組み合わせとして受け取ります。REQUEST
オーソライザーを使用して、$context.path
や $context.httpMethod
コンテキスト変数など、複数の ID ソースからの情報に基づいてきめ細かなポリシーを作成できます。
REQUEST
オーソライザーの認可のキャッシュを有効にすると、API Gateway は、指定されたすべての ID ソースがリクエスト内に存在することを確認します。指定された ID ソースが欠落しているか、null または空である場合、API Gateway は、Lambda オーソライザー関数を呼び出すことなく 401 Unauthorized
HTTP レスポンスを返します。複数の ID ソースが定義されている場合は、すべての ID ソースがオーソライザーのキャッシュキーを取得するために使用されます (順序は保持されます)。複数の ID ソースを使用して、きめ細かなキャッシュキーを定義できます。
キャッシュキーのいずれかの部分を変更して API を再デプロイすると、オーソライザーは、キャッシュされたポリシードキュメントを破棄して新しいドキュメントを作成します。
REQUEST
オーソライザーの認可のキャッシュを無効にすると、API Gateway はリクエストを Lambda 関数に直接渡します。
- トークンベースの Lambda オーソライザー (
TOKEN
オーソライザー)
-
TOKEN
オーソライザーは、JSON ウェブトークン (JWT) や OAuth トークンなどのベアラートークンで発信者 ID を受け取ります。
TOKEN
オーソライザーの認可のキャッシュを有効にすると、トークンソースに指定されているヘッダー名がキャッシュキーになります。
さらに、トークン検証を使用して RegEx ステートメントを入力できます。API Gateway は、この式に対して入力トークンの初期検証を実行し、検証が成功すると Lambda オーソライザー関数を呼び出します。これにより API への呼び出しを減らすことができます。
IdentityValidationExpression
プロパティは TOKEN
オーソライザーでのみサポートされています。詳細については、「x-amazon-apigateway-authorizer オブジェクト」を参照してください。
REQUEST
オーソライザーを使用して API へのアクセスを制御することをお勧めします。REQUEST
オーソライザーを使用すると、(TOKEN
オーソライザーを使用した場合の単一の ID ソースと比べて) 複数の ID ソースに基づく API へのアクセスを制御できます。さらに、REQUEST
オーソライザーでは複数の ID ソースを使用してキャッシュキーを分離できます。
REQUEST
オーソライザー Lambda 関数の例
次のコード例で作成する Lambda オーソライザー関数では、クライアントが提供した HeaderAuth1
ヘッダー、QueryString1
クエリパラメータ、ステージ変数 StageVar1
のすべてが、それぞれ headerValue1
、queryValue1
、stageValue1
の指定された値と一致する場合に、リクエストを許可します。
- Node.js
// A simple request-based authorizer example to demonstrate how to use request
// parameters to allow or deny a request. In this example, a request is
// authorized if the client-supplied HeaderAuth1 header, QueryString1
// query parameter, and stage variable of StageVar1 all match
// specified values of 'headerValue1', 'queryValue1', and 'stageValue1',
// respectively.
export const handler = function(event, context, callback) {
console.log('Received event:', JSON.stringify(event, null, 2));
// Retrieve request parameters from the Lambda function input:
var headers = event.headers;
var queryStringParameters = event.queryStringParameters;
var pathParameters = event.pathParameters;
var stageVariables = event.stageVariables;
// Parse the input for the parameter values
var tmp = event.methodArn.split(':');
var apiGatewayArnTmp = tmp[5].split('/');
var awsAccountId = tmp[4];
var region = tmp[3];
var restApiId = apiGatewayArnTmp[0];
var stage = apiGatewayArnTmp[1];
var method = apiGatewayArnTmp[2];
var resource = '/'; // root resource
if (apiGatewayArnTmp[3]) {
resource += apiGatewayArnTmp[3];
}
// Perform authorization to return the Allow policy for correct parameters and
// the 'Unauthorized' error, otherwise.
if (headers.HeaderAuth1 === "headerValue1"
&& queryStringParameters.QueryString1 === "queryValue1"
&& stageVariables.StageVar1 === "stageValue1") {
callback(null, generateAllow('me', event.methodArn));
} else {
callback("Unauthorized");
}
}
// Help function to generate an IAM policy
var generatePolicy = function(principalId, effect, resource) {
// Required output:
var authResponse = {};
authResponse.principalId = principalId;
if (effect && resource) {
var policyDocument = {};
policyDocument.Version = '2012-10-17'; // default version
policyDocument.Statement = [];
var statementOne = {};
statementOne.Action = 'execute-api:Invoke'; // default action
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;
}
var generateAllow = function(principalId, resource) {
return generatePolicy(principalId, 'Allow', resource);
}
var generateDeny = function(principalId, resource) {
return generatePolicy(principalId, 'Deny', resource);
}
- Python
# A simple request-based authorizer example to demonstrate how to use request
# parameters to allow or deny a request. In this example, a request is
# authorized if the client-supplied headerauth1 header, QueryString1
# query parameter, and stage variable of StageVar1 all match
# specified values of 'headerValue1', 'queryValue1', and 'stageValue1',
# respectively.
import json
def lambda_handler(event, context):
print(event)
# Retrieve request parameters from the Lambda function input:
headers = event['headers']
queryStringParameters = event['queryStringParameters']
pathParameters = event['pathParameters']
stageVariables = event['stageVariables']
# Parse the input for the parameter values
tmp = event['methodArn'].split(':')
apiGatewayArnTmp = tmp[5].split('/')
awsAccountId = tmp[4]
region = tmp[3]
restApiId = apiGatewayArnTmp[0]
stage = apiGatewayArnTmp[1]
method = apiGatewayArnTmp[2]
resource = '/'
if (apiGatewayArnTmp[3]):
resource += apiGatewayArnTmp[3]
# Perform authorization to return the Allow policy for correct parameters
# and the 'Unauthorized' error, otherwise.
if (headers['HeaderAuth1'] == "headerValue1" and queryStringParameters['QueryString1'] == "queryValue1" and stageVariables['StageVar1'] == "stageValue1"):
response = generateAllow('me', event['methodArn'])
print('authorized')
return response
else:
print('unauthorized')
raise Exception('Unauthorized') # Return a 401 Unauthorized response
# Help function to generate IAM policy
def generatePolicy(principalId, effect, resource):
authResponse = {}
authResponse['principalId'] = principalId
if (effect and resource):
policyDocument = {}
policyDocument['Version'] = '2012-10-17'
policyDocument['Statement'] = []
statementOne = {}
statementOne['Action'] = 'execute-api:Invoke'
statementOne['Effect'] = effect
statementOne['Resource'] = resource
policyDocument['Statement'] = [statementOne]
authResponse['policyDocument'] = policyDocument
authResponse['context'] = {
"stringKey": "stringval",
"numberKey": 123,
"booleanKey": True
}
return authResponse
def generateAllow(principalId, resource):
return generatePolicy(principalId, 'Allow', resource)
def generateDeny(principalId, resource):
return generatePolicy(principalId, 'Deny', resource)
この例では、Lambda オーソライザー関数は入力パラメータをチェックして次のように動作します。
-
必要なすべてのパラメータ値が予想値と一致する場合、オーソライザー関数は 200 OK
HTTP レスポンスと次のような IAM ポリシーを返し、メソッドリクエストは成功します。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow",
"Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/"
}
]
}
-
一致しない場合、オーソライザー関数は 401 Unauthorized
HTTP レスポンスを返し、メソッドリクエストは失敗します。
Lambda オーソライザー関数は、IAM ポリシーだけでなく、発信者のプリンシパル ID を返す必要があります。オプションで、context
オブジェクトを返すこともできます。このオブジェクトには、統合バックエンドに渡すことができる追加情報が含まれています。詳細については、「API Gateway Lambda オーソライザーからの出力」を参照してください。
本番稼働コードでは、権限を付与する前にユーザーの認証が必要になる場合があります。この場合、認証プロバイダーを (関連ドキュメントの指示に従って) 呼び出すことで、Lambda 関数に認証ロジックを追加できます。
TOKEN
オーソライザー Lambda 関数の例
次のコード例で作成する TOKEN
Lambda オーソライザー関数では、クライアントが提供したトークン値が allow
の場合に、メソッドを呼び出すことを発信者に許可します。トークン値が deny
の場合、発信者はリクエストを呼び出すことを許可されません。トークン値が unauthorized
または空の文字列の場合、オーソライザー関数は 401 UNAUTHORIZED
レスポンスを返します。
- Node.js
// A simple token-based authorizer example to demonstrate how to use an authorization token
// to allow or deny a request. In this example, the caller named 'user' is allowed to invoke
// a request if the client-supplied token value is 'allow'. The caller is not allowed to invoke
// the request if the token value is 'deny'. If the token value is 'unauthorized' or an empty
// string, the authorizer function returns an HTTP 401 status code. For any other token value,
// the authorizer returns an HTTP 500 status code.
// Note that token values are case-sensitive.
export const handler = function(event, context, callback) {
var token = event.authorizationToken;
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;
}
- Python
# A simple token-based authorizer example to demonstrate how to use an authorization token
# to allow or deny a request. In this example, the caller named 'user' is allowed to invoke
# a request if the client-supplied token value is 'allow'. The caller is not allowed to invoke
# the request if the token value is 'deny'. If the token value is 'unauthorized' or an empty
# string, the authorizer function returns an HTTP 401 status code. For any other token value,
# the authorizer returns an HTTP 500 status code.
# Note that token values are case-sensitive.
import json
def lambda_handler(event, context):
token = event['authorizationToken']
if token == 'allow':
print('authorized')
response = generatePolicy('user', 'Allow', event['methodArn'])
elif token == 'deny':
print('unauthorized')
response = generatePolicy('user', 'Deny', event['methodArn'])
elif token == 'unauthorized':
print('unauthorized')
raise Exception('Unauthorized') # Return a 401 Unauthorized response
return 'unauthorized'
try:
return json.loads(response)
except BaseException:
print('unauthorized')
return 'unauthorized' # Return a 500 error
def generatePolicy(principalId, effect, resource):
authResponse = {}
authResponse['principalId'] = principalId
if (effect and resource):
policyDocument = {}
policyDocument['Version'] = '2012-10-17'
policyDocument['Statement'] = []
statementOne = {}
statementOne['Action'] = 'execute-api:Invoke'
statementOne['Effect'] = effect
statementOne['Resource'] = resource
policyDocument['Statement'] = [statementOne]
authResponse['policyDocument'] = policyDocument
authResponse['context'] = {
"stringKey": "stringval",
"numberKey": 123,
"booleanKey": True
}
authResponse_JSON = json.dumps(authResponse)
return authResponse_JSON
この例では、API がメソッドリクエストを受信すると、API Gateway は event.authorizationToken
属性でこの Lambda オーソライザー関数にソーストークンを渡します。Lambda オーソライザー関数はトークンを読み取り、次のように動作します。
-
トークン値が allow
の場合、オーソライザー関数は 200 OK
HTTP レスポンスと次のような IAM ポリシーを返し、メソッドリクエストは成功します。
{
"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
の場合、オーソライザー関数は 200
OK
HTTP レスポンスと次のような Deny
IAM ポリシーを返し、メソッドリクエストは失敗します。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Deny",
"Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/"
}
]
}
テスト環境以外では、API Gateway は 403 Forbidden
HTTP レスポンスを返し、メソッドリクエストは失敗します。
-
トークン値が unauthorized
または空の文字列の場合、オーソライザー関数は 401 Unauthorized
HTTP レスポンスを返し、メソッド呼び出しは失敗します。
-
それ以外のトークンの場合、クライアントは 500 Invalid token
レスポンスを受け取り、メソッド呼び出しは失敗します。
Lambda オーソライザー関数は、IAM ポリシーだけでなく、発信者のプリンシパル ID を返す必要があります。オプションで、context
オブジェクトを返すこともできます。このオブジェクトには、統合バックエンドに渡すことができる追加情報が含まれています。詳細については、「API Gateway Lambda オーソライザーからの出力」を参照してください。
本番稼働コードでは、権限を付与する前にユーザーの認証が必要になる場合があります。この場合、認証プロバイダーを (関連ドキュメントの指示に従って) 呼び出すことで、Lambda 関数に認証ロジックを追加できます。
その他の Lambda オーソライザー関数の例
次のリストは、その他の Lambda オーソライザー関数の例を示しています。Lambda 関数は、API を作成したのと同じアカウントまたは別のアカウントで作成できます。
前の例に示した Lambda 関数の場合は、他の AWS のサービスを呼び出さないため、組み込みの AWSLambdaBasicExecutionRole を使用できます。Lambda 関数から他の AWS のサービスを呼び出す場合は、Lambda 関数に IAM 実行ロールを割り当てる必要があります。ロールを作成するには、「AWS Lambda 実行ロール」の手順に従ってください。