Skip to content
Closed
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
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,37 @@ module "acm" {

```

## Usage with Route53 DNS validation & different zones

```hcl
module "acm" {
source = "terraform-aws-modules/acm/aws"
version = "~> 3.3"

domain_name = "my-domain.com"
zone_id = "Z2ES7B9AZ6SHAE"

subject_alternative_names = [
"*.my-domain.com",
"app.sub.my-domain.com",
{
name = "my-other-domain.com"
zone_id = "Z06730ESICABNX"
},
{
name = "*.my-other-domain.com"
zone_id = "Z06730ESICABNX"
}
]

wait_for_validation = true

tags = {
Name = "my-domain.com"
}
}
```

## Examples

- [Complete example with DNS validation (recommended)](https://github.com/terraform-aws-modules/terraform-aws-acm/tree/master/examples/complete-dns-validation)
Expand Down
59 changes: 59 additions & 0 deletions examples/dns-validation-multiple-zones/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# ACM example with Route53 DNS validation and multiple zones

Configuration in this directory creates a new ACM certificate which has SAN's that need a different Route53 Zone compared to `var.domain_name` to be validated.


## Usage

To run this example you need to execute:

```bash
$ terraform init
$ terraform plan
$ terraform apply
```

Note that this example may create resources which cost money. Run `terraform destroy` when you don't need these resources.

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 0.12.26 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 2.53 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 2.53 |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_acm"></a> [acm](#module\_acm) | ../../ | n/a |

## Resources

| Name | Type |
|------|------|
| [aws_route53_zone.this](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/data-sources/route53_zone) | data source |

## Inputs

No inputs.

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_acm_certificate_arn"></a> [acm\_certificate\_arn](#output\_acm\_certificate\_arn) | The ARN of the certificate |
| <a name="output_acm_certificate_domain_validation_options"></a> [acm\_certificate\_domain\_validation\_options](#output\_acm\_certificate\_domain\_validation\_options) | A list of attributes to feed into other resources to complete certificate validation. Can have more than one element, e.g. if SANs are defined. Only set if DNS-validation was used. |
| <a name="output_acm_certificate_validation_emails"></a> [acm\_certificate\_validation\_emails](#output\_acm\_certificate\_validation\_emails) | A list of addresses that received a validation E-Mail. Only set if EMAIL-validation was used. |
| <a name="output_distinct_domain_names"></a> [distinct\_domain\_names](#output\_distinct\_domain\_names) | List of distinct domains names used for the validation. |
| <a name="output_validation_domains"></a> [validation\_domains](#output\_validation\_domains) | List of distinct domain validation options. This is useful if subject alternative names contain wildcards. |
| <a name="output_validation_route53_record_fqdns"></a> [validation\_route53\_record\_fqdns](#output\_validation\_route53\_record\_fqdns) | List of FQDNs built using the zone domain and name. |
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
44 changes: 44 additions & 0 deletions examples/dns-validation-multiple-zones/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
locals {
primary_domain = "terraform-aws-modules.modules.tf"
extra_domain = "terraform-aws-modules.extra-modules.tf"

# Removing trailing dot from domain - just to be sure :)
primary_domain_name = trimsuffix(local.primary_domain, ".")
extra_domain_name = trimsuffix(local.extra_domain, ".")
}

data "aws_route53_zone" "primary_domain" {
name = local.primary_domain_name
private_zone = false
}

data "aws_route53_zone" "extra_domain" {
name = local.extra_domain_name
private_zone = false
}


module "acm" {
source = "../../"

domain_name = local.primary_domain_name
zone_id = data.aws_route53_zone.primary_domain.zone_id

subject_alternative_names = [
"*.${local.primary_domain_name}",
{
name = "alerts.${local.extra_domain_name}"
zone_id = data.aws_route53_zone.extra_domain.zone_id
},
{
name = "*.alerts.${local.extra_domain_name}"
zone_id = data.aws_route53_zone.extra_domain.zone_id
}
]

wait_for_validation = true

tags = {
Name = local.primary_domain_name
}
}
29 changes: 29 additions & 0 deletions examples/dns-validation-multiple-zones/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
output "acm_certificate_arn" {
description = "The ARN of the certificate"
value = module.acm.acm_certificate_arn
}

output "acm_certificate_domain_validation_options" {
description = "A list of attributes to feed into other resources to complete certificate validation. Can have more than one element, e.g. if SANs are defined. Only set if DNS-validation was used."
value = module.acm.acm_certificate_domain_validation_options
}

output "acm_certificate_validation_emails" {
description = "A list of addresses that received a validation E-Mail. Only set if EMAIL-validation was used."
value = module.acm.acm_certificate_validation_emails
}

output "validation_route53_record_fqdns" {
description = "List of FQDNs built using the zone domain and name."
value = module.acm.validation_route53_record_fqdns
}

output "distinct_domain_names" {
description = "List of distinct domains names used for the validation."
value = module.acm.distinct_domain_names
}

output "validation_domains" {
description = "List of distinct domain validation options. This is useful if subject alternative names contain wildcards."
value = module.acm.validation_domains
}
Empty file.
10 changes: 10 additions & 0 deletions examples/dns-validation-multiple-zones/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
terraform {
required_version = ">= 0.12.26"

required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.53"
}
}
}
33 changes: 28 additions & 5 deletions main.tf
Original file line number Diff line number Diff line change
@@ -1,10 +1,33 @@
locals {
create_certificate = var.create_certificate && var.putin_khuylo

# Normalize var.subject_alternative_names to a list of maps: [{name = NAME, zone_id = ZONE_ID}]
## var.subject_alternative_names is a list of mixed elements: Strings and Maps of Strings
## string elements use the string as the "name" and use var.zone_id as their "zone_id"
## map elements passthrough their "name" and "zone_id" values (if zone_id not specified use var.zone_id)
subject_alternative_names = [
for element in var.subject_alternative_names :
{
name = try(tostring(element["name"]), tostring(element))
zone_id = try(tostring(element["zone_id"]), var.zone_id)
}
]

# Create a map from domain name (minus wildcard) to zone id
## The extra flatten([]) is to resolve a bug in terraform 0.12.26 (keeping backwards compatibility)
## https://github.com/hashicorp/terraform/issues/22404
domainname_to_zoneid = merge(flatten([[
for element in concat([{ name = var.domain_name, zone_id = var.zone_id }], local.subject_alternative_names) :
{
replace(element.name, "*.", "") = element.zone_id
}
]])...)

# Get distinct list of domains and SANs
distinct_domain_names = distinct(
[for s in concat([var.domain_name], var.subject_alternative_names) : replace(s, "*.", "")]
)
distinct_domain_names = distinct([
for s in concat([var.domain_name], local.subject_alternative_names[*].name) :
replace(s, "*.", "")
])

# Get the list of distinct domain_validation_options, with wildcard
# domain names replaced by the domain name
Expand All @@ -19,7 +42,7 @@ resource "aws_acm_certificate" "this" {
count = local.create_certificate ? 1 : 0

domain_name = var.domain_name
subject_alternative_names = var.subject_alternative_names
subject_alternative_names = local.subject_alternative_names[*].name
validation_method = var.validation_method

options {
Expand All @@ -45,7 +68,7 @@ resource "aws_acm_certificate" "this" {
resource "aws_route53_record" "validation" {
count = local.create_certificate && var.validation_method == "DNS" && var.create_route53_records && var.validate_certificate ? length(local.distinct_domain_names) : 0

zone_id = var.zone_id
zone_id = local.domainname_to_zoneid[element(local.validation_domains, count.index)["domain_name"]]
name = element(local.validation_domains, count.index)["resource_record_name"]
type = element(local.validation_domains, count.index)["resource_record_type"]
ttl = var.dns_ttl
Expand Down
2 changes: 1 addition & 1 deletion variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ variable "domain_name" {

variable "subject_alternative_names" {
description = "A list of domains that should be SANs in the issued certificate"
type = list(string)
type = any # list(string | map(string))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a belief that this change won't work with terragrunt because of type any. There is a similar issue in Route53 module.

Could you change the type from list(string) to list(map(string)) to prevent the issue?

PS: I have not executed this code yet.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we change from any to list(map(string)) it will no-longer be a backwards compatible change for pure-terraform as they currently provide a list(string).

if we keep the any and follow the terragrunt workaround it will be backwards compatible for pure-terraform but not for terragrunt.

if backwards compatibility is required for both pure-terraform & terragrunt the vars interface will need to be changed (something like a 2nd optional list of zone_ids but this isnt clean/reliable) or we bump major version to use list(map(string)).

if we going to bump the major version to use list(map(string)), do we want to consider any other changes at the same time?

current user input:

subject_alternative_names = [
  "subdomain.mydomain.com",
  "www.subdomain.mydomain.com",
]

user input if list(map(string)) is required but for the same result as above:

subject_alternative_names = [
  {name = "subdomain.mydomain.com"},
  {name = "www.subdomain.mydomain.com"},
]

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi @antonbabenko , have you had a chance to go over my previous reply & which direction we want to head?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry that it takes more time to process these PRs than one would expect.

I looked into #108 a few days ago, and I think the feature that this PR (#100) adds should be considered and implemented after it.

The main reason to order PRs like this is that users may want to create records using different instances of the providers (zone_id + provider). It will be easier to implement that way and update examples to show a variety of combinations.

default = []
}

Expand Down