diff --git a/README.md b/README.md index ae1aa42..5db1f76 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,32 @@ module "acm" { } ``` +## Usage with external DNS validation (e.g. CloudFlare) + +```hcl +module "acm" { + source = "terraform-aws-modules/acm/aws" + version = "~> 3.0" + + domain_name = "weekly.tf" + zone_id = "b7d259641bf30b89887c943ffc9d2138" + + subject_alternative_names = [ + "*.weekly.tf", + ] + + create_route53_records = false + validation_record_fqdns = [ + "_689571ee9a5f9ec307c512c5d851e25a.weekly.tf", + ] + + tags = { + Name = "weekly.tf" + } +} + +``` + ## [Usage with CloudFront](https://aws.amazon.com/premiumsupport/knowledge-center/install-ssl-cloudfront/) ```hcl @@ -56,6 +82,7 @@ module "acm" { ## Examples - [Complete example with DNS validation (recommended)](https://github.com/terraform-aws-modules/terraform-aws-acm/tree/master/examples/complete-dns-validation) +- [Complete example with DNS validation via external DNS provider (CloudFlare)](https://github.com/terraform-aws-modules/terraform-aws-acm/tree/master/examples/complete-dns-validation-with-cloudflare) - [Complete example with EMAIL validation](https://github.com/terraform-aws-modules/terraform-aws-acm/tree/master/examples/complete-email-validation) ## Conditional creation and validation @@ -92,7 +119,7 @@ module "acm" { | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 0.12.26 | +| [terraform](#requirement\_terraform) | >= 0.13.1 | | [aws](#requirement\_aws) | >= 2.53 | ## Providers @@ -119,6 +146,7 @@ No modules. |------|-------------|------|---------|:--------:| | [certificate\_transparency\_logging\_preference](#input\_certificate\_transparency\_logging\_preference) | Specifies whether certificate details should be added to a certificate transparency log | `bool` | `true` | no | | [create\_certificate](#input\_create\_certificate) | Whether to create ACM certificate | `bool` | `true` | no | +| [create\_route53\_records](#input\_create\_route53\_records) | When validation is set to DNS, define whether to create the DNS records internally via Route53 or externally using any DNS provider | `bool` | `true` | no | | [dns\_ttl](#input\_dns\_ttl) | The TTL of DNS recursive resolvers to cache information about this record. | `number` | `60` | no | | [domain\_name](#input\_domain\_name) | A domain name for which the certificate should be issued | `string` | `""` | no | | [subject\_alternative\_names](#input\_subject\_alternative\_names) | A list of domains that should be SANs in the issued certificate | `list(string)` | `[]` | no | @@ -126,8 +154,9 @@ No modules. | [validate\_certificate](#input\_validate\_certificate) | Whether to validate certificate by creating Route53 record | `bool` | `true` | no | | [validation\_allow\_overwrite\_records](#input\_validation\_allow\_overwrite\_records) | Whether to allow overwrite of Route53 records | `bool` | `true` | no | | [validation\_method](#input\_validation\_method) | Which method to use for validation. DNS or EMAIL are valid, NONE can be used for certificates that were imported into ACM and then into Terraform. | `string` | `"DNS"` | no | +| [validation\_record\_fqdns](#input\_validation\_record\_fqdns) | When validation is set to DNS and the DNS validation records are set externally, provide the fqdns for the validation | `list(string)` | `[]` | 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. | `string` | `""` | no | +| [zone\_id](#input\_zone\_id) | The ID of the hosted zone to contain this record. Required when validating via Route53 | `string` | `""` | no | ## Outputs diff --git a/examples/complete-dns-validation-with-cloudflare/README.md b/examples/complete-dns-validation-with-cloudflare/README.md new file mode 100644 index 0000000..b4ad585 --- /dev/null +++ b/examples/complete-dns-validation-with-cloudflare/README.md @@ -0,0 +1,63 @@ +# Complete ACM example with external CloudFlare DNS validation + +Configuration in this directory creates an ACM certificate (valid for the domain name and wildcard) while the DNS validation is done via an external DNS provider. + +For this example CloudFlare DNS is used but any DNS provider could be used instead. + +This is a complete example which fits most of scenarios. + +## 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. + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.13.1 | +| [aws](#requirement\_aws) | >= 2.53 | +| [cloudflare](#requirement\_cloudflare) | >= 3.4.0 | + +## Providers + +| Name | Version | +|------|---------| +| [cloudflare](#provider\_cloudflare) | >= 3.4.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [acm](#module\_acm) | ../../ | n/a | + +## Resources + +| Name | Type | +|------|------| +| [cloudflare_record.validation](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/record) | resource | +| [cloudflare_zone.this](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/data-sources/zone) | data source | + +## Inputs + +No inputs. + +## Outputs + +| Name | Description | +|------|-------------| +| [acm\_certificate\_arn](#output\_acm\_certificate\_arn) | The ARN of the certificate | +| [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. | +| [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. | +| [distinct\_domain\_names](#output\_distinct\_domain\_names) | List of distinct domains names used for the validation. | +| [validation\_domains](#output\_validation\_domains) | List of distinct domain validation options. This is useful if subject alternative names contain wildcards. | +| [validation\_route53\_record\_fqdns](#output\_validation\_route53\_record\_fqdns) | List of FQDNs built using the zone domain and name. | + diff --git a/examples/complete-dns-validation-with-cloudflare/main.tf b/examples/complete-dns-validation-with-cloudflare/main.tf new file mode 100644 index 0000000..f99a154 --- /dev/null +++ b/examples/complete-dns-validation-with-cloudflare/main.tf @@ -0,0 +1,44 @@ +locals { + domain = "terraform-aws-modules.modules.tf" + + # Removing trailing dot from domain - just to be sure :) + domain_name = trimsuffix(local.domain, ".") +} + +module "acm" { + source = "../../" + + domain_name = local.domain_name + zone_id = data.cloudflare_zone.this.id + + subject_alternative_names = [ + "*.alerts.${local.domain_name}", + "new.sub.${local.domain_name}", + "*.${local.domain_name}", + "alerts.${local.domain_name}", + ] + + create_route53_records = false + validation_record_fqdns = cloudflare_record.validation.*.hostname + + tags = { + Name = local.domain_name + } +} + +resource "cloudflare_record" "validation" { + count = length(module.acm.distinct_domain_names) + + zone_id = data.cloudflare_zone.this.id + name = element(module.acm.validation_domains, count.index)["resource_record_name"] + type = element(module.acm.validation_domains, count.index)["resource_record_type"] + value = replace(element(module.acm.validation_domains, count.index)["resource_record_value"], "/.$/", "") + ttl = 60 + proxied = false + + allow_overwrite = true +} + +data "cloudflare_zone" "this" { + name = local.domain_name +} diff --git a/examples/complete-dns-validation-with-cloudflare/outputs.tf b/examples/complete-dns-validation-with-cloudflare/outputs.tf new file mode 100644 index 0000000..1eb07eb --- /dev/null +++ b/examples/complete-dns-validation-with-cloudflare/outputs.tf @@ -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 +} diff --git a/examples/complete-dns-validation-with-cloudflare/variables.tf b/examples/complete-dns-validation-with-cloudflare/variables.tf new file mode 100644 index 0000000..e69de29 diff --git a/examples/complete-dns-validation-with-cloudflare/versions.tf b/examples/complete-dns-validation-with-cloudflare/versions.tf new file mode 100644 index 0000000..ec2f77a --- /dev/null +++ b/examples/complete-dns-validation-with-cloudflare/versions.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 0.13.1" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 2.53" + } + cloudflare = { + source = "cloudflare/cloudflare" + version = ">= 3.4.0" + } + } +} diff --git a/examples/complete-dns-validation/README.md b/examples/complete-dns-validation/README.md index 60c2eb3..2abeae3 100644 --- a/examples/complete-dns-validation/README.md +++ b/examples/complete-dns-validation/README.md @@ -23,7 +23,7 @@ Note that this example may create resources which cost money. Run `terraform des | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 0.12.26 | +| [terraform](#requirement\_terraform) | >= 0.13.1 | | [aws](#requirement\_aws) | >= 2.53 | ## Providers diff --git a/examples/complete-dns-validation/versions.tf b/examples/complete-dns-validation/versions.tf index 67d15ec..25f85e5 100644 --- a/examples/complete-dns-validation/versions.tf +++ b/examples/complete-dns-validation/versions.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 0.12.26" + required_version = ">= 0.13.1" required_providers { aws = { diff --git a/examples/complete-email-validation/README.md b/examples/complete-email-validation/README.md index ee9823c..2ae55d5 100644 --- a/examples/complete-email-validation/README.md +++ b/examples/complete-email-validation/README.md @@ -36,7 +36,7 @@ Note that this example may create resources which cost money. Run `terraform des | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 0.12.26 | +| [terraform](#requirement\_terraform) | >= 0.13.1 | | [aws](#requirement\_aws) | >= 2.53 | ## Providers diff --git a/examples/complete-email-validation/versions.tf b/examples/complete-email-validation/versions.tf index 67d15ec..25f85e5 100644 --- a/examples/complete-email-validation/versions.tf +++ b/examples/complete-email-validation/versions.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 0.12.26" + required_version = ">= 0.13.1" required_providers { aws = { diff --git a/main.tf b/main.tf index 0adc774..3cf045b 100644 --- a/main.tf +++ b/main.tf @@ -32,7 +32,7 @@ resource "aws_acm_certificate" "this" { } resource "aws_route53_record" "validation" { - count = var.create_certificate && var.validation_method == "DNS" && var.validate_certificate ? length(local.distinct_domain_names) : 0 + count = var.create_certificate && var.validation_method == "DNS" && var.create_route53_records && var.validate_certificate ? length(local.distinct_domain_names) : 0 zone_id = var.zone_id name = element(local.validation_domains, count.index)["resource_record_name"] @@ -53,5 +53,5 @@ resource "aws_acm_certificate_validation" "this" { certificate_arn = aws_acm_certificate.this[0].arn - validation_record_fqdns = aws_route53_record.validation.*.fqdn + validation_record_fqdns = flatten([aws_route53_record.validation.*.fqdn, var.validation_record_fqdns]) } diff --git a/variables.tf b/variables.tf index 4a5c670..42c149a 100644 --- a/variables.tf +++ b/variables.tf @@ -44,10 +44,27 @@ variable "validation_method" { description = "Which method to use for validation. DNS or EMAIL are valid, NONE can be used for certificates that were imported into ACM and then into Terraform." type = string default = "DNS" + + validation { + condition = contains(["DNS", "EMAIL", "NONE"], var.validation_method) + error_message = "Valid values are DNS, EMAIL or NONE." + } +} + +variable "create_route53_records" { + description = "When validation is set to DNS, define whether to create the DNS records internally via Route53 or externally using any DNS provider" + type = bool + default = true +} + +variable "validation_record_fqdns" { + description = "When validation is set to DNS and the DNS validation records are set externally, provide the fqdns for the validation" + type = list(string) + default = [] } variable "zone_id" { - description = "The ID of the hosted zone to contain this record." + description = "The ID of the hosted zone to contain this record. Required when validating via Route53" type = string default = "" } diff --git a/versions.tf b/versions.tf index 67d15ec..25f85e5 100644 --- a/versions.tf +++ b/versions.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 0.12.26" + required_version = ">= 0.13.1" required_providers { aws = {