Skip to content

Commit

Permalink
feat: Allow validating the certificate with CloudFlare (#101)
Browse files Browse the repository at this point in the history
  • Loading branch information
antonbabenko authored Jan 14, 2022
1 parent 02ca0fa commit a9a3c23
Show file tree
Hide file tree
Showing 13 changed files with 206 additions and 10 deletions.
33 changes: 31 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -92,7 +119,7 @@ module "acm" {

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

## Providers
Expand All @@ -119,15 +146,17 @@ No modules.
|------|-------------|------|---------|:--------:|
| <a name="input_certificate_transparency_logging_preference"></a> [certificate\_transparency\_logging\_preference](#input\_certificate\_transparency\_logging\_preference) | Specifies whether certificate details should be added to a certificate transparency log | `bool` | `true` | no |
| <a name="input_create_certificate"></a> [create\_certificate](#input\_create\_certificate) | Whether to create ACM certificate | `bool` | `true` | no |
| <a name="input_create_route53_records"></a> [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 |
| <a name="input_dns_ttl"></a> [dns\_ttl](#input\_dns\_ttl) | The TTL of DNS recursive resolvers to cache information about this record. | `number` | `60` | no |
| <a name="input_domain_name"></a> [domain\_name](#input\_domain\_name) | A domain name for which the certificate should be issued | `string` | `""` | no |
| <a name="input_subject_alternative_names"></a> [subject\_alternative\_names](#input\_subject\_alternative\_names) | A list of domains that should be SANs in the issued certificate | `list(string)` | `[]` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | A mapping of tags to assign to the resource | `map(string)` | `{}` | no |
| <a name="input_validate_certificate"></a> [validate\_certificate](#input\_validate\_certificate) | Whether to validate certificate by creating Route53 record | `bool` | `true` | no |
| <a name="input_validation_allow_overwrite_records"></a> [validation\_allow\_overwrite\_records](#input\_validation\_allow\_overwrite\_records) | Whether to allow overwrite of Route53 records | `bool` | `true` | no |
| <a name="input_validation_method"></a> [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 |
| <a name="input_validation_record_fqdns"></a> [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 |
| <a name="input_wait_for_validation"></a> [wait\_for\_validation](#input\_wait\_for\_validation) | Whether to wait for the validation to complete | `bool` | `true` | no |
| <a name="input_zone_id"></a> [zone\_id](#input\_zone\_id) | The ID of the hosted zone to contain this record. | `string` | `""` | no |
| <a name="input_zone_id"></a> [zone\_id](#input\_zone\_id) | The ID of the hosted zone to contain this record. Required when validating via Route53 | `string` | `""` | no |

## Outputs

Expand Down
63 changes: 63 additions & 0 deletions examples/complete-dns-validation-with-cloudflare/README.md
Original file line number Diff line number Diff line change
@@ -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.

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

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

## Providers

| Name | Version |
|------|---------|
| <a name="provider_cloudflare"></a> [cloudflare](#provider\_cloudflare) | >= 3.4.0 |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_acm"></a> [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 |
|------|-------------|
| <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/complete-dns-validation-with-cloudflare/main.tf
Original file line number Diff line number Diff line change
@@ -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
}
29 changes: 29 additions & 0 deletions examples/complete-dns-validation-with-cloudflare/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.
14 changes: 14 additions & 0 deletions examples/complete-dns-validation-with-cloudflare/versions.tf
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
2 changes: 1 addition & 1 deletion examples/complete-dns-validation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Note that this example may create resources which cost money. Run `terraform des

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

## Providers
Expand Down
2 changes: 1 addition & 1 deletion examples/complete-dns-validation/versions.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
terraform {
required_version = ">= 0.12.26"
required_version = ">= 0.13.1"

required_providers {
aws = {
Expand Down
2 changes: 1 addition & 1 deletion examples/complete-email-validation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Note that this example may create resources which cost money. Run `terraform des

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

## Providers
Expand Down
2 changes: 1 addition & 1 deletion examples/complete-email-validation/versions.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
terraform {
required_version = ">= 0.12.26"
required_version = ">= 0.13.1"

required_providers {
aws = {
Expand Down
4 changes: 2 additions & 2 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand All @@ -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])
}
19 changes: 18 additions & 1 deletion variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ""
}
Expand Down
2 changes: 1 addition & 1 deletion versions.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
terraform {
required_version = ">= 0.12.26"
required_version = ">= 0.13.1"

required_providers {
aws = {
Expand Down

0 comments on commit a9a3c23

Please sign in to comment.