I'm using Terraform to allocate a Lambda function that's triggered by a request to an API Gateway on AWS. Here's my .tf file:
dsf
This correctly sets up the Lambda function, but something is off with the API Gateway. When I curl with the output URL (https://cqsso4fw67.execute-api.us-east-1.amazonaws.com), it gives me the following:
curl https://cqsso4fw67.execute-api.us-east-1.amazonaws.com/
{"message":"Internal Server Error"}%
If I manually remove this API Gateway and create a new one from the AWS Console within the Lambda function and run curl again, I get "SUCCESS!" (which is what my Lambda should do).
smf
Any ideas how I can fix the .tf file to correctly setup the API Gateway trigger?
Here are the differences between the one created in AWS and the one provisioned in Terraform. Terraform one is at the top.
The TF code that you showed is correct. Most likely reason for the failure is your lambda function, which you haven't showed. You have to inspect lambda function logs in CloudWatch to check why it fails.
Edit:
The function should return:
return {
'statusCode': 200,
'body': 'SUCCESS'
}
If anyone comes across this issue, I managed to fix it by greatly simplifying things. I switched out all the API Gateway clauses in the Terraform file with just:
resource "aws_apigatewayv2_api" "apigw-terraform" {
name = "terraform-api"
protocol_type = "HTTP"
target = aws_lambda_function.w-scan-terraform.arn
}
The tutorial I was following had implemented something more complex than what I needed.
Related
I created a REST API with AWS API Gateway. I have a GET method that triggers a Lambda function, but I cannot get the response I need. I properly configured query params etc. but in Lambda logs I see this.
com.amazonaws.serverless.exceptions.InvalidRequestEventException: The incoming event is not a valid request from Amazon API Gateway or an Application Load Balancer
2021-05-19T15:37:38.003+04:00 at com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequestReader.readRequest(AwsProxyHttpServletRequestReader.java:48)
2021-05-19T15:37:38.003+04:00 at com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequestReader.readRequest(AwsProxyHttpServletRequestReader.java:30)
2021-05-19T15:37:38.003+04:00 at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxy(LambdaContainerHandler.java:201)
What am I missing ? Thank you in advance.
When running lambdas locally, you need to define the event that trigger it.
For example:
sam local invoke --event tst\event.json where the event.json is basically the http parameters you are passing.
{
"httpMethod": "GET",
"path": "/",
}
For creating an event json template file for http requests, you can use: sam local generate-event apigateway aws-proxy.
I have an API Gateway resource that points to a specific version of lambda:
Foo-LambdaFunction7804AD21-1LLYB0GTDYURR:1
I use AWS API Gateway web UI navigate to the resource, then "test" section. I click "Test" and get back:
Execution failed due to configuration error: Invalid permissions on Lambda function
If I point to a lambda ARN without a version, i.e.
Foo-LambdaFunction7804AD21-1LLYB0GTDYURR
then it works as expected.
Does "Test" page of the AWS UI console has a different resource id and requires different resource-based policy statement?
I had to give API Gateway's execution role a permission to call Foo-LambdaFunction7804AD21-1LLYB0GTDYURR:1 lambda version.
I am relatively new to AWS and the beast. After working on API Gateway to Lambda proxy integration I am getting Execution failed due to configuration error: Invalid permissions on Lambda function
I followed below setup referred from really well documented terraform documentation and does exactly what was needed for me. But while testing on API Gateway console giving the above error.
resource "aws_lambda_permission" "apigw" {
statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = "${aws_lambda_function.resource_name.arn}"
principal = "apigateway.amazonaws.com"
# The /*/* portion grants access from any method on any resource
# within the API Gateway "REST API".
source_arn = "${aws_api_gateway_deployment.resource_name_of_deployment.execution_arn}/*/*"
}
Few learnings from API Gateway Lambda proxy integration
API Gateway is deployed in different stages and ARN for API gateway in stage vs on test console is somewhat different. (atleast thats what I got on terraform output)
As many documentations and fixes for the problem suggests to explicitly configure detailed path as "arn:aws:execute-api:region_name:account_id:${aws_api_gateway_rest_api.api_resource.id}/*/*"
The configured source with granted access permission
arn:aws:execute-api:region:accountid:fu349z93pa/*/*
From terraform documentation
For "${aws_api_gateway_deployment.deployment_rsc_name.execution_arn}"
The configured source with granted access permission is
arn:aws:execute-api:region:accountid:fu349z93pa/stage/*/*
If you test from API Gateway console you would end up with same error and have to manually add permission to lambda or reselect lambda function name on method integration console (which does the same thing). That configures 2 API gateways to access Lambda. (one with /stage deployed ARN and other /*/METHOD/* - used for test console)
But if you test API gateway from ARN of stage environment on postman it works just as fine without any manual updates to infrastructure built with terraform. And in most cases that is the one that would matter.
Even after fixing first error manually / not second challenge is Malformed response from lambda
This one is fairly easy and well documented. AWS Doc
All we have to do is update lambda to respond with a specified format.
for. e.g. add below
callback(null, { "statusCode": 200, "body" : JSON.stringify(sampleResponseJSON) }); on lambda `js`
Once it is working end to end we could always add error handling scenarios.
Hopefully, this should save some time for beginners like me.
So instead of using:
resource "aws_lambda_permission" "apigw" {
... ...
source_arn = "${aws_api_gateway_deployment.resource_name_of_deployment.execution_arn}/*/*"
}
I use the replace method to remove the stage_name from the execution_arn:
resource "aws_lambda_permission" "apigw" {
... ...
source_arn = "${replace(aws_api_gateway_deployment.resource_name_of_deployment.execution_arn, var.stage_name, "")}*/*"
}
And now everything works for me
I am creating infrastructure with terraform with API Gateway connecting to DynamoDb API. I am creating resource aws_api_gateway_integration to define the integration with DynamoDb with type attribute set as AWS.
But somehow i am unable to get the uri value right for db.
Documentation says it should be of format arn:aws:apigateway:{region}:{subdomain.service|service}:{path|action}/{service_api}.
Current value configured is arn:aws:apigateway:us-east-1:dynamodb:GetItem.
I am not sure what is service_api. Did anyone encounter this before? Kindly help.
This also took me some time to figure out, I think the DynamoDB API-Gateway Integration deserves a dedicated example in the Terraform docs similar to Lambda. Actually service_api just refers to the DynamoDB Action (which you would also enter in the AWS Api Gateway Console Action field) prefixed with the literal action/. So the following block eventually worked for my PUT request mapping:
resource "aws_api_gateway_integration" "my-integration" {
type = "AWS"
integration_http_method = "POST"
uri = "arn:aws:apigateway:eu-central-1:dynamodb:action/PutItem"
# (...)
}
I am making a call to aws cloudWatchEvent putRule & PutTarget api through aws sdk to create a cloudWatch Rule and attach a target to it. My Target is a lambda function, the rule gets created, the target gets attached to the rule but when the rule triggers based on its schedule the target lambda function not trigger. So I looked further and found out that the event source under the lambda function is not added which makes it not trigger. If I create the rule and target through AWS console the event source gets created and everything works but not thorugh API.
You'll need to call the lambda add-permission after adding the target.
That is (via boto3 for me):
create the lambda
create the rule
create the targets
call lambda add-permission with the lambda arn
see boto3 documentation or the cli doc.
It is possible to add event sources via aws sdk. I faced the same issue and please see code below as the solution using java.
AddPermissionRequest addPermissionRequest = new AddPermissionRequest();
addPermissionRequest.setStatementId("12345ff"); //any unique string would go
addPermissionRequest.withSourceArn(ruleArn);
addPermissionRequest.setAction("lambda:InvokeFunction");
addPermissionRequest.setPrincipal("events.amazonaws.com");
addPermissionRequest.setFunctionName("name of your lambda function");
AWSLambdaAsyncClient lambdaClient = new AWSLambdaAsyncClient();
lambdaClient.withRegion(Regions.US_EAST_1); //region of your lambda's location
lambdaClient.addPermission(addPermissionRequest);
I had same issue here, and i solve this by what #Anvita Shukla has sugested.
This worked fine when i do:
create the lambda (this i was created in web page)
And with SDK
create the rule object
create the target object
put request of the rule
put request of the target
get response object of rule request to retrieve the rule ARN
create permission object (has #Anvita Shukla said) and set the rule
ARN
add permission by lambda client object
In the aws lambda page i can see my lambdas with associated triggers events. And in aws cloudwatch events page i can see the created rules.
I wrote this in java lang. If you want i can share the code.
I fixed it. You need to add permission for lambda with SourceArn is cloud watch after putTargets. For example :
var lambdaPermission = {
FunctionName: 'cloudwatch-trigger',
StatementId : timestamp.toString(),
Action: 'lambda:InvokeFunction',
Principal: 'events.amazonaws.com',
SourceArn: 'arn:aws:events:ap-southeast-1:XXXXXX:rule/schedule_auto_1'
};
lambda.addPermission(lambdaPermission, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data);
console.log("add permisson done");
}
});
As far as I understand this is currently not possible through the SDK, CloudWatch event sources can only be added to lambdas through the console as you said or using the CLI. If I'm wrong I would love to know what is possible, but the documentation here seems to agree.
http://docs.aws.amazon.com/lambda/latest/dg/with-scheduled-events.html