Skip to content

Commit

Permalink
Add certificate_authority_arn for private CAs (#53)
Browse files Browse the repository at this point in the history
* Ensure domain names & SANs are lower-case

If you provide an upper-case domain name, this module fails with the following error:

  on .terraform/modules/my_certificate/main.tf line 37, in resource "aws_route53_record" "default":
  37:   name            = each.value.name
A reference to "each.value" has been used in a context in which it
unavailable, such as when the configuration no longer contains the value in
its "for_each" expression. Remove this reference to each.value in your
configuration to work around this error.

* Auto Format

* Update Terraform minimum version to 0.13

Variable validation requires 0.13.0.

* Auto Format

* Fix condition

* Add output to allow dependencies to run post validation.

* Add certificate_authority_arn

* Add certificate_authority_arn

* Auto Format

* Add to contributors

* Auto Format

* Auto Format

* Added back markdown missing from PR

* Auto Format

* Bump LICENSE to 2022

Co-authored-by: Alex Jurkiewicz <[email protected]>
Co-authored-by: cloudpossebot <[email protected]>
Co-authored-by: Michael Arnold <[email protected]>
  • Loading branch information
4 people authored Jan 3, 2022
1 parent 761030e commit 6cce676
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 10 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright 2017-2019 Cloud Posse, LLC
Copyright 2017-2022 Cloud Posse, LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ Available targets:
|------|-------------|------|---------|:--------:|
| <a name="input_additional_tag_map"></a> [additional\_tag\_map](#input\_additional\_tag\_map) | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.<br>This is for some rare cases where resources want additional configuration of tags<br>and therefore take a list of maps with tag key, value, and additional configuration. | `map(string)` | `{}` | no |
| <a name="input_attributes"></a> [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,<br>in the order they appear in the list. New attributes are appended to the<br>end of the list. The elements of the list are joined by the `delimiter`<br>and treated as a single ID element. | `list(string)` | `[]` | no |
| <a name="input_certificate_authority_arn"></a> [certificate\_authority\_arn](#input\_certificate\_authority\_arn) | ARN of an ACM PCA | `string` | `null` | no |
| <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_context"></a> [context](#input\_context) | Single object for setting entire context at once.<br>See description of individual variables for details.<br>Leave string and numeric variables as `null` to use default value.<br>Individual variable settings (non-null) override settings in context object,<br>except for attributes, tags, and additional\_tag\_map, which are merged. | `any` | <pre>{<br> "additional_tag_map": {},<br> "attributes": [],<br> "delimiter": null,<br> "descriptor_formats": {},<br> "enabled": true,<br> "environment": null,<br> "id_length_limit": null,<br> "label_key_case": null,<br> "label_order": [],<br> "label_value_case": null,<br> "labels_as_tags": [<br> "unset"<br> ],<br> "name": null,<br> "namespace": null,<br> "regex_replace_chars": null,<br> "stage": null,<br> "tags": {},<br> "tenant": null<br>}</pre> | no |
| <a name="input_delimiter"></a> [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.<br>Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no |
Expand Down Expand Up @@ -207,6 +208,7 @@ Available targets:
| <a name="output_arn"></a> [arn](#output\_arn) | The ARN of the certificate |
| <a name="output_domain_validation_options"></a> [domain\_validation\_options](#output\_domain\_validation\_options) | CNAME records that are added to the DNS zone to complete certificate validation |
| <a name="output_id"></a> [id](#output\_id) | The ID of the certificate |
| <a name="output_validation_id"></a> [validation\_id](#output\_validation\_id) | The ID of the certificate validation |
<!-- markdownlint-restore -->


Expand Down Expand Up @@ -355,8 +357,8 @@ Check out [our other projects][github], [follow us on twitter][twitter], [apply
### Contributors

<!-- markdownlint-disable -->
| [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]<br/>[Andriy Knysh][aknysh_homepage] | [![Erik Osterman][osterman_avatar]][osterman_homepage]<br/>[Erik Osterman][osterman_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]<br/>[Igor Rodionov][goruha_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]<br/>[Vladimir][SweetOps_homepage] |
|---|---|---|---|
| [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]<br/>[Andriy Knysh][aknysh_homepage] | [![Erik Osterman][osterman_avatar]][osterman_homepage]<br/>[Erik Osterman][osterman_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]<br/>[Igor Rodionov][goruha_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]<br/>[Vladimir][SweetOps_homepage] | [![RB][nitrocode_avatar]][nitrocode_homepage]<br/>[RB][nitrocode_homepage] |
|---|---|---|---|---|
<!-- markdownlint-restore -->

[aknysh_homepage]: https://github.com/aknysh
Expand All @@ -367,6 +369,8 @@ Check out [our other projects][github], [follow us on twitter][twitter], [apply
[goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png
[SweetOps_homepage]: https://github.com/SweetOps
[SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png
[nitrocode_homepage]: https://github.com/nitrocode
[nitrocode_avatar]: https://img.cloudposse.com/150x150/https://github.com/nitrocode.png

[![README Footer][readme_footer_img]][readme_footer_link]
[![Beacon][beacon]][website]
Expand Down
2 changes: 2 additions & 0 deletions README.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,5 @@ contributors:
github: "goruha"
- name: "Vladimir"
github: "SweetOps"
- name: "RB"
github: "nitrocode"
2 changes: 2 additions & 0 deletions docs/terraform.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
|------|-------------|------|---------|:--------:|
| <a name="input_additional_tag_map"></a> [additional\_tag\_map](#input\_additional\_tag\_map) | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.<br>This is for some rare cases where resources want additional configuration of tags<br>and therefore take a list of maps with tag key, value, and additional configuration. | `map(string)` | `{}` | no |
| <a name="input_attributes"></a> [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,<br>in the order they appear in the list. New attributes are appended to the<br>end of the list. The elements of the list are joined by the `delimiter`<br>and treated as a single ID element. | `list(string)` | `[]` | no |
| <a name="input_certificate_authority_arn"></a> [certificate\_authority\_arn](#input\_certificate\_authority\_arn) | ARN of an ACM PCA | `string` | `null` | no |
| <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_context"></a> [context](#input\_context) | Single object for setting entire context at once.<br>See description of individual variables for details.<br>Leave string and numeric variables as `null` to use default value.<br>Individual variable settings (non-null) override settings in context object,<br>except for attributes, tags, and additional\_tag\_map, which are merged. | `any` | <pre>{<br> "additional_tag_map": {},<br> "attributes": [],<br> "delimiter": null,<br> "descriptor_formats": {},<br> "enabled": true,<br> "environment": null,<br> "id_length_limit": null,<br> "label_key_case": null,<br> "label_order": [],<br> "label_value_case": null,<br> "labels_as_tags": [<br> "unset"<br> ],<br> "name": null,<br> "namespace": null,<br> "regex_replace_chars": null,<br> "stage": null,<br> "tags": {},<br> "tenant": null<br>}</pre> | no |
| <a name="input_delimiter"></a> [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.<br>Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no |
Expand Down Expand Up @@ -66,4 +67,5 @@
| <a name="output_arn"></a> [arn](#output\_arn) | The ARN of the certificate |
| <a name="output_domain_validation_options"></a> [domain\_validation\_options](#output\_domain\_validation\_options) | CNAME records that are added to the DNS zone to complete certificate validation |
| <a name="output_id"></a> [id](#output\_id) | The ID of the certificate |
| <a name="output_validation_id"></a> [validation\_id](#output\_validation\_id) | The ID of the certificate validation |
<!-- markdownlint-restore -->
18 changes: 11 additions & 7 deletions main.tf
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
locals {
enabled = module.this.enabled
zone_name = var.zone_name == "" ? "${var.domain_name}." : var.zone_name
process_domain_validation_options = local.enabled && var.process_domain_validation_options && var.validation_method == "DNS"
domain_validation_options_set = local.process_domain_validation_options ? aws_acm_certificate.default.0.domain_validation_options : toset([])
}

resource "aws_acm_certificate" "default" {
count = local.enabled ? 1 : 0
domain_name = var.domain_name
validation_method = var.validation_method
subject_alternative_names = var.subject_alternative_names
certificate_authority_arn = var.certificate_authority_arn

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

tags = module.this.tags

lifecycle {
create_before_destroy = true
}
}

locals {
enabled = module.this.enabled
zone_name = var.zone_name == "" ? "${var.domain_name}." : var.zone_name
process_domain_validation_options = local.enabled && var.process_domain_validation_options && var.validation_method == "DNS"
domain_validation_options_set = local.process_domain_validation_options ? aws_acm_certificate.default.0.domain_validation_options : toset([])
}

data "aws_route53_zone" "default" {
count = local.process_domain_validation_options ? 1 : 0
zone_id = var.zone_id
Expand Down
5 changes: 5 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ output "domain_validation_options" {
value = aws_acm_certificate.default.*.domain_validation_options
description = "CNAME records that are added to the DNS zone to complete certificate validation"
}

output "validation_id" {
value = join("", aws_acm_certificate_validation.default.*.id)
description = "The ID of the certificate validation"
}
16 changes: 16 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ variable "wait_for_certificate_issued" {
variable "domain_name" {
type = string
description = "A domain name for which the certificate should be issued"

validation {
condition = ! can(regex("[A-Z]", var.domain_name))
error_message = "Domain name must be lower-case."
}
}

variable "validation_method" {
Expand All @@ -31,6 +36,11 @@ variable "subject_alternative_names" {
type = list(string)
default = []
description = "A list of domains that should be SANs in the issued certificate"

validation {
condition = length([for name in var.subject_alternative_names : name if can(regex("[A-Z]", name))]) == 0
error_message = "All SANs must be lower-case."
}
}

variable "zone_name" {
Expand All @@ -50,3 +60,9 @@ variable "certificate_transparency_logging_preference" {
default = true
description = "Specifies whether certificate details should be added to a certificate transparency log"
}

variable "certificate_authority_arn" {
type = string
default = null
description = "ARN of an ACM PCA"
}

0 comments on commit 6cce676

Please sign in to comment.