I'm currently creating an AWS API Gateway with terraform by using an open api spec from a json file.
resource "aws_api_gateway_rest_api" "my_test_gateway" {
name = "test_gateway"
description = "test gateway"
body = "${file("assets/test_openapi_spc.json")}"
}
I need to map the api resources that are created by said openAPI spec to AWS Step Functions.
How can i reference a API Gateway resource created by the openAPI spec to be able to create a new aws_api_gateway_integration?
Normally you would do something like this and describe the resources in terraform
resource "aws_api_gateway_integration" "test" {
resource_id = "${aws_api_gateway_resource.my_resource.id}"
}
In my case, however, i don't have a resource id defined in my terraform scripts because they get created by the openAPI spec.
Is there some way of extracting all the resources of an api gateway that were created as terraform data source so that i can reference them?
Not sure if i'm missing something major here.
seems the best way to do this is with swagger extensions
https://swagger.io/docs/specification/openapi-extensions/
The integration part of the API resource can reside in your swagger spec.
Just like mentioned in the aws API Gateway extensions to swagger https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions.html
So if you want to map a resource to a step function for example, you can do:
x-amazon-apigateway-integration:
credentials: "arn:aws:iam::my_account:role/ApiGWToStepFunction"
responses:
default:
statusCode: "201"
uri: "arn:aws:apigateway:my_zone:states:action/StartExecution"
passthroughBehavior: "when_no_templates"
httpMethod: "POST"
type: "aws"
I'm not finished yet, but i believe that instead of arn:aws:apigateway:my_zone:states:action/StartExecution it should be arn:aws:apigateway:my_zone:states:your_step_function_name
Related
Original Requirement:
Create a route/path on AWS Api Gateway which connects API Gateway directly to AWS Event Bridge (Cloudwatch Events) and puts/pushes event on an event bus of it.
Was able to create it and executes just fine when done from AWS Console.
Actual Problem:
When writing the AWS Cloudformation script for this API Gateway, it looks like this:
EventsPostMethod:
Type: AWS::ApiGateway::Method
Properties:
ResourceId:
Ref: EventsResource
RestApiId:
Ref: RestAPI
HttpMethod: POST
AuthorizationType: NONE
Integration:
Type: AWS
IntegrationHttpMethod: POST
Uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:cloudwatchEvents:action/PutEvents
RequestParameters:
integration.request.header.X-Amz-Target: "'AWSEvents.PutEvents'"
RequestTemplate:
some-script-here...
Notice the Uri value:
"arn:aws:apigateway:${AWS::Region}:cloudwatchEvents:action/PutEvents"
arn:aws:apigateway:{region}:{subdomain.service|service}:path|action/{service_api}
According to AWS Docs the value of uri should be following:
For AWS or AWS_PROXY integrations, the URI is of the form arn:aws:apigateway:{region}:{subdomain.service|service}:path|action/{service_api}. Here, {Region} is the API Gateway region (e.g., us-east-1); {service} is the name of the integrated AWS service (e.g., s3); and {subdomain} is a designated subdomain supported by certain AWS service for fast host-name lookup. action can be used for an AWS service action-based API, using an Action={name}&{p1}={v1}&p2={v2}... query string. The ensuing {service_api} refers to a supported action {name} plus any required input parameters. Alternatively, path can be used for an AWS service path-based API. The ensuing service_api refers to the path to an AWS service resource, including the region of the integrated AWS service, if applicable. For example, for integration with the S3 API of GetObject, the uri can be either arn:aws:apigateway:us-west-2:s3:action/GetObject&Bucket={bucket}&Key={key} or arn:aws:apigateway:us-west-2:s3:path/{bucket}/{key}
You must have noticed that I replaced the service with cloudwatchEvents in the above mentioned uri.
Now, error Given by AWS Cloudformation Console during Publish of API Gateway:
AWS Service of type cloudwatchEvents not supported (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: 07bae22c-d198-4595-8de9-6ea23763eff5; Proxy: null)
Now I have tried replacing service with
cloudwatch
eventBridge
cloudwatchEvent
event-bus
This is the real problem. What should I place in service in uri so that it accepts ?
Based on the comments,
The URI should be something like below for events:
arn:aws:apigateway:${AWS::Region}:events:action/PutEvents
Amazon released HTTP APIs for their api gateway product fairly recently, and I'd like to use Terraform to spin some up. I saw that Terraform has documentation for the aws_apigatewayv2_api resource, which will create the gateway itself, but I can't find documentation for routes, stages, or any other types of resources that I'll be needing in my gateway.
Are HTTP APIs just not fully supported by Terraform yet, or am I missing some documentation somewhere?
Update:
Per the closing comment on issue #11148, the AWS API Gateway HTTP API resources were first generally supported in terraform-aws-provider starting in v3.3.0. Later releases have already added new functionality.
Historical answer:
Indeed, it looks like the Terraform AWS provider does not yet support all of the resources necessary for an API Gateway HTTP API.
The aws_apigatewayv2_api resource was released on March 12, 2020 in terraform-provider-aws 2.53.0, but implementations of resources such as aws_apigatewayv2_route, aws_apigatewayv2_stage, and aws_apigatewayv2_integration have yet to be merged.
terraform-provider-aws issue #11148 has links to pending pull requests for the new resources.
Everything you need to use http v2 apis is now available in terraform. There is a good tutorial on creating them here.
Essentially, for a simple gateway+lambda combo you want something like this:
# Lambda function
resource "aws_lambda_function" "lambda" {
# ...
}
# HTTP API
resource "aws_apigatewayv2_api" "api" {
name = "api-${random_id.id.hex}"
protocol_type = "HTTP"
target = aws_lambda_function.lambda.arn
}
# Permission
resource "aws_lambda_permission" "apigw" {
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.lambda.arn
principal = "apigateway.amazonaws.com"
source_arn = "${aws_apigatewayv2_api.api.execution_arn}/*/*"
}
I have a lambda deployed to AWS, integration is lambda-proxy, now I have an API Gateway which gives me an endpoint for calling the lambda. I need to get this endpoint URL in a terraform configuration, how can I do this?
Data sources don't expose any URL
data "aws_lambda_function" "myfunction" {
function_name = "my-function-name"
}
data "aws_api_gateway_rest_api" "my_rest_api" {
name = "my-rest-api"
}
api_gateway_deployment does expose an invoke_url, but infortunately it can't be imported, otherwise I could have declared the resources and then use terraform import ...
resource "aws_api_gateway_rest_api" "my_rest_api" {
name = "my-rest-api"
tags = {
STAGE = "prod"
}
}
resource "aws_api_gateway_deployment" "my_rest_api" {
rest_api_id = aws_api_gateway_rest_api.my_rest_api.id
stage_name = "prod"
}
EDIT: to clarify, the lambda is not deployed or managed by terraform.
I have a slightly different but similar setup working on my end.
I used:
- Terraform to provision AWS API Gateway Custom Domain
- Serverless Framework to deploy & link Lambdas to the API GW URL created above.
I exported API GW URL from Terraform as an Output Variable. And, passed it as an environment variable to Serverless Framework during function deployment.
Here it is how in action.
1/ main.tf responsible for exporting API GW URL
output "tf_output_aws_apigw_domain_name__domain_name"
{
value = "${aws_api_gateway_domain_name.tf_aws_apigw_domain_for_apis.domain_name}"
}
2/ serverless.yml responsible for linking Lambda function to this API GW URL
[...]
customDomain:
domainName: ${env:APIGW_DOMAIN_NAME}
basePath: /myapi
stage: dev
createRoute53Record: true
[...]
Here are the commands which glue them together (in my automation pipeline).
First part is responsible to read the terraform's output variable value (i.e. API GW URL that was created earlier) and sets itself to an environment variable APIGW_DOMAIN_NAME.
Later part initializes serverless-domain-manager plug-in responsible for mapping lambda function to APIGW URL and deploys a serverless setup.
terraform init ...
terraform refresh ...
export APIGW_DOMAIN_NAME=`terraform output tf_output_aws_apigw_domain_name__domain_name`
sls plugin install -n serverless-domain-manager
sls deploy --debug
cheers,
ram
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"
# (...)
}