From 54e54221403d73e1cb081c910058bbc600d2e0fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Mart=C3=ADn=20Medina?= Date: Tue, 13 Aug 2024 02:42:54 +0200 Subject: [PATCH] feat: Allow multiple domains in a single certificate (#149) Co-authored-by: Andres Montalban --- README.md | 1 + examples/complete-dns-validation/README.md | 9 +++- examples/complete-dns-validation/main.tf | 48 ++++++++++++++++++- examples/complete-dns-validation/variables.tf | 17 +++++++ main.tf | 2 +- variables.tf | 6 +++ wrappers/main.tf | 1 + 7 files changed, 80 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 83764a2..1f7e009 100644 --- a/README.md +++ b/README.md @@ -224,6 +224,7 @@ No modules. | [validation\_timeout](#input\_validation\_timeout) | Define maximum timeout to wait for the validation to complete | `string` | `null` | no | | [wait\_for\_validation](#input\_wait\_for\_validation) | Whether to wait for the validation to complete | `bool` | `true` | no | | [zone\_id](#input\_zone\_id) | The ID of the hosted zone to contain this record. Required when validating via Route53 | `string` | `""` | no | +| [zones](#input\_zones) | Map containing the Route53 Zone IDs for additional domains. | `map(string)` | `{}` | no | ## Outputs diff --git a/examples/complete-dns-validation/README.md b/examples/complete-dns-validation/README.md index c89c825..f316577 100644 --- a/examples/complete-dns-validation/README.md +++ b/examples/complete-dns-validation/README.md @@ -37,6 +37,7 @@ Note that this example may create resources which cost money. Run `terraform des | Name | Source | Version | |------|--------|---------| | [acm](#module\_acm) | ../../ | n/a | +| [acm\_multi\_domain](#module\_acm\_multi\_domain) | ../../ | n/a | | [acm\_only](#module\_acm\_only) | ../../ | n/a | | [route53\_records\_only](#module\_route53\_records\_only) | ../../ | n/a | @@ -44,12 +45,18 @@ Note that this example may create resources which cost money. Run `terraform des | Name | Type | |------|------| +| [aws_route53_zone.extra](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_zone) | resource | | [aws_route53_zone.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_zone) | resource | +| [aws_route53_zone.extra](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source | | [aws_route53_zone.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source | ## Inputs -No inputs. +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [domain](#input\_domain) | Domain to be used for the tests | `string` | `"terraform-aws-modules.modules.tf"` | no | +| [extra\_domain](#input\_extra\_domain) | Extra domain to be used in acm\_multi\_domain module | `string` | `"extra.terraform-aws-modules.modules.tf"` | no | +| [use\_existing\_route53\_zone](#input\_use\_existing\_route53\_zone) | Use existing (via data source) or create new zone (will fail validation, if zone is not reachable) | `bool` | `true` | no | ## Outputs diff --git a/examples/complete-dns-validation/main.tf b/examples/complete-dns-validation/main.tf index d5efb97..978c64d 100644 --- a/examples/complete-dns-validation/main.tf +++ b/examples/complete-dns-validation/main.tf @@ -1,8 +1,9 @@ locals { # Use existing (via data source) or create new zone (will fail validation, if zone is not reachable) - use_existing_route53_zone = true + use_existing_route53_zone = var.use_existing_route53_zone - domain = "terraform-aws-modules.modules.tf" + domain = var.domain + extra_domain = var.extra_domain # Removing trailing dot from domain - just to be sure :) domain_name = trimsuffix(local.domain, ".") @@ -103,3 +104,46 @@ module "route53_records_only" { acm_certificate_domain_validation_options = module.acm_only.acm_certificate_domain_validation_options } + +############################################################################### +# Example 3: +# Single certificate with multiple domains from different Route53 hosted zones. +# Useful when using the certificate for CloudFront, which only support a +# single certificate per distribution. +############################################################################### + +data "aws_route53_zone" "extra" { + count = local.use_existing_route53_zone ? 1 : 0 + + name = local.extra_domain + private_zone = false +} + +resource "aws_route53_zone" "extra" { + count = !local.use_existing_route53_zone ? 1 : 0 + + name = local.extra_domain +} + +module "acm_multi_domain" { + source = "../../" + + domain_name = local.domain_name + zone_id = local.zone_id + + subject_alternative_names = [ + "*.alerts.${local.domain_name}", + "new.sub.${local.domain_name}", + local.extra_domain, + "*.alerts.${local.extra_domain}", + "new.sub.${local.extra_domain}", + ] + + validation_method = "DNS" + + zones = { + (local.extra_domain) = try(data.aws_route53_zone.extra[0].zone_id, aws_route53_zone.extra[0].zone_id), + "alerts.${local.extra_domain}" = try(data.aws_route53_zone.extra[0].zone_id, aws_route53_zone.extra[0].zone_id), + "new.sub.${local.extra_domain}" = try(data.aws_route53_zone.extra[0].zone_id, aws_route53_zone.extra[0].zone_id) + } +} diff --git a/examples/complete-dns-validation/variables.tf b/examples/complete-dns-validation/variables.tf index e69de29..09864ba 100644 --- a/examples/complete-dns-validation/variables.tf +++ b/examples/complete-dns-validation/variables.tf @@ -0,0 +1,17 @@ +variable "use_existing_route53_zone" { + description = "Use existing (via data source) or create new zone (will fail validation, if zone is not reachable)" + type = bool + default = true +} + +variable "domain" { + description = "Domain to be used for the tests" + type = string + default = "terraform-aws-modules.modules.tf" +} + +variable "extra_domain" { + description = "Extra domain to be used in acm_multi_domain module" + type = string + default = "extra.terraform-aws-modules.modules.tf" +} diff --git a/main.tf b/main.tf index 5f1894c..9c044fc 100644 --- a/main.tf +++ b/main.tf @@ -47,7 +47,7 @@ resource "aws_acm_certificate" "this" { resource "aws_route53_record" "validation" { count = (local.create_certificate || local.create_route53_records_only) && var.validation_method == "DNS" && var.create_route53_records && (var.validate_certificate || local.create_route53_records_only) ? length(local.distinct_domain_names) : 0 - zone_id = var.zone_id + zone_id = lookup(var.zones, element(local.validation_domains, count.index)["domain_name"], var.zone_id) name = element(local.validation_domains, count.index)["resource_record_name"] type = element(local.validation_domains, count.index)["resource_record_type"] ttl = var.dns_ttl diff --git a/variables.tf b/variables.tf index 5664e57..6c0e56d 100644 --- a/variables.tf +++ b/variables.tf @@ -87,6 +87,12 @@ variable "zone_id" { default = "" } +variable "zones" { + description = "Map containing the Route53 Zone IDs for additional domains." + type = map(string) + default = {} +} + variable "tags" { description = "A mapping of tags to assign to the resource" type = map(string) diff --git a/wrappers/main.tf b/wrappers/main.tf index 108f4e1..688abb0 100644 --- a/wrappers/main.tf +++ b/wrappers/main.tf @@ -23,4 +23,5 @@ module "wrapper" { validation_timeout = try(each.value.validation_timeout, var.defaults.validation_timeout, null) wait_for_validation = try(each.value.wait_for_validation, var.defaults.wait_for_validation, true) zone_id = try(each.value.zone_id, var.defaults.zone_id, "") + zones = try(each.value.zones, var.defaults.zones, {}) }