Terraform module to create Amazon API Gateway (v1) resources.
Amazon API Gateway is a fully managed service that makes it easy for developers to create, publish, maintain, monitor, and secure APIs at any scale. APIs act as the "front door" for applications to access data, business logic, or functionality from your backend services. Using API Gateway, you can create RESTful APIs and WebSocket APIs that enable real-time two-way communication applications. API Gateway supports containerized and serverless workloads, as well as web applications.
Build RESTful APIs optimized for serverless workloads and HTTP backends using HTTP APIs. HTTP APIs are the best choice for building APIs that only require API proxy functionality. If your APIs require API proxy functionality and API management features in a single solution, API Gateway also offers REST APIs.
- Uses OpenAPI 3.x Specification
- Deploy REST API to many stages
- Supports creation of many API Keys
- Supports creation of many stages
- Supports stage canaries.
- Supports creation of domain name and its mapping
- Supports assigning many API Keys to many usage plans
- Supports assigning many usage plans to many stages
- Supports WAF integration for stages
- Supports VPC Link for
EDGE
®IONAL
type API's - Supports VPC Endpoints for
PRIVATE
type API's
- COMING SOON...
- Public API Scenario
- You already have Network Load Balancer (NLB) with an IP type target group created if you are creating an API using the
regional
oredge
deployment type. - You already have VPC Link setup and configured to point to your internal Network Load Balancer (NLB) if you are creating an API using the
regional
oredge
deployment type. - You have already configured a VPC endpoint(s) that your NLB is using as targets if you are creating an API using the
regional
oredge
deployment type. That VPC endpoint is connected to a VPC Endpoint Service in the same account or another account. (see architecture diagram)
- You already have Network Load Balancer (NLB) with an IP type target group created if you are creating an API using the
- All Scenarios
- You already have created the CloudWatch Log Group for your access logging. This is different from execution log groups which is created automatically by API Gateway and is not manageable by Terraform.
- You already have created the IAM role and policy for API Gateway execution. This role is needed so that it can create the CloudWatch Log Group and push log streams to it.
-
The definition of the API is managed using the OpenAPI 3.x standard and is contained in a openapi.yaml file. This file contains the paths, authorization integrations, VPC Link integrations, responses, authorizers, etc. The goal is to configure as much of the API in this .yaml as possible and use Terragrunt to manage the broader context of API Gateway. This approach also reduces greatly the amount of Terraform resources that need to be created/managed.
-
The resources abstracted from Terraform and into OpenAPI spec are listed below. Because of this, there are no inputs in Terraform for the REST API itself except for the
name
,description
,body
, andput_rest_api_mode
. To provide inputs for these resources, you must do so in the openapi.yaml file using the AWS OpenAPI Extensions from the developer guide.aws_api_gateway_resource aws_api_gateway_method aws_api_gateway_method_response aws_api_gateway_method_settings aws_api_gateway_integration aws_api_gateway_integration_response aws_api_gateway_gateway_response aws_api_gateway_model
-
The API is deployed every time a change is made in Terraform. This is done to ensure that the deploy being used matches with the most recent deploy. Otherwise, this can be unexpectedly out-of-sync.
-
This module was initially built to suit a public REST API over Private Link and as such, depended on a Network Load Balancer (NLB) to function with VPC Link. You can choose to remove this dependency for private API's not using the
regional
oredge
deployment type.
- (Merge Mode)
- When importing Open API Specifications with the
body
argument, by default the API Gateway REST API will be replaced with the Open API Specification thus removing any existing methods, resources, integrations, or endpoints. Endpoint mutations are asynchronous operations, and race conditions with DNS are possible. To overcome this limitation, use theput_rest_api_mode
attribute and set it tomerge
. - Using
put_rest_api_mode
=merge
when importing the OpenAPI Specification, the AWS control plane WILL NOT delete all existing literal properties that are not explicitly set in the OpenAPI definition. Impacted API Gateway properties: ApiKeySourceType, BinaryMediaTypes, Description, EndpointConfiguration, MinimumCompressionSize, Name, Policy). - When using
put_rest_api_mode
=merge
, and you rename/remove a resource in the body, that resource change WILL NOT be reflected in the console. - When using
put_rest_api_mode
=overwrite
, the AWS APIGW console reflects all changes you make accurately. However, be aware of the warning issued by the provider about usingoverwrite
mode. We have not experienced issues using it so far with this module and implementation but in tests, we have only toggled this mode when we are renaming resource paths or removing resources from the body altogether.
- When importing Open API Specifications with the
- (PRIVATE Type API Endpoint)
- When a REST API type of
PRIVATE
is needed, the VPC endpoints must be specified in theopenapi.yaml
definition. This is especially called out since it is not obvious as most modules allow setting this in the Terraform input block.x-amazon-apigateway-endpoint-configuration: vpcEndpointIds: [""] disableExecuteApiEndpoint: true
- When a REST API type of
- (Deployments History vs. Deployment being used)
- We deploy every time using
(timestamp()}
in theaws_api_gateway_deployment
resource. If we do not, sometimes the deployment history has new deployments but the actual deployment in-use by the stage might be an older one. - Currently there is almost always one deployment, which is the most recent one. When there are multiple deployments in history, only the most recent will be used by default.
- Domain names supports only one ACM Certificate for all the domain names, so the certificate must be valid for all the chosen domain names.
- We deploy every time using
- Want
aws_api_gateway_method_settings
to allow us to apply different method settings by stage and by method instead of choosing between the full override*/*
or only a single method to manage (e.g.{resource_path}/{http_method}
). Currently whatever the path is dictates all method settings for the stages that have been deployed. Method settings would be represented as amap
just as we already do with api keys and usage plans. - Want a usage_plan to accept many API keys as a
list(string)
. Currenly a usage plan has a 1:1 relationship with API keys. This should be expanded so that many API keys can be associated with a single usage plan in the event multiple external consumers have similar API needs. This will reduce the number of usage plans needed. Want the ability to create/enable VPC Link in this module since we're already consuming the Network Load Balancer (NLB) outputs when we are using the.regional
oredge
deployment type
- CloudWatch Alarms
- For CloudWatch Cache Hit/Miss alarms to work, you must enable the cache cluster for the stage.
- NLB Health Checks
- Ensure you are using the same availability zones from your NLB all the way to the target ALB where your service is running. Otherwise, you will see NLB targets (which are VPC endpint IP's) that are in an unhealthy state.
- NLB Target Groups
- At the time of this writing, there is an open issue for NLB's specifically where you will only be able to have 1 target group for a listener in Terraform (e.g. 443). Because of this, we must deploy an NLB, & VPCLink for each API instead of having 1 NLB and many target groups for each API. See this issue opened for the AWS CDK (is not a CDK issue alone)
- VPCLink + Private Link
- In the case where we are using private link + VPC Link to connect a REST API to a target service, it is important to know that the integration URI needed for the API integration request needs to match the domain/cert that is being used at the ALB level closest to the target service. Do not point the integration URI to the network load balancer. If the ALB listener for the application has a cert attached for
*.nonprod.mycompany.com
, the integration URI for the API needs to also use that domain(e.g. my-app.nonprod.mycompany.com)
to avoid a cert mismatch error.
- In the case where we are using private link + VPC Link to connect a REST API to a target service, it is important to know that the integration URI needed for the API integration request needs to match the domain/cert that is being used at the ALB level closest to the target service. Do not point the integration URI to the network load balancer. If the ALB listener for the application has a cert attached for
module "rest-api" {
source = "git::git@github.com:adamwshero/terraform-aws-api-gateway.git//.?ref=1.0.7"
inputs = {
api_name = "my-app-dev"
description = "Development API for the My App service."
endpoint_type = ["REGIONAL"]
put_rest_api_mode = "merge" // Toggle to `overwrite` only when renaming a resource path or removing a resource from the openapi definition.
// API Definition & Vars
openapi_definition = templatefile("${get_terragrunt_dir()}/openapi.yaml",
{
endpoint_uri = "https://my-app.nonprod.company.com}/my_app_path"
authorizer_invoke_arn = "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:111111111111:function:my-app-dev/invocation"
authorizer_execution_arn = "arn:aws:iam::111111111111:role/my-app-dev"
}
)
// Stage Settings
stage_names = ["dev"]
stage_description = "Development stage for My App API"
log_group_name = "/aws/apigateway/access/my_app/dev"
access_log_format = templatefile("${get_terragrunt_dir()}/log_format.json.tpl", {})
// Method Settings
method_path = "*/*"
// Security
enable_waf = false
// Execution Role
cloudwatch_role_arn = "arn:aws:logs:us-east-1:111111111111:log-group:/aws/lambda/my-app-dev"
cloudwatch_policy_name = "my-app-dev"
// Usage Plans & API Keys
create_usage_plan = false
enable_api_key = false
tags = local.tags
}
terraform {
source = "git::git@github.com:adamwshero/terraform-aws-api-gateway.git//.?ref=1.0.7"
}
inputs = {
api_name = "my-app-dev"
description = "Development API for the My App service."
endpoint_type = ["REGIONAL"]
put_rest_api_mode = "merge" // Toggle to `overwrite` only when renaming a resource path or removing a resource from the openapi definition.
// API Definition & Vars
openapi_definition = templatefile("${get_terragrunt_dir()}/openapi.yaml",
{
endpoint_uri = "https://my-app.nonprod.company.com}/my_app_path"
authorizer_invoke_arn = "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:111111111111:function:my-app-dev/invocation"
authorizer_execution_arn = "arn:aws:iam::111111111111:role/my-app-dev"
}
)
// Stage Settings
stage_names = ["dev"]
stage_description = "Development stage for My App API"
log_group_name = "/aws/apigateway/access/my_app/dev"
access_log_format = templatefile("${get_terragrunt_dir()}/log_format.json.tpl", {})
// Method Settings
method_path = "*/*"
// Security
enable_waf = false
// Execution Role
cloudwatch_role_arn = "arn:aws:logs:us-east-1:111111111111:log-group:/aws/lambda/my-app-dev"
cloudwatch_policy_name = "my-app-dev"
// Usage Plans & API Keys
create_usage_plan = false
enable_api_key = false
tags = local.tags
}
- Working with AWS API Gateway Extensions to OpenAPI
- AWS API Gateway Dimensions & Metrics
- OpenAPI Specification
Name | Version |
---|---|
terraform | >= 0.13.1 |
aws | >= 4.30.0 |
terragrunt | >= 0.28.0 |
Name | Version |
---|---|
aws | >= 4.30.0 |
No modules.
Name | Type |
---|---|
aws_api_gateway_account.this | resource |
aws_api_gateway_api_key.this | resource |
aws_api_gateway_base_path_mapping.edge_acm | resource |
aws_api_gateway_base_path_mapping.edge_iam | resource |
aws_api_gateway_base_path_mapping.regional_acm | resource |
aws_api_gateway_base_path_mapping.regional_iam | resource |
aws_api_gateway_deployment.this | resource |
aws_api_gateway_domain_name.edge_acm | resource |
aws_api_gateway_domain_name.edge_iam | resource |
aws_api_gateway_domain_name.regional_acm | resource |
aws_api_gateway_domain_name.regional_iam | resource |
aws_api_gateway_method_settings.this | resource |
aws_api_gateway_rest_api.this | resource |
aws_api_gateway_rest_api_policy.this | resource |
aws_api_gateway_stage.this | resource |
aws_api_gateway_usage_plan.this | resource |
aws_api_gateway_usage_plan_key.this | resource |
aws_cloudwatch_log_group.this | resource |
aws_wafv2_web_acl_association.this | resource |
Name | Description | Type | Default | Required |
---|---|---|---|---|
access_log_format | (Required) Formatting and values recorded in the logs. For more information on configuring the log format rules visit the AWS documentation | string |
n/a | yes |
api_key_description | (Optional) API key description. Defaults to Managed by Terraform . |
string |
null |
no |
api_key_name | (Required) Name of the API key. | string |
null |
no |
api_keys | Map of objects that define the usage plan to be created. | list( |
[ |
no |
api_name | (Required) Name of the REST API. If importing an OpenAPI specification via the body argument, this corresponds to the info.title field. If the argument value is different than the OpenAPI value, the argument value will override the OpenAPI value. |
string |
null |
no |
burst_limit | (Optional) - The API request burst limit, the maximum rate limit over a time ranging from one to a few seconds, depending upon whether the underlying token bucket is at its full capacity. | number |
5 |
no |
cache_cluster_enabled | (Optional) Whether a cache cluster is enabled for the stage. | bool |
true |
no |
cache_cluster_size | (Optional) Size of the cache cluster for the stage, if enabled. Allowed values include 0.5 , 1.6 , 6.1 , 13.5 , 28.4 , 58.2 , 118 and 237 . |
number |
0.5 |
no |
cache_data_encrypted | (Optional) Whether the cached responses are encrypted. | bool |
false |
no |
cache_ttl_in_seconds | (Optional) Time to live (TTL), in seconds, for cached responses. The higher the TTL, the longer the response will be cached. | number |
300 |
no |
caching_enabled | (Optional) Whether responses should be cached and returned for requests. A cache cluster must be enabled on the stage for responses to be cached. | bool |
true |
no |
certificate_type | This resource currently only supports managing a single value. Valid values: ACM or IAM . If unspecified, defaults to acm |
string |
"ACM" |
no |
client_certificate_id | (Optional) Identifier of a client certificate for the stage. | string |
null |
no |
client_name | client name to use this api. | string |
null |
no |
cloudwatch_role_arn | (Required) for the api_gateway_account resource. |
string |
n/a | yes |
create_api_domain_name | Whether to create API domain name resource. | bool |
false |
no |
create_rest_api_policy | Enables creation of the resource policy for a given API. | bool |
true |
no |
create_usage_plan | Allows creation of a usage plan. (Requires var.enable_api_key = true ) |
bool |
false |
no |
data_trace_enabled | (Optional) Whether data trace logging is enabled for this method, which effects the log entries pushed to Amazon CloudWatch Logs. | bool |
false |
no |
description | (Optional) Description of the REST API. If importing an OpenAPI specification via the body argument, this corresponds to the info.description field. If the argument value is provided and is different than the OpenAPI value, the argument value will override the OpenAPI value. |
string |
null |
no |
documentation_version | (Optional) Version of the associated API documentation. | string |
null |
no |
domain_certificate_arn | The ARN of an AWS-managed certificate that will be used by the endpoint for the domain name. | string |
null |
no |
domain_certificate_name | Unique name to use when registering this certificate as an IAM server certificate. Conflicts with certificate_arn, regional_certificate_arn, and regional_certificate_name. Required if certificate_arn is not set. | string |
null |
no |
domain_names | Fully-qualified domain name to register. The domain names to use for API gateway it will use the index of stage_names to select the domain name. | list(string) |
null |
no |
enable_api_key | (Optional) Whether the API key can be used by callers. Defaults to false . |
bool |
false |
no |
enable_canary | (Optional) Whether to use the values supplied for the canary and stage_variable_overrides or not. | bool |
false |
no |
enable_waf | Enables associating existing WAF ACL to all stages. | bool |
false |
no |
endpoint_type | (Required) List of endpoint types. This resource currently only supports managing a single value. Valid values: EDGE , REGIONAL or PRIVATE . If unspecified, defaults to EDGE . Must be declared as REGIONAL in non-Commercial partitions. If set to PRIVATE recommend to set put_rest_api_mode = merge to not cause the endpoints and associated Route53 records to be deleted. Refer to the documentation for more information on the difference between edge-optimized and regional APIs. |
string |
"EDGE" |
no |
iam_certificate_body | Certificate issued for the domain name being registered, in PEM format. Only valid for EDGE endpoint configuration type. Conflicts with certificate_arn, regional_certificate_arn, and regional_certificate_name | string |
null |
no |
iam_certificate_chain | Certificate for the CA that issued the certificate, along with any intermediate CA certificates required to create an unbroken chain to a certificate trusted by the intended API clients. Only valid for EDGE endpoint configuration type. Conflicts with certificate_arn, regional_certificate_arn, and regional_certificate_name. | string |
null |
no |
iam_certificate_private_key | Private key associated with the domain certificate given in certificate_body. Only valid for EDGE endpoint configuration type. Conflicts with certificate_arn, regional_certificate_arn, and regional_certificate_name. | string |
null |
no |
limit | (Optional) - Maximum number of requests that can be made in a given time period. | number |
20 |
no |
log_group_kms_key | (Optional) The ARN of the KMS Key to use when encrypting log data. Please note, after the AWS KMS CMK is disassociated from the log group, AWS CloudWatch Logs stops encrypting newly ingested data for the log group. All previously ingested data remains encrypted, and AWS CloudWatch Logs requires permissions for the CMK whenever the encrypted data is requested. | string |
null |
no |
log_group_name | (Optional, Forces new resource) The name of the log group. If omitted, Terraform will assign a random, unique name. | string |
null |
no |
log_group_retention_in_days | (Optional) Specifies the number of days you want to retain log events in the specified log group. Possible values are: 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653, and 0. If you select 0, the events in the log group are always retained and never expire. | string |
7 |
no |
logging_level | (Optional) Logging level for this method, which effects the log entries pushed to Amazon CloudWatch Logs. The available levels are OFF, ERROR, and INFO. | string |
"INFO" |
no |
method_path | (Required) Method path defined as {resource_path}/{http_method} for an individual method override, or */* for overriding all methods in the stage. Ensure to trim any leading forward slashes in the path. |
string |
n/a | yes |
metrics_enabled | (Optional) Whether Amazon CloudWatch metrics are enabled for this method. | string |
true |
no |
mutual_tls_authentication | An Amazon S3 URL that specifies the truststore for mutual TLS authentication as well as version, keyed at uri and version | map(string) |
{} |
no |
offset | (Optional) - Number of requests subtracted from the given limit in the initial time period. | number |
2 |
no |
openapi_definition | (Required) YAML formatted definition file using OpenAPI 3.x specification. This definition contains all API configuration inputs. Any inputs used in Terraform will override inputs in the definition. | string |
n/a | yes |
percent_traffic | (Optional) Percent 0.0 - 100.0 of traffic to divert to the canary deployment. | number |
null |
no |
period | (Optional) - Time period in which the limit applies. Valid values are DAY , WEEK or MONTH . |
string |
"WEEK" |
no |
put_rest_api_mode | (Optional) Mode of the PutRestApi operation when importing an OpenAPI specification via the body argument (create or update operation). Valid values are merge and overwrite. If unspecificed, defaults to overwrite (for backwards compatibility). This corresponds to the x-amazon-apigateway-put-integration-method extension. If the argument value is provided and is different than the OpenAPI value, the argument value will override the OpenAPI value. | string |
"overwrite" |
no |
rate_limit | (Optional) - The API request steady-state rate limit. | number |
10 |
no |
require_authorization_for_cache_control | (Optional) Whether authorization is required for a cache invalidation request. | bool |
true |
no |
rest_api_policy | (Required) JSON formatted policy document that controls access to the API Gateway. For more information about building AWS IAM policy documents with Terraform, see the AWS IAM Policy Document Guide | string |
"" |
no |
stage_description | (Optional) Description of the stage. | string |
null |
no |
stage_names | (Required) Name of the stage(s). | list(string) |
null |
no |
stage_variable_overrides | (Optional) Map of overridden stage variables (including new variables) for the canary deployment. | any |
{} |
no |
stage_variables | (Optional) Map that defines the stage variables. | any |
{} |
no |
throttling_burst_limit | (Optional) Throttling burst limit. Default: -1 (throttling disabled). | number |
-1 |
no |
throttling_rate_limit | (Optional) Throttling rate limit. Default: -1 (throttling disabled). | number |
-1 |
no |
unauthorized_cache_control_header_strategy | (Optional) How to handle unauthorized requests for cache invalidation. The available values are FAIL_WITH_403 , SUCCEED_WITH_RESPONSE_HEADER , SUCCEED_WITHOUT_RESPONSE_HEADER . |
string |
"SUCCEED_WITH_RESPONSE_HEADER" |
no |
usage_plans | Map of objects that define the usage plan to be created. | list( |
[ |
no |
use_stage_cache | (Optional) Whether the canary deployment uses the stage cache. Defaults to false. | bool |
false |
no |
waf_acl | (Required) The ID of the WAF Regional WebACL to create an association. | string |
null |
no |
xray_tracing_enabled | (Optional) Whether active tracing with X-ray is enabled. Defaults to false. | bool |
false |
no |
Name | Description |
---|---|
api_gateway_rest_api_arn | Arn of the REST API. |
api_gateway_rest_api_execution_arn | Execution Arn of the REST API. |
api_gateway_rest_api_id | Id of the REST API. |
api_gateway_rest_api_name | Name of the REST API. |
api_gateway_rest_api_stage_arn | Arn of the deployed stage(s). |
api_gateway_rest_api_stage_execution_arn | Execution arn of the deployed stage(s). |
api_gateway_rest_api_stage_id | Id of the deployed stage(s). |
api_gateway_rest_api_stage_invoke_url | Invoke URL of the deployed stage(s). |
api_gateway_rest_api_stage_web_acl | WAF Access Control List for the stage(s) |