Skip to content

feat: Added support for Authorizers #64

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,28 @@ module "api_gateway" {
payload_format_version = "2.0"
timeout_milliseconds = 12000
}

"GET /some-route-with-authorizer" = {
integration_type = "HTTP_PROXY"
integration_uri = "some url"
authorizer_key = "azure"
}

"$default" = {
lambda_arn = "arn:aws:lambda:eu-west-1:052235179155:function:my-default-function"
}
}

authorizers = {
"azure" = {
authorizer_type = "JWT"
identity_sources = "$request.header.Authorization"
name = "azure-auth"
audience = ["d6a38afd-45d6-4874-d1aa-3c5c558aqcc2"]
issuer = "https://sts.windows.net/aaee026e-8f37-410e-8869-72d9154873e4/"
}
}

tags = {
Name = "http-apigateway"
}
Expand Down Expand Up @@ -112,6 +128,7 @@ No modules.
|------|------|
| [aws_apigatewayv2_api.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_api) | resource |
| [aws_apigatewayv2_api_mapping.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_api_mapping) | resource |
| [aws_apigatewayv2_authorizer.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_authorizer) | resource |
| [aws_apigatewayv2_domain_name.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_domain_name) | resource |
| [aws_apigatewayv2_integration.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_integration) | resource |
| [aws_apigatewayv2_route.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_route) | resource |
Expand All @@ -124,6 +141,7 @@ No modules.
|------|-------------|------|---------|:--------:|
| <a name="input_api_key_selection_expression"></a> [api\_key\_selection\_expression](#input\_api\_key\_selection\_expression) | An API key selection expression. Valid values: $context.authorizer.usageIdentifierKey, $request.header.x-api-key. | `string` | `"$request.header.x-api-key"` | no |
| <a name="input_api_version"></a> [api\_version](#input\_api\_version) | A version identifier for the API | `string` | `null` | no |
| <a name="input_authorizers"></a> [authorizers](#input\_authorizers) | Map of API gateway authorizers | `map(any)` | `{}` | no |
| <a name="input_body"></a> [body](#input\_body) | An OpenAPI specification that defines the set of routes and integrations to create as part of the HTTP APIs. Supported only for HTTP APIs. | `string` | `null` | no |
| <a name="input_cors_configuration"></a> [cors\_configuration](#input\_cors\_configuration) | The cross-origin resource sharing (CORS) configuration. Applicable for HTTP APIs. | `any` | `{}` | no |
| <a name="input_create"></a> [create](#input\_create) | Controls if API Gateway resources should be created | `bool` | `true` | no |
Expand Down
18 changes: 17 additions & 1 deletion examples/complete-http/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ module "api_gateway" {
throttling_rate_limit = 100
}

authorizers = {
"cognito" = {
authorizer_type = "JWT"
identity_sources = "$request.header.Authorization"
name = "cognito"
audience = ["d6a38afd-45d6-4874-d1aa-3c5c558aqcc2"]
issuer = "https://${aws_cognito_user_pool.this.endpoint}"
}
}

integrations = {

"ANY /" = {
Expand All @@ -65,6 +75,12 @@ module "api_gateway" {
authorizer_id = aws_apigatewayv2_authorizer.some_authorizer.id
}

"GET /some-route-with-authorizer" = {
lambda_arn = module.lambda_function.lambda_function_arn
payload_format_version = "2.0"
authorizer_key = "cognito"
}

"POST /start-step-function" = {
integration_type = "AWS_PROXY"
integration_subtype = "StepFunctions-StartExecution"
Expand Down Expand Up @@ -259,7 +275,7 @@ module "lambda_function" {

resource "aws_s3_bucket" "truststore" {
bucket = "${random_pet.this.id}-truststore"
acl = "private"
# acl = "private"
}

resource "aws_s3_bucket_object" "truststore" {
Expand Down
105 changes: 66 additions & 39 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ resource "aws_apigatewayv2_api" "this" {
for_each = length(keys(var.cors_configuration)) == 0 ? [] : [var.cors_configuration]

content {
allow_credentials = lookup(cors_configuration.value, "allow_credentials", null)
allow_headers = lookup(cors_configuration.value, "allow_headers", null)
allow_methods = lookup(cors_configuration.value, "allow_methods", null)
allow_origins = lookup(cors_configuration.value, "allow_origins", null)
expose_headers = lookup(cors_configuration.value, "expose_headers", null)
max_age = lookup(cors_configuration.value, "max_age", null)
allow_credentials = try(cors_configuration.value.allow_credentials, null)
allow_headers = try(cors_configuration.value.allow_headers, null)
allow_methods = try(cors_configuration.value.allow_methods, null)
allow_origins = try(cors_configuration.value.allow_origins, null)
expose_headers = try(cors_configuration.value.expose_headers, null)
max_age = try(cors_configuration.value.max_age, null)
}
}

Expand All @@ -48,9 +48,10 @@ resource "aws_apigatewayv2_domain_name" "this" {

dynamic "mutual_tls_authentication" {
for_each = length(keys(var.mutual_tls_authentication)) == 0 ? [] : [var.mutual_tls_authentication]

content {
truststore_uri = mutual_tls_authentication.value.truststore_uri
truststore_version = lookup(mutual_tls_authentication.value, "truststore_version", null)
truststore_version = try(mutual_tls_authentication.value.truststore_version, null)
}
}

Expand All @@ -67,6 +68,7 @@ resource "aws_apigatewayv2_stage" "default" {

dynamic "access_log_settings" {
for_each = var.default_stage_access_log_destination_arn != null && var.default_stage_access_log_format != null ? [true] : []

content {
destination_arn = var.default_stage_access_log_destination_arn
format = var.default_stage_access_log_format
Expand All @@ -75,12 +77,13 @@ resource "aws_apigatewayv2_stage" "default" {

dynamic "default_route_settings" {
for_each = length(keys(var.default_route_settings)) == 0 ? [] : [var.default_route_settings]

content {
data_trace_enabled = lookup(default_route_settings.value, "data_trace_enabled", false)
detailed_metrics_enabled = lookup(default_route_settings.value, "detailed_metrics_enabled", false)
logging_level = lookup(default_route_settings.value, "logging_level", null)
throttling_burst_limit = lookup(default_route_settings.value, "throttling_burst_limit", null)
throttling_rate_limit = lookup(default_route_settings.value, "throttling_rate_limit", null)
data_trace_enabled = try(default_route_settings.value.data_trace_enabled, false)
detailed_metrics_enabled = try(default_route_settings.value.detailed_metrics_enabled, false)
logging_level = try(default_route_settings.value.logging_level, null)
throttling_burst_limit = try(default_route_settings.value.throttling_burst_limit, null)
throttling_rate_limit = try(default_route_settings.value.throttling_rate_limit, null)
}
}

Expand All @@ -89,11 +92,11 @@ resource "aws_apigatewayv2_stage" "default" {
# for_each = var.create_routes_and_integrations ? var.integrations : {}
# content {
# route_key = route_settings.key
# data_trace_enabled = lookup(route_settings.value, "data_trace_enabled", null)
# detailed_metrics_enabled = lookup(route_settings.value, "detailed_metrics_enabled", null)
# logging_level = lookup(route_settings.value, "logging_level", null) # Error: error updating API Gateway v2 stage ($default): BadRequestException: Execution logs are not supported on protocolType HTTP
# throttling_burst_limit = lookup(route_settings.value, "throttling_burst_limit", null)
# throttling_rate_limit = lookup(route_settings.value, "throttling_rate_limit", null)
# data_trace_enabled = try(route_settings.value.data_trace_enabled, null)
# detailed_metrics_enabled = try(route_settings.value.detailed_metrics_enabled, null)
# logging_level = try(route_settings.value.logging_level, null) # Error: error updating API Gateway v2 stage ($default): BadRequestException: Execution logs are not supported on protocolType HTTP
# throttling_burst_limit = try(route_settings.value.throttling_burst_limit, null)
# throttling_rate_limit = try(route_settings.value.throttling_rate_limit, null)
# }
# }

Expand Down Expand Up @@ -121,49 +124,51 @@ resource "aws_apigatewayv2_route" "this" {
api_id = aws_apigatewayv2_api.this[0].id
route_key = each.key

api_key_required = lookup(each.value, "api_key_required", null)
authorization_type = lookup(each.value, "authorization_type", "NONE")
authorizer_id = lookup(each.value, "authorizer_id", null)
model_selection_expression = lookup(each.value, "model_selection_expression", null)
operation_name = lookup(each.value, "operation_name", null)
route_response_selection_expression = lookup(each.value, "route_response_selection_expression", null)
api_key_required = try(each.value.api_key_required, null)
authorization_type = try(each.value.authorization_type, "NONE")
authorizer_id = try(aws_apigatewayv2_authorizer.this[each.value.authorizer_key].id, each.value.authorizer_id, null)
model_selection_expression = try(each.value.model_selection_expression, null)
operation_name = try(each.value.operation_name, null)
route_response_selection_expression = try(each.value.route_response_selection_expression, null)
target = "integrations/${aws_apigatewayv2_integration.this[each.key].id}"

# Not sure what structure is allowed for these arguments...
# authorization_scopes = lookup(each.value, "authorization_scopes", null)
# request_models = lookup(each.value, "request_models", null)
# authorization_scopes = try(each.value.authorization_scopes, null)
# request_models = try(each.value.request_models, null)
}

resource "aws_apigatewayv2_integration" "this" {
for_each = var.create && var.create_routes_and_integrations ? var.integrations : {}

api_id = aws_apigatewayv2_api.this[0].id
description = lookup(each.value, "description", null)
description = try(each.value.description, null)

integration_type = lookup(each.value, "integration_type", lookup(each.value, "lambda_arn", "") != "" ? "AWS_PROXY" : "MOCK")
integration_subtype = lookup(each.value, "integration_subtype", null)
integration_method = lookup(each.value, "integration_method", lookup(each.value, "integration_subtype", null) == null ? "POST" : null)
integration_uri = lookup(each.value, "lambda_arn", lookup(each.value, "integration_uri", null))
integration_type = try(each.value.integration_type, try(each.value.lambda_arn, "") != "" ? "AWS_PROXY" : "MOCK")
integration_subtype = try(each.value.integration_subtype, null)
integration_method = try(each.value.integration_method, try(each.value.integration_subtype, null) == null ? "POST" : null)
integration_uri = try(each.value.lambda_arn, try(each.value.integration_uri, null))

connection_type = lookup(each.value, "connection_type", "INTERNET")
connection_id = try(aws_apigatewayv2_vpc_link.this[each.value["vpc_link"]].id, lookup(each.value, "connection_id", null))
connection_type = try(each.value.connection_type, "INTERNET")
connection_id = try(aws_apigatewayv2_vpc_link.this[each.value["vpc_link"]].id, try(each.value.connection_id, null))

payload_format_version = lookup(each.value, "payload_format_version", null)
timeout_milliseconds = lookup(each.value, "timeout_milliseconds", null)
passthrough_behavior = lookup(each.value, "passthrough_behavior", null)
content_handling_strategy = lookup(each.value, "content_handling_strategy", null)
credentials_arn = lookup(each.value, "credentials_arn", null)
payload_format_version = try(each.value.payload_format_version, null)
timeout_milliseconds = try(each.value.timeout_milliseconds, null)
passthrough_behavior = try(each.value.passthrough_behavior, null)
content_handling_strategy = try(each.value.content_handling_strategy, null)
credentials_arn = try(each.value.credentials_arn, null)
request_parameters = try(jsondecode(each.value["request_parameters"]), each.value["request_parameters"], null)

dynamic "tls_config" {
for_each = flatten([try(jsondecode(each.value["tls_config"]), each.value["tls_config"], [])])

content {
server_name_to_verify = tls_config.value["server_name_to_verify"]
}
}

dynamic "response_parameters" {
for_each = flatten([try(jsondecode(each.value["response_parameters"]), each.value["response_parameters"], [])])

content {
status_code = response_parameters.value["status_code"]
mappings = response_parameters.value["mappings"]
Expand All @@ -175,13 +180,35 @@ resource "aws_apigatewayv2_integration" "this" {
}
}

# Authorizers
resource "aws_apigatewayv2_authorizer" "this" {
for_each = var.create && var.create_routes_and_integrations ? var.authorizers : {}

api_id = aws_apigatewayv2_api.this[0].id

authorizer_type = try(each.value.authorizer_type, null)
identity_sources = try(flatten([each.value.identity_sources]), null)
name = try(each.value.name, null)
authorizer_uri = try(each.value.authorizer_uri, null)
authorizer_payload_format_version = try(each.value.authorizer_payload_format_version, null)

dynamic "jwt_configuration" {
for_each = length(try(each.value.audience, [each.value.issuer], [])) > 0 ? [true] : []

content {
audience = try(each.value.audience, null)
issuer = try(each.value.issuer, null)
}
}
}

# VPC Link (Private API)
resource "aws_apigatewayv2_vpc_link" "this" {
for_each = var.create && var.create_vpc_link ? var.vpc_links : {}

name = lookup(each.value, "name", each.key)
name = try(each.value.name, each.key)
security_group_ids = each.value["security_group_ids"]
subnet_ids = each.value["subnet_ids"]

tags = merge(var.tags, var.vpc_link_tags, lookup(each.value, "tags", {}))
tags = merge(var.tags, var.vpc_link_tags, try(each.value.tags, {}))
}
30 changes: 15 additions & 15 deletions outputs.tf
Original file line number Diff line number Diff line change
@@ -1,68 +1,68 @@
output "apigatewayv2_api_id" {
description = "The API identifier"
value = element(concat(aws_apigatewayv2_api.this.*.id, [""]), 0)
value = try(aws_apigatewayv2_api.this[0].id, "")
}

output "apigatewayv2_api_api_endpoint" {
description = "The URI of the API"
value = element(concat(aws_apigatewayv2_api.this.*.api_endpoint, [""]), 0)
value = try(aws_apigatewayv2_api.this[0].api_endpoint, "")
}

output "apigatewayv2_api_arn" {
description = "The ARN of the API"
value = element(concat(aws_apigatewayv2_api.this.*.arn, [""]), 0)
value = try(aws_apigatewayv2_api.this[0].arn, "")
}

output "apigatewayv2_api_execution_arn" {
description = "The ARN prefix to be used in an aws_lambda_permission's source_arn attribute or in an aws_iam_policy to authorize access to the @connections API."
value = element(concat(aws_apigatewayv2_api.this.*.execution_arn, [""]), 0)
value = try(aws_apigatewayv2_api.this[0].execution_arn, "")
}

# default stage
output "default_apigatewayv2_stage_id" {
description = "The default stage identifier"
value = element(concat(aws_apigatewayv2_stage.default.*.id, [""]), 0)
value = try(aws_apigatewayv2_stage.default[0].id, "")
}

output "default_apigatewayv2_stage_arn" {
description = "The default stage ARN"
value = element(concat(aws_apigatewayv2_stage.default.*.arn, [""]), 0)
value = try(aws_apigatewayv2_stage.default[0].arn, "")
}

output "default_apigatewayv2_stage_execution_arn" {
description = "The ARN prefix to be used in an aws_lambda_permission's source_arn attribute or in an aws_iam_policy to authorize access to the @connections API."
value = element(concat(aws_apigatewayv2_stage.default.*.execution_arn, [""]), 0)
value = try(aws_apigatewayv2_stage.default[0].execution_arn, "")
}

output "default_apigatewayv2_stage_invoke_url" {
description = "The URL to invoke the API pointing to the stage"
value = element(concat(aws_apigatewayv2_stage.default.*.invoke_url, [""]), 0)
value = try(aws_apigatewayv2_stage.default[0].invoke_url, "")
}

output "default_apigatewayv2_stage_domain_name" {
description = "Domain name of the stage (useful for CloudFront distribution)"
value = replace(element(concat(aws_apigatewayv2_stage.default.*.invoke_url, [""]), 0), "/^https?://([^/]*).*/", "$1")
value = replace(try(aws_apigatewayv2_stage.default[0].invoke_url, ""), "/^https?://([^/]*).*/", "$1")
}

# domain name
output "apigatewayv2_domain_name_id" {
description = "The domain name identifier"
value = element(concat(aws_apigatewayv2_domain_name.this.*.id, [""]), 0)
value = try(aws_apigatewayv2_domain_name.this[0].id, "")
}

output "apigatewayv2_domain_name_arn" {
description = "The ARN of the domain name"
value = element(concat(aws_apigatewayv2_domain_name.this.*.arn, [""]), 0)
value = try(aws_apigatewayv2_domain_name.this[0].arn, "")
}

output "apigatewayv2_domain_name_api_mapping_selection_expression" {
description = "The API mapping selection expression for the domain name"
value = element(concat(aws_apigatewayv2_domain_name.this.*.api_mapping_selection_expression, [""]), 0)
value = try(aws_apigatewayv2_domain_name.this[0].api_mapping_selection_expression, "")
}

output "apigatewayv2_domain_name_configuration" {
description = "The domain name configuration"
value = element(concat(aws_apigatewayv2_domain_name.this.*.domain_name_configuration, [""]), 0)
value = try(aws_apigatewayv2_domain_name.this[0].domain_name_configuration, "")
}

output "apigatewayv2_domain_name_target_domain_name" {
Expand All @@ -78,13 +78,13 @@ output "apigatewayv2_domain_name_hosted_zone_id" {
# api mapping
output "apigatewayv2_api_mapping_id" {
description = "The API mapping identifier."
value = element(concat(aws_apigatewayv2_api_mapping.this.*.id, [""]), 0)
value = try(aws_apigatewayv2_api_mapping.this[0].id, "")
}

# route
# output "apigatewayv2_route_id" {
# description = "The default route identifier."
# value = element(concat(aws_apigatewayv2_route.this.*.id, [""]), 0)
# value = try(aws_apigatewayv2_route.this[0].id, "")
# }

# VPC link
Expand Down
7 changes: 7 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,13 @@ variable "integrations" {
default = {}
}

# authorrizers
variable "authorizers" {
description = "Map of API gateway authorizers"
type = map(any)
default = {}
}

# vpc link
variable "vpc_links" {
description = "Map of VPC Links details to create"
Expand Down