Terraform-provider-aws: Terraform support for AWS API Gateway authorizer using "Request" type "Lambda Event Payload"

Created on 20 Oct 2017  ยท  5Comments  ยท  Source: hashicorp/terraform-provider-aws

_This issue was originally opened by @dp-c as hashicorp/terraform#16318. It was migrated here as a result of the provider split. The original body of the issue is below._


I 'am looking for terraform options to use the "Request" type "Lambda Event Payload" for API Gateway authorizer.

Here is some information about this on AWS

http://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html

Create a Lambda Function of a Custom Authorizer of the REQUEST type

In the code editor of the Lambda console, enter the following Node.js code for a simplified Lambda function as an example of the API Gateway custom authorizers of the REQUEST type.

Copy
exports.handler = function(event, context, callback) {
console.log('Received event:', JSON.stringify(event, null, 2));

// A simple REQUEST 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,
// stage variable of StageVar1 and the accountId in the request context all match
// specified values of 'headerValue1', 'queryValue1', 'stageValue1', and
// '123456789012', respectively.

// Retrieve request parameters from the Lambda function input:
var headers = event.headers;
var queryStringParameters = event.queryStringParameters;
var pathParameters = event.pathParameters;
var stageVariables = event.stageVariables;
var requestContext = event.requestContext;

// 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.
var authResponse = {};
var condition = {};
condition.IpAddress = {};

if (headers.HeaderAuth1 === "headerValue1"
    && queryStringParameters.QueryString1 === "queryValue1"
    && stageVariables.StageVar1 === "stageValue1"
    && requestContext.accountId === "123456789012") {
    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);
}
This Lambda function of the REQUEST authorizer verifies the input request parameters to return an Allow IAM policy on a specified method if all the required parameter (HeaderAuth1, QueryString1, StageVar1, and accountId) values match the pre-configured ones. This permits a caller to invoke the specified method. The caller receives a 200 OK response. Otherwise, the authorizer function returns an Unauthorized error, without generating any IAM policy.

enhancement servicapigateway stale

Most helpful comment

After some more investigation, by reading the AWS CLI docs, it turns out multiple parameters are supported by putting them all in one string using comma delimiters like so:

resource "aws_api_gateway_authorizer" "my_resource_name" {
      name = "my_resource_name"
      rest_api_id = "${aws_api_gateway_rest_api.my_rest_api.id}"
      authorizer_uri = "${var.authorizer_invoke_arn}"
      authorizer_credentials = "${aws_iam_role.invocation_role.arn}"
      type = "REQUEST"
      identity_source = "method.request.querystring.token,method.request.querystring.param2,method.request.querystring.param3"
      authorizer_result_ttl_in_seconds = 300
}

So with the current implementation it is indeed possible to correctly create a REQUEST type for custom authrorizer.

I think the docs could be updated to describe this scenario, so it avoids confusion.

All 5 comments

I also needed to use the "Request" type in the custom authorizer lambda event payload and it seems to be working, although the terraform documentation says only "TOKEN" type is supported.

My configuration looks like this and it worked properly:

resource "aws_api_gateway_authorizer" "my_resource_name" {
      name = "my_resource_name"
      rest_api_id = "${aws_api_gateway_rest_api.my_rest_api.id}"
      authorizer_uri = "${var.authorizer_invoke_arn}"
      authorizer_credentials = "${aws_iam_role.invocation_role.arn}"
      type = "REQUEST"
      identity_source = "method.request.querystring.token"
      authorizer_result_ttl_in_seconds = 300
}

The only limitation seems to be that identity_source doesn't accept a list of values, like it can be configured on AWS console, but in my case all I needed was token in querystring so it worked properly.

Actually, it turned out my cache key was not invalidating properly with just the token queryString in the identity_sources field, so I needed to add other queryString params to the list.

resource_aws_api_gateway_authorizer needs to be updated to support a Map instead of just String when type is set to "REQUEST"

After some more investigation, by reading the AWS CLI docs, it turns out multiple parameters are supported by putting them all in one string using comma delimiters like so:

resource "aws_api_gateway_authorizer" "my_resource_name" {
      name = "my_resource_name"
      rest_api_id = "${aws_api_gateway_rest_api.my_rest_api.id}"
      authorizer_uri = "${var.authorizer_invoke_arn}"
      authorizer_credentials = "${aws_iam_role.invocation_role.arn}"
      type = "REQUEST"
      identity_source = "method.request.querystring.token,method.request.querystring.param2,method.request.querystring.param3"
      authorizer_result_ttl_in_seconds = 300
}

So with the current implementation it is indeed possible to correctly create a REQUEST type for custom authrorizer.

I think the docs could be updated to describe this scenario, so it avoids confusion.

Marking this issue as stale due to inactivity. This helps our maintainers find and focus on the active issues. If this issue receives no comments in the next 30 days it will automatically be closed. Maintainers can also remove the stale label.

If this issue was automatically closed and you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. Thank you!

I'm going to lock this issue because it has been closed for _30 days_ โณ. This helps our maintainers find and focus on the active issues.

If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. Thanks!

Was this page helpful?
0 / 5 - 0 ratings