diff --git a/examples/default/main.tf b/examples/default/main.tf index 7d620b0..492ef0d 100644 --- a/examples/default/main.tf +++ b/examples/default/main.tf @@ -4,24 +4,21 @@ provider "aws" { provider "aws" { region = "us-east-1" - alias = "certificate_provider" + alias = "certificate_provider" } -data "aws_vpc" "main" { - default = true -} - -data "aws_subnet_ids" "main" { - vpc_id = data.aws_vpc.main.id +resource "aws_route53_zone" "main" { + name = "example.com" } module "static-example" { - source = "../../" + source = "../../" providers = { aws.certificate_provider = aws.certificate_provider } - name_prefix = "static-example" - hosted_zone_name = "example.com" - site_name = "static-example.example.com" + name_prefix = "static-example" + domain_zones = { + "static-example.example.com" = aws_route53_zone.main.id + } } diff --git a/examples/default/versions.tf b/examples/default/versions.tf index ac97c6a..e469a70 100644 --- a/examples/default/versions.tf +++ b/examples/default/versions.tf @@ -1,4 +1,8 @@ terraform { required_version = ">= 0.12" + + required_providers { + aws = ">= 2.65.0" + } } diff --git a/main.tf b/main.tf index b84e10d..0f2c7cc 100644 --- a/main.tf +++ b/main.tf @@ -3,38 +3,60 @@ # ------------------------------------------------------------------------------ provider "aws" { # Module expects aws.certificate_provider set to us-east-1 to be passed in via the "providers" argument - alias = "certificate_provider" + alias = "certificate_provider" } data "aws_caller_identity" "current-account" {} +locals { + validation_options_by_domain_name = { for opt in aws_acm_certificate.cert_website.domain_validation_options : opt.domain_name => opt } + all_domains_static = { for obj in concat([var.domain_name], var.subject_alternative_names) : obj.name => obj } + all_domains_dynamic = { for name, v in local.all_domains_static : name => merge(v, { + /* + // NOTE: `domain_validation_options` may reference stale data due to issues with the AWS provider, + // so we default to a known value if this is the case. + */ + validation_options = lookup(local.validation_options_by_domain_name, name, values(local.validation_options_by_domain_name)[0]) + zone_id = data.aws_route53_zone.zone[name].id + }) + } +} + +data "aws_route53_zone" "zone" { + for_each = local.all_domains_static + name = each.value.zone +} + resource "aws_acm_certificate" "cert_website" { - domain_name = var.site_name - validation_method = "DNS" - provider = aws.certificate_provider - tags = var.tags + domain_name = var.domain_name.name + validation_method = "DNS" + provider = aws.certificate_provider + subject_alternative_names = [for obj in var.subject_alternative_names : obj.name] + tags = var.tags lifecycle { create_before_destroy = true } } -data "aws_route53_zone" "main" { - name = var.hosted_zone_name -} - resource "aws_route53_record" "cert_website_validation" { - name = aws_acm_certificate.cert_website.domain_validation_options.0.resource_record_name - type = aws_acm_certificate.cert_website.domain_validation_options.0.resource_record_type - zone_id = data.aws_route53_zone.main.id - records = [aws_acm_certificate.cert_website.domain_validation_options.0.resource_record_value] - ttl = 60 + depends_on = [aws_acm_certificate.cert_website] + for_each = local.all_domains_static + name = local.all_domains_dynamic[each.key].validation_options.resource_record_name + type = local.all_domains_dynamic[each.key].validation_options.resource_record_type + records = [local.all_domains_dynamic[each.key].validation_options.resource_record_value] + zone_id = local.all_domains_dynamic[each.key].zone_id + ttl = 60 + allow_overwrite = true } resource "aws_acm_certificate_validation" "main" { certificate_arn = aws_acm_certificate.cert_website.arn - validation_record_fqdns = [aws_route53_record.cert_website_validation.fqdn] provider = aws.certificate_provider + validation_record_fqdns = values(aws_route53_record.cert_website_validation).*.fqdn + timeouts { + create = var.certificate_validation_timeout + } } data "aws_s3_bucket" "website_bucket" { @@ -82,7 +104,7 @@ resource "aws_cloudfront_distribution" "s3_distribution" { enabled = true is_ipv6_enabled = true default_root_object = "index.html" - aliases = [aws_acm_certificate.cert_website.domain_name] + aliases = sort(keys(local.all_domains_static)) custom_error_response { error_code = 404 @@ -136,11 +158,11 @@ resource "aws_cloudfront_distribution" "s3_distribution" { } } -resource "aws_route53_record" "wwww_a" { - name = "${var.site_name}." - type = "A" - zone_id = data.aws_route53_zone.main.id - +resource "aws_route53_record" "www_a" { + for_each = local.all_domains_static + name = "${each.key}." + type = "A" + zone_id = data.aws_route53_zone.zone[each.key].id alias { name = aws_cloudfront_distribution.s3_distribution.domain_name zone_id = aws_cloudfront_distribution.s3_distribution.hosted_zone_id diff --git a/variables.tf b/variables.tf index 427ae9e..d06d9e4 100644 --- a/variables.tf +++ b/variables.tf @@ -6,11 +6,6 @@ variable "name_prefix" { type = string } -variable "hosted_zone_name" { - description = "The name of the hosted zone in which to register this site" - type = string -} - variable "bucket_versioning" { description = "(Optional) Enable versioning. Once you version-enable a bucket, it can never return to an unversioned state. You can, however, suspend versioning on that bucket." type = bool @@ -23,9 +18,14 @@ variable "tags" { default = {} } -variable "site_name" { - description = "The name of the certificate and address for the site" - type = string +variable "domain_name" { + description = "A map containing a domain and name of the associated hosted zone. The domain will be associated with the CloudFront distribution and ACM certificate." + type = map(string) +} + +variable "subject_alternative_names" { + description = "A list of maps containing domains and names of their associated hosted zones. The domains will be associated with the CloudFront distribution and ACM certificate." + type = list(map(string)) } variable "use_external_bucket" { @@ -38,4 +38,10 @@ variable "website_bucket" { description = "(Optional) The name of an existing bucket to use - if not set the module will create a bucket" type = string default = "" -} \ No newline at end of file +} + +variable "certificate_validation_timeout" { + description = "(Optional) How long to wait for the certificate to be issued." + type = string + default = "45m" +} diff --git a/versions.tf b/versions.tf index ac97c6a..68589b3 100644 --- a/versions.tf +++ b/versions.tf @@ -1,4 +1,7 @@ - terraform { required_version = ">= 0.12" + + required_providers { + aws = ">= 2.65.0" + } }