Skip to content

Commit

Permalink
Refine modules for certs (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
posquit0 authored Nov 17, 2023
1 parent 191c1f9 commit aa7707e
Show file tree
Hide file tree
Showing 14 changed files with 305 additions and 93 deletions.
38 changes: 22 additions & 16 deletions modules/amazon-issued-cert/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@
This module creates following resources.

- `aws_acm_certificate`
- `aws_acm_certificate_validation` (Optional)
- `aws_route53_record` (Optional)

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

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

## Providers

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

## Modules

Expand All @@ -29,39 +31,43 @@ This module creates following resources.
| Name | Type |
|------|------|
| [aws_acm_certificate.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate) | resource |
| [aws_acm_certificate_validation.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation) | resource |
| [aws_acm_certificate_validation.dns](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation) | resource |
| [aws_acm_certificate_validation.email](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation) | resource |
| [aws_route53_record.validation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_subject_name"></a> [subject\_name](#input\_subject\_name) | (Required) A domain name for which the certificate should be issued. | `string` | n/a | yes |
| <a name="input_certificate_transparency_logging_enabled"></a> [certificate\_transparency\_logging\_enabled](#input\_certificate\_transparency\_logging\_enabled) | (Optional) Specifies whether certificate details should be added to a certificate transparency log. | `bool` | `true` | no |
| <a name="input_domain_name"></a> [domain\_name](#input\_domain\_name) | (Required) A domain name for which the certificate should be issued. FQDN (Fully qualified domain name), such as `www.example.com`, that you want to secure with an ACM certificate. Use an asterisk (*) to create a wildcard certificate that protects several sites in the same domain. | `string` | n/a | yes |
| <a name="input_name"></a> [name](#input\_name) | (Required) The name of the certificate. | `string` | n/a | yes |
| <a name="input_certificate_transparency_logging_enabled"></a> [certificate\_transparency\_logging\_enabled](#input\_certificate\_transparency\_logging\_enabled) | (Optional) Whether to add the certificate to a certificate transparency log. Transparency makes it possible to detect SSL/TLS certificates that have been mistakenly or maliciously issued. Certificates that have not been logged typically produce an error message in a browser. Defaults to `true`. | `bool` | `true` | no |
| <a name="input_dns_validation"></a> [dns\_validation](#input\_dns\_validation) | (Optional) The configuration for the DNS validation. `dns_validation` as defined below.<br> (Optional) `enabled` - Whether to process DNS validation by creating the necessary domain records in the module. Defaults to `false`.<br> (Optional) `managed_zones` - List of Hosted Zones to automatically manage the records for DNS validation as a map. The key is the name of Hosted Zone. The value is the ID of Hosted Zone. | <pre>object({<br> enabled = optional(bool, false)<br> managed_zones = optional(map(string), {})<br> })</pre> | `{}` | no |
| <a name="input_email_validation"></a> [email\_validation](#input\_email\_validation) | (Optional) The configuration for the Email validation. `email_validation` as defined below.<br> (Optional) `enabled` - Whether to process Email validation by waiting the manual approval. Defaults to `false`. | <pre>object({<br> enabled = optional(bool, false)<br> })</pre> | `{}` | no |
| <a name="input_key_algorithm"></a> [key\_algorithm](#input\_key\_algorithm) | (Optional) The algorithm of the public and private key pair that your Amazon issued certificate uses to encrypt data. RSA is the default key algorithm for ACM certificates. Elliptic Curve Digital Signature Algorithm (ECDSA) keys are smaller, offering security comparable to RSA keys but with greater computing efficiency. However, ECDSA is not supported by all network clients. Some AWS services may require RSA keys, or only support ECDSA keys of a particular size, while others allow the use of either RSA and ECDSA keys to ensure that compatibility is not broken. Supported values are `RSA_1024`, `RSA_2048`, `RSA_3072`, `RSA_4096`, `ECDSA_P256`, `ECDSA_P384`, `ECDSA_P521`. Defaults to `RSA_2048`. | `string` | `"RSA_2048"` | no |
| <a name="input_module_tags_enabled"></a> [module\_tags\_enabled](#input\_module\_tags\_enabled) | (Optional) Whether to create AWS Resource Tags for the module informations. | `bool` | `true` | no |
| <a name="input_name"></a> [name](#input\_name) | (Optional) The name of the certificate. | `string` | `""` | no |
| <a name="input_resource_group_description"></a> [resource\_group\_description](#input\_resource\_group\_description) | (Optional) The description of Resource Group. | `string` | `"Managed by Terraform."` | no |
| <a name="input_resource_group_enabled"></a> [resource\_group\_enabled](#input\_resource\_group\_enabled) | (Optional) Whether to create Resource Group to find and group AWS resources which are created by this module. | `bool` | `true` | no |
| <a name="input_resource_group_name"></a> [resource\_group\_name](#input\_resource\_group\_name) | (Optional) The name of Resource Group. A Resource Group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`. | `string` | `""` | no |
| <a name="input_subject_alternative_names"></a> [subject\_alternative\_names](#input\_subject\_alternative\_names) | (Optional) List of domains that should be SANs in the issued certificate. To remove all elements of a previously configured list, set this value equal to an empty list (`[]`) or use the `terraform taint` command to trigger recreation. | `list(string)` | `[]` | no |
| <a name="input_subject_alternative_names"></a> [subject\_alternative\_names](#input\_subject\_alternative\_names) | (Optional) A list of additional FQDNs (Fully qualified domain names) to be included in SANs of the issued certificate. | `list(string)` | `[]` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | (Optional) A map of tags to add to all resources. | `map(string)` | `{}` | no |
| <a name="input_validation_dns_managed"></a> [validation\_dns\_managed](#input\_validation\_dns\_managed) | (Optional) Specifies whether validation should be managed by the module when `validation_method` is `DNS`. | `bool` | `false` | no |
| <a name="input_validation_dns_managed_zones"></a> [validation\_dns\_managed\_zones](#input\_validation\_dns\_managed\_zones) | (Optional) List of Hosted Zones to automatically manage the records for DNS validation as a map. The key is the name of Hosted Zone. The value is the ID of Hosted Zone. | `map(string)` | `{}` | no |
| <a name="input_validation_method"></a> [validation\_method](#input\_validation\_method) | (Optional) 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_method"></a> [validation\_method](#input\_validation\_method) | (Optional) Which method to use for validation. Valid values are `DNS` or `EMAIL`. Only support `DNS` validation method in this module. | `string` | `"DNS"` | no |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_arn"></a> [arn](#output\_arn) | The ARN of the certificate. |
| <a name="output_certificate_transparency_logging_enabled"></a> [certificate\_transparency\_logging\_enabled](#output\_certificate\_transparency\_logging\_enabled) | Whether or not the certificate transparency logging is enabled. |
| <a name="output_domain_name"></a> [domain\_name](#output\_domain\_name) | The domain name for which the certificate is issued. |
| <a name="output_effective_date"></a> [effective\_date](#output\_effective\_date) | Effective date and time of the certificate. Start of the validity period of the certificate. |
| <a name="output_expiration_date"></a> [expiration\_date](#output\_expiration\_date) | Expiration date and time of the certificate. |
| <a name="output_id"></a> [id](#output\_id) | The ID of the certificate. |
| <a name="output_key_algorithm"></a> [key\_algorithm](#output\_key\_algorithm) | The algorithm of the public and private key pair to encrypt data. |
| <a name="output_name"></a> [name](#output\_name) | The name of the certificate. |
| <a name="output_renewal"></a> [renewal](#output\_renewal) | The configuration for the certificate renewal.<br> `eligibility` - Whether the certificate is eligible for managed renewal.<br> `summary` - The information about the status of ACM's managed renewal for the certificate. |
| <a name="output_status"></a> [status](#output\_status) | Status of the certificate. |
| <a name="output_subject_alternative_names"></a> [subject\_alternative\_names](#output\_subject\_alternative\_names) | List of domains that is SANs in the issued certificate. |
| <a name="output_subject_name"></a> [subject\_name](#output\_subject\_name) | The domain name for which the certificate is issued. |
| <a name="output_validation_domain_records"></a> [validation\_domain\_records](#output\_validation\_domain\_records) | List of domain validation objects which can be used 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_validation_emails"></a> [validation\_emails](#output\_validation\_emails) | A list of addresses that received a validation E-Mail. Only set if `EMAIL` validation was used. |
| <a name="output_validation_method"></a> [validation\_method](#output\_validation\_method) | The method to use for validation. |
| <a name="output_subject_alternative_names"></a> [subject\_alternative\_names](#output\_subject\_alternative\_names) | The list of additional FQDNs (Fully qualified domain names) to be included in SANs of the issued certificate. |
| <a name="output_type"></a> [type](#output\_type) | The type of the certificate. |
| <a name="output_validation"></a> [validation](#output\_validation) | The configuration for the certificate validation.<br> `method` - The method to use to validate the domain ownership for requesting a public certificate.<br> `domain_records` - A map of domain validation records which can be used to complete certificate validation. Can have more than one element, e.g. if SANs are defined. Only set if `validation.method` is `DNS`.<br> `emails` - A list of addresses that received a validation E-Mail. Only set if `validation.method` is `EMAIL`. |
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
71 changes: 58 additions & 13 deletions modules/amazon-issued-cert/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,42 @@ locals {
} : {}
}

locals {
key_algorithms = {
"RSA_1024" = "RSA_1024"
"RSA_2048" = "RSA_2048"
"RSA_3072" = "RSA_3072"
"RSA_4096" = "RSA_4096"
"ECDSA_P256" = "EC_prime256v1"
"ECDSA_P384" = "EC_secp384r1"
"ECDSA_P521" = "EC_secp521r1"
}
}


###################################################
# ACM Certificate
###################################################

# INFO: Not supported attributes
# - `certificate_authority_arn`
# - `certificate_body`
# - `certificate_chain`
# - `private_key`
# TODO: Support `EMAIL` validation method
# - `validation_options`
resource "aws_acm_certificate" "this" {
domain_name = var.subject_name
domain_name = var.domain_name
subject_alternative_names = var.subject_alternative_names

validation_method = var.validation_method
key_algorithm = local.key_algorithms[var.key_algorithm]

options {
certificate_transparency_logging_preference = var.certificate_transparency_logging_enabled ? "ENABLED" : "DISABLED"
}

validation_method = var.validation_method

tags = merge(
{
"Name" = local.metadata.name
Expand All @@ -43,30 +69,49 @@ resource "aws_acm_certificate" "this" {
###################################################

locals {
subject_names = concat([var.subject_name], var.subject_alternative_names)
subject_names = concat([var.domain_name], var.subject_alternative_names)

validation_dns_managed = var.validation_method == "DNS" && var.validation_dns_managed
validation_domain_records = {
dns_validation_enabled = var.validation_method == "DNS" && var.dns_validation.enabled
dns_validation_records = {
for record in aws_acm_certificate.this.domain_validation_options :
record.domain_name => record
record.domain_name => {
name = record.resource_record_name
type = record.resource_record_type
value = record.resource_record_value
}
}
}

resource "aws_route53_record" "validation" {
for_each = toset(local.validation_dns_managed ? local.subject_names : [])
for_each = toset(local.dns_validation_enabled ? local.subject_names : [])

zone_id = var.validation_dns_managed_zones[replace(each.value, "*.", "")]
type = local.validation_domain_records[each.value].resource_record_type
name = local.validation_domain_records[each.value].resource_record_name
records = [local.validation_domain_records[each.value].resource_record_value]
zone_id = var.dns_validation.managed_zones[replace(each.value, "*.", "")]
name = local.dns_validation_records[each.value].name
type = local.dns_validation_records[each.value].type
records = [local.dns_validation_records[each.value].value]

ttl = 60
allow_overwrite = true
}

resource "aws_acm_certificate_validation" "this" {
count = local.validation_dns_managed ? 1 : 0
resource "aws_acm_certificate_validation" "dns" {
count = local.dns_validation_enabled ? 1 : 0

certificate_arn = aws_acm_certificate.this.arn
validation_record_fqdns = values(aws_route53_record.validation)[*].fqdn
}


###################################################
# Email Validation
###################################################

locals {
email_validation_enabled = var.validation_method == "EMAIL" && var.email_validation.enabled
}

resource "aws_acm_certificate_validation" "email" {
count = local.email_validation_enabled ? 1 : 0

certificate_arn = aws_acm_certificate.this.arn
}
5 changes: 5 additions & 0 deletions modules/amazon-issued-cert/migrations.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# INFO: [2023-11-17] Change the name of `aws_acm_certificate_validation` resource for DNS validation
moved {
from = aws_acm_certificate_validation.this
to = aws_acm_certificate_validation.dns
}
68 changes: 55 additions & 13 deletions modules/amazon-issued-cert/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ output "name" {
value = var.name
}

output "id" {
description = "The ID of the certificate."
value = aws_acm_certificate.this.id
}

output "arn" {
description = "The ARN of the certificate."
value = aws_acm_certificate.this.arn
Expand All @@ -13,16 +18,29 @@ output "status" {
value = aws_acm_certificate.this.status
}

output "subject_name" {
output "type" {
description = "The type of the certificate."
value = aws_acm_certificate.this.type
}

output "domain_name" {
description = "The domain name for which the certificate is issued."
value = aws_acm_certificate.this.domain_name
}

output "subject_alternative_names" {
description = "List of domains that is SANs in the issued certificate."
description = "The list of additional FQDNs (Fully qualified domain names) to be included in SANs of the issued certificate."
value = aws_acm_certificate.this.subject_alternative_names
}

output "key_algorithm" {
description = "The algorithm of the public and private key pair to encrypt data."
value = {
for k, v in local.key_algorithms :
v => k
}[aws_acm_certificate.this.key_algorithm]
}

output "certificate_transparency_logging_enabled" {
description = "Whether or not the certificate transparency logging is enabled."
value = var.certificate_transparency_logging_enabled
Expand All @@ -38,17 +56,41 @@ output "expiration_date" {
value = aws_acm_certificate.this.not_after
}

output "validation_method" {
description = "The method to use for validation."
value = aws_acm_certificate.this.validation_method
}

output "validation_domain_records" {
description = "List of domain validation objects which can be used to complete certificate validation. Can have more than one element, e.g. if SANs are defined. Only set if `DNS` validation was used."
value = aws_acm_certificate.this.domain_validation_options
output "validation" {
description = <<EOF
The configuration for the certificate validation.
`method` - The method to use to validate the domain ownership for requesting a public certificate.
`domain_records` - A map of domain validation records which can be used to complete certificate validation. Can have more than one element, e.g. if SANs are defined. Only set if `validation.method` is `DNS`.
`emails` - A list of addresses that received a validation E-Mail. Only set if `validation.method` is `EMAIL`.
EOF
value = {
method = aws_acm_certificate.this.validation_method
domain_records = (aws_acm_certificate.this.validation_method == "DNS"
? {
for option in aws_acm_certificate.this.domain_validation_options :
option.domain_name => {
name = option.resource_record_name
type = option.resource_record_type
value = option.resource_record_value
}
}
: {}
)
emails = (aws_acm_certificate.this.validation_method == "EMAIL"
? aws_acm_certificate.this.validation_emails
: []
)
}
}

output "validation_emails" {
description = "A list of addresses that received a validation E-Mail. Only set if `EMAIL` validation was used."
value = aws_acm_certificate.this.validation_emails
output "renewal" {
description = <<EOF
The configuration for the certificate renewal.
`eligibility` - Whether the certificate is eligible for managed renewal.
`summary` - The information about the status of ACM's managed renewal for the certificate.
EOF
value = {
eligibility = aws_acm_certificate.this.renewal_eligibility
summary = aws_acm_certificate.this.renewal_summary
}
}
Loading

0 comments on commit aa7707e

Please sign in to comment.