From 9aea20fbcc3658268bfdc84a71ced3c79478162f Mon Sep 17 00:00:00 2001 From: Prem Kumar <46669067+pkailasu@users.noreply.github.com> Date: Fri, 13 May 2022 17:45:33 +0800 Subject: [PATCH] Custom domain sub module added (#5) * Refactoring the variables to map * Custom domain module added * pre-commit fixes * added example for variable * enforce TLS1.2 * tf fmt * pre-commit fixes * typo fixed and map updated * ACM Cert provisioning * remove the extra new line Co-authored-by: pre-commit --- examples/apigw_with_usage_plan/main.tf | 49 +++++++++++++++++++------ modules/custom_domain/README.md | 50 ++++++++++++++++++++++++++ modules/custom_domain/main.tf | 31 ++++++++++++++++ modules/custom_domain/outputs.tf | 4 +++ modules/custom_domain/variables.tf | 37 +++++++++++++++++++ modules/custom_domain/versions.tf | 9 +++++ modules/usage_plan/README.md | 5 +-- modules/usage_plan/main.tf | 28 +++++++-------- modules/usage_plan/variables.tf | 22 +++++++++--- 9 files changed, 204 insertions(+), 31 deletions(-) create mode 100644 modules/custom_domain/README.md create mode 100644 modules/custom_domain/main.tf create mode 100644 modules/custom_domain/outputs.tf create mode 100644 modules/custom_domain/variables.tf create mode 100644 modules/custom_domain/versions.tf diff --git a/examples/apigw_with_usage_plan/main.tf b/examples/apigw_with_usage_plan/main.tf index 4cfd532..1b7a0a1 100644 --- a/examples/apigw_with_usage_plan/main.tf +++ b/examples/apigw_with_usage_plan/main.tf @@ -68,16 +68,43 @@ module "api_gateway_usage_plan" { name = "PetStoreSandbox-usage-plan" - stages = [ - { - "stage" : module.api_gateway.aws_api_gateway_stage_name, - "api_id" : module.api_gateway.aws_api_gateway_rest_api_id + stages = { + stage1 = { + stage = module.api_gateway.aws_api_gateway_stage_name + api_id = module.api_gateway.aws_api_gateway_rest_api_id } - ] - api_keys = [ - { "key_name" : "key1", "enabled" : true }, - { "key_name" : "key2", "enabled" : true }, - { "key_name" : "key3", "enabled" : false }, - { "key_name" : "key4", "enabled" : true }, - ] + } + api_keys = { + key1 = { + key_name = "key1" + enabled = true + } + key2 = { + key_name = "key2" + enabled = true + } + key3 = { + key_name = "key3", + enabled = false + } + key4 = { + key_name = "key4", + enabled = true + } + } +} + +module "api_gateway_custom_domain" { + source = "../../../terraform-aws-apigw/modules/custom_domain" + + domain_name = "petstore-apitest.sphdigital.com" + create_acm_cert = true + + path_mappings = { + v1 = { + stage_name = module.api_gateway.aws_api_gateway_stage_name + api_id = module.api_gateway.aws_api_gateway_rest_api_id + base_path = "v1" + } + } } diff --git a/modules/custom_domain/README.md b/modules/custom_domain/README.md new file mode 100644 index 0000000..43adcce --- /dev/null +++ b/modules/custom_domain/README.md @@ -0,0 +1,50 @@ +# Custom domain name for API Gateway + +Provides custom domain name resource for the API Gateway and the mapping of domain name to the api. + +Supports only REGIONAL endpoint for now. + +Provisions option to create ACM certifcation. Cert validation needs to be done offline. + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0 | +| [aws](#requirement\_aws) | ~> 4.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | 4.13.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_acm_certificate.cert](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate) | resource | +| [aws_api_gateway_base_path_mapping.mapping](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_base_path_mapping) | resource | +| [aws_api_gateway_domain_name.domain](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_domain_name) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cert\_arn](#input\_cert\_arn) | Cert ARN. Create ACM cert. create\_acm\_cert and cert\_arn Mutually exclusive. | `string` | `""` | no | +| [create\_acm\_cert](#input\_create\_acm\_cert) | Create ACM cert. create\_acm\_cert and cert\_arn Mutually exclusive. | `bool` | `false` | no | +| [domain\_name](#input\_domain\_name) | Custom domain name | `string` | n/a | yes | +| [path\_mappings](#input\_path\_mappings) | List of stages the usage plan can be used |
map(
object({
api_id = string
stage_name = string
base_path = string
})
)
| n/a | yes | +| [security\_policy](#input\_security\_policy) | TLS Security Policy for the domain | `string` | `"TLS_1_2"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [arn](#output\_arn) | ARN of domain name. | + diff --git a/modules/custom_domain/main.tf b/modules/custom_domain/main.tf new file mode 100644 index 0000000..7c6f80a --- /dev/null +++ b/modules/custom_domain/main.tf @@ -0,0 +1,31 @@ +# Provisioned only for regional types. @todo: Enhance for other types as well +resource "aws_api_gateway_domain_name" "domain" { + domain_name = var.domain_name + regional_certificate_arn = var.cert_arn == "" ? aws_acm_certificate.cert[0].arn : var.cert_arn + security_policy = var.security_policy + + endpoint_configuration { + types = ["REGIONAL"] + } + +} + +resource "aws_api_gateway_base_path_mapping" "mapping" { + for_each = var.path_mappings + + api_id = each.value.api_id + stage_name = each.value.stage_name + base_path = each.value.base_path + domain_name = aws_api_gateway_domain_name.domain.domain_name +} + +resource "aws_acm_certificate" "cert" { + count = var.create_acm_cert && var.cert_arn == "" ? 1 : 0 + + domain_name = var.domain_name + validation_method = "DNS" + + lifecycle { + create_before_destroy = true + } +} diff --git a/modules/custom_domain/outputs.tf b/modules/custom_domain/outputs.tf new file mode 100644 index 0000000..efbdeb3 --- /dev/null +++ b/modules/custom_domain/outputs.tf @@ -0,0 +1,4 @@ +output "arn" { + value = aws_api_gateway_domain_name.domain.arn + description = "ARN of domain name." +} diff --git a/modules/custom_domain/variables.tf b/modules/custom_domain/variables.tf new file mode 100644 index 0000000..192d0b9 --- /dev/null +++ b/modules/custom_domain/variables.tf @@ -0,0 +1,37 @@ +################################################################################ +# variables for Custom domain mapping sub module +################################################################################ + +variable "domain_name" { + description = "Custom domain name" + type = string +} + +variable "security_policy" { + description = "TLS Security Policy for the domain" + type = string + default = "TLS_1_2" +} + +variable "create_acm_cert" { + description = "Create ACM cert. create_acm_cert and cert_arn Mutually exclusive. " + type = bool + default = false +} + +variable "cert_arn" { + description = "Cert ARN. Create ACM cert. create_acm_cert and cert_arn Mutually exclusive." + type = string + default = "" +} + +variable "path_mappings" { + description = "List of stages the usage plan can be used " + type = map( + object({ + api_id = string + stage_name = string + base_path = string + }) + ) +} diff --git a/modules/custom_domain/versions.tf b/modules/custom_domain/versions.tf new file mode 100644 index 0000000..5985968 --- /dev/null +++ b/modules/custom_domain/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.0" + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.0" + } + } +} diff --git a/modules/usage_plan/README.md b/modules/usage_plan/README.md index 441520d..d53ad24 100644 --- a/modules/usage_plan/README.md +++ b/modules/usage_plan/README.md @@ -32,13 +32,14 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [api\_keys](#input\_api\_keys) | List of api keys created and assigned to the usage plan | `list(any)` | `[]` | no | +| [api\_keys](#input\_api\_keys) | List of api keys created and assigned to the usage plan |
map(
object({
key_name = string
enabled = bool
})
)
| `{}` | no | | [default\_tags](#input\_default\_tags) | Default Tags for Auto Scaling Group | `map(string)` | `{}` | no | | [limit](#input\_limit) | The maximum number of requests that can be made in a given time period. | `number` | `5000` | no | | [name](#input\_name) | Usage plan name | `string` | n/a | yes | | [offset](#input\_offset) | The number of requests subtracted from the given limit in the initial time period. | `number` | `2` | no | | [period](#input\_period) | The time period in which the limit applies. Valid values are DAY, WEEK or MONTH. | `string` | `"MONTH"` | no | -| [stages](#input\_stages) | List of stages the usage plan can be used | `list(any)` | n/a | yes | +| [quota\_settings\_unlimited](#input\_quota\_settings\_unlimited) | Specifies whether there is a unlimited quota limit . | `bool` | `false` | no | +| [stages](#input\_stages) | List of stages the usage plan can be used |
map(
object({
api_id = string
stage = string
})
)
| n/a | yes | ## Outputs diff --git a/modules/usage_plan/main.tf b/modules/usage_plan/main.tf index ec0a8bf..7c04aa6 100644 --- a/modules/usage_plan/main.tf +++ b/modules/usage_plan/main.tf @@ -3,10 +3,7 @@ resource "aws_api_gateway_usage_plan" "usage_plan" { description = "Usage plan created for ${var.name}" dynamic "api_stages" { - for_each = [for s in var.stages : { - api_id = s.api_id - stage = s.stage - }] + for_each = var.stages content { api_id = api_stages.value.api_id @@ -15,10 +12,13 @@ resource "aws_api_gateway_usage_plan" "usage_plan" { } - quota_settings { - limit = var.limit - offset = var.offset - period = var.period + dynamic "quota_settings" { + for_each = var.quota_settings_unlimited == true ? [1] : [] + content { + limit = var.limit + offset = var.offset + period = var.period + } } tags = { @@ -27,22 +27,22 @@ resource "aws_api_gateway_usage_plan" "usage_plan" { } resource "aws_api_gateway_api_key" "key" { - for_each = { for api_key in var.api_keys : api_key.key_name => api_key } + for_each = var.api_keys - name = each.key - description = "API Key for ${each.key}" + name = each.value.key_name + description = "API Key for ${each.value.key_name}" enabled = each.value.enabled tags = { - Name = each.key + Name = each.value.key_name } } resource "aws_api_gateway_usage_plan_key" "main" { - for_each = { for api_key in var.api_keys : api_key.key_name => api_key } + for_each = var.api_keys - key_id = aws_api_gateway_api_key.key[each.key].id + key_id = aws_api_gateway_api_key.key[each.value.key_name].id key_type = "API_KEY" usage_plan_id = aws_api_gateway_usage_plan.usage_plan.id } diff --git a/modules/usage_plan/variables.tf b/modules/usage_plan/variables.tf index f147550..5b3fab9 100644 --- a/modules/usage_plan/variables.tf +++ b/modules/usage_plan/variables.tf @@ -16,9 +16,19 @@ variable "default_tags" { variable "stages" { description = "List of stages the usage plan can be used " - type = list(any) + type = map( + object({ + api_id = string + stage = string + }) + ) } +variable "quota_settings_unlimited" { + description = "Specifies whether there is a unlimited quota limit ." + type = bool + default = false +} variable "limit" { description = "The maximum number of requests that can be made in a given time period." @@ -40,7 +50,11 @@ variable "period" { variable "api_keys" { description = "List of api keys created and assigned to the usage plan" - type = list(any) - default = [] - # It is a list of objects with the keyname and enabled flag. ex: [ { "key_name" : "key1", "enabled" : true }] + type = map( + object({ + key_name = string + enabled = bool + }) + ) + default = {} }