From 391d4fcdc3d7cb8e827e461acb2e66b74bd02ff8 Mon Sep 17 00:00:00 2001 From: badra001 Date: Mon, 8 Jan 2024 09:00:34 -0500 Subject: [PATCH] * 1.0.1 -- 2024-01-08 - add - certificate_ip_addresses - certificate_uris - generate filename if certificate_dns missing and certificate_cn contains non FQDN characters - update docs --- CHANGELOG.md | 7 +++++++ acm/README.md | 2 ++ acm/main.tf | 2 ++ acmpca/README.md | 48 +++++++++++++++---------------------------- acmpca/certificate.tf | 31 ++++++++++++++++++++++------ acmpca/main.tf | 40 ++++++++++-------------------------- acmpca/output.tf | 4 +--- acmpca/variables.tf | 15 +++++++++++++- common/version.tf | 2 +- 9 files changed, 80 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebdaf46..50d3052 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,3 +3,10 @@ * 1.0.0 -- 2024-01-02 - initial creation + +* 1.0.1 -- 2024-01-08 + - add + - certificate_ip_addresses + - certificate_uris + - generate filename if certificate_dns missing and certificate_cn contains non FQDN characters + - update docs diff --git a/acm/README.md b/acm/README.md index 8b9dbd6..76f6d38 100644 --- a/acm/README.md +++ b/acm/README.md @@ -50,6 +50,8 @@ resource "aws_lb_listener" "app_443" { The output value to look at is `certificate_arn`. This is null if the certificate is incomplete or failed to load into ACM, or the ARN if completed. You'll use the ARN for an AWS LB Listener. +# Links + ## Requirements | Name | Version | diff --git a/acm/main.tf b/acm/main.tf index 12d9fb0..3626f13 100644 --- a/acm/main.tf +++ b/acm/main.tf @@ -49,6 +49,8 @@ * * The output value to look at is `certificate_arn`. This is null if the certificate is incomplete or failed to load into ACM, or * the ARN if completed. You'll use the ARN for an AWS LB Listener. +* +* # Links */ diff --git a/acmpca/README.md b/acmpca/README.md index 700a7b8..7ab62c0 100644 --- a/acmpca/README.md +++ b/acmpca/README.md @@ -10,42 +10,24 @@ reference. Other documentation states otherwise (TBD -- find link). It expects an SSM parameter `/enterprise/pki/ca1` for general purpose and `/enterprise/pki/ca2` for short term CA to exist in the account (distributed to all OUs from a central account). If this parameter does not exist, this module will fail. -It returns: +You may select from the available templates for the specific CA from the [SSM Paramter](https://github.e.it.census.gov/terraform/cloud-information/blob/master/aws/documentation/organizations/shared-secrets-parameters/parameters/enterprise_pki.md). +Currently, only the `end-entity` (used for typical server or LB certificates) and `subordinate-ca` types are permitted and shared to the organization. Client Auth, Server Auth, +and Passthrough certificate types may be made availble in the future as need dictates. + +We are also unable to support [custom attributes](https://docs.aws.amazon.com/privateca/latest/userguide/PcaIssueCert.html) at this time. + +This module returns: # Usage This shows the module call with how you would use it. -```hcl -module "cert" { - source = "git@github.e.it.census.gov:terraform-modules/aws-certificates//acm" - - certificate_dns = "test.domain.census.gov" - contact_email = "cio.engineering.alert.list@census.gov" - - ## optional - ## add additional names to SAN - # certificate_san = [ "otherdomain.domain.census.gov" ] -} - -# associating it with the ALB listener -resource "aws_lb_listener" "app_443" { - count = module.cert.certificate_arn != null ? 1 : 0 - load_balancer_arn = aws_lb.app.arn - port = 443 - protocol = "HTTPS" - ssl_policy = "ELBSecurityPolicy-TLS-1-2-2017-01" - certificate_arn = module.cert.certificate_arn - - default_action { - type = "forward" - target_group_arn = aws_lb_target_group.app.arn - } -} -``` - The output value to look at is `certificate_arn`. This is null if the certificate is incomplete or failed to load into ACM, or the ARN if completed. You'll use the ARN for an AWS LB Listener. +# Links +* https://docs.aws.amazon.com/privateca/latest/userguide/UsingTemplates.html +* https://docs.aws.amazon.com/privateca/latest/userguide/PcaIssueCert.html + ## Requirements | Name | Version | @@ -63,6 +45,7 @@ the ARN if completed. You'll use the ARN for an AWS LB Listener. | [aws](#provider\_aws) | >= 5.0 | | [local](#provider\_local) | >= 2.1.0 | | [null](#provider\_null) | >= 3.1.0 | +| [random](#provider\_random) | n/a | | [tls](#provider\_tls) | >= 3.1.0 | ## Modules @@ -79,6 +62,7 @@ No modules. | [local_sensitive_file.certificate_csr](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/sensitive_file) | resource | | [local_sensitive_file.certificate_key](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/sensitive_file) | resource | | [null_resource.output_directory](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource | +| [random_uuid.filename](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/uuid) | resource | | [tls_cert_request.certificate](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/cert_request) | resource | | [tls_private_key.certificate](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key) | resource | | [aws_arn.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/arn) | data source | @@ -97,11 +81,13 @@ No modules. | [certificate\_authority\_template](#input\_certificate\_authority\_template) | String indicating which specific ACMPCA template to use | `string` | `null` | no | | [certificate\_chain\_filename](#input\_certificate\_chain\_filename) | Filename for Certificate Chain (signer, intermediate(s) and root). Defaults to {certificate\_dns}.chain.crt | `string` | `null` | no | | [certificate\_cn](#input\_certificate\_cn) | CommonName (CN) to use for certificate, defaults in c=US,o=U.S. Census Bureau,ou=Servers. This will typically be the DNS name. Uses certificate\_dns if not provided. | `string` | `null` | no | -| [certificate\_dns](#input\_certificate\_dns) | DNS Name to be used for the certificate. For ACM certificate, the subject and CN may not be customized. | `string` | n/a | yes | +| [certificate\_dns](#input\_certificate\_dns) | DNS Name to be used for the certificate. One of certificate\_dns or certificate\_cn must be provided. | `string` | `null` | no | | [certificate\_filename](#input\_certificate\_filename) | Filename for Certificate. Defaults to {certificate\_dns}.crt | `string` | `null` | no | +| [certificate\_ip\_addresses](#input\_certificate\_ip\_addresses) | List of IP Addresses to be used in the CSR. It is not recommended to use this for any service with auto-assigned addressing. | `string` | `[]` | no | | [certificate\_san](#input\_certificate\_san) | The Subject Alternate Names (SAN), a list of FQDNs to include in the ACM Certificate. Only DNS names are supported. See docs at https://docs.aws.amazon.com/cli/latest/reference/acm/request-certificate.html | `list(string)` | `[]` | no | | [certificate\_subject\_overrides](#input\_certificate\_subject\_overrides) | Map of c, o, and ou to override certificate signing request settings. Note that only a single OU is permitted. | `map(string)` | `{}` | no | | [certificate\_type](#input\_certificate\_type) | Selection of type of certificate, either end-entity or subordinate-ca. Note that the subordinate-ca type is not available for the short lived CA mode | `string` | `"end-entity"` | no | +| [certificate\_uris](#input\_certificate\_uris) | List of URIs to be used in the CSR. | `string` | `[]` | no | | [contact\_email](#input\_contact\_email) | Email address in @census.gov of contact for the certificate. This is strongly recommended to be a group email address. | `string` | n/a | yes | | [create\_files](#input\_create\_files) | Flag controlling the creation of output files for the key, CSR, and certificate and bundle. | `bool` | `false` | no | | [csr\_filename](#input\_csr\_filename) | Filename for Certificate Signing Request (CSR). Defaults to {certificate\_dns}.csr | `string` | `null` | no | @@ -118,6 +104,6 @@ No modules. | [certificate](#output\_certificate) | PEM format for signed certificate | | [certificate\_chain](#output\_certificate\_chain) | PEM format for certificate chain (issuer through root) | | [certificate\_csr](#output\_certificate\_csr) | PEM format Certificate Signing Request | -| [certificate\_files](#output\_certificate\_files) | Map of certificate file names | +| [certificate\_filenames](#output\_certificate\_filenames) | Map of certificate file names | | [certificate\_key](#output\_certificate\_key) | PEM format RSA Key | \ No newline at end of file diff --git a/acmpca/certificate.tf b/acmpca/certificate.tf index 4c835c9..ebf3df7 100644 --- a/acmpca/certificate.tf +++ b/acmpca/certificate.tf @@ -6,8 +6,17 @@ locals { ca_type = lookup(local._defaults["template"], var.certificate_type, null) ca_settings = var.certificate_authority_mode == "general" ? local.ca_longterm_settings : local.ca_shortterm_settings - output_file_directory = var.output_file_directory != null ? var.output_file_directory : format("%v/%v", path.root, "certs") + output_file_directory = var.output_file_directory != null ? var.output_file_directory : format("%v/%v", path.root, "certs") + _cert_filename = coalesce(var.certificate_cn, local.cert_dns)[0] + generate_cert_filename = try(regex("[^a-zA-Z0-9_-.]", local._cert_filename, false)) + cert_filename = local.generate_cert_filename ? local._cert_filename : random_uuid.filename.result +} +resource "random_uuid" "filename" { + count = local.generate_cert_filename ? 1 : 0 + keepers = { + generate_cert_filename = local.generate_cert_filename + } } resource "tls_private_key" "certificate" { @@ -20,11 +29,21 @@ resource "tls_cert_request" "certificate" { dns_names = local.cert_san subject { - common_name = local.cert_dns + common_name = coalesce(var.certificate_cn, local.cert_dns)[0] country = lookup(var.certificate_subject_overrides, "c", local._defaults.certificate["c"]) organization = lookup(var.certificate_subject_overrides, "o", local._defaults.certificate["o"]) organizational_unit = lookup(var.certificate_subject_overrides, "ou", local._defaults.certificate["ou"]) } + + ip_addresses = var.certificate_ip_addresses + uris = var.certificate_uris + + lifecycle { + precondition { + condition = var.certificate_cn != null && local.cert_dns != null + error_message = "One of the certificate_cn or certificate_dns must be provided and not null." + } + } } resource "aws_acmpca_certificate" "certificate" { @@ -70,10 +89,10 @@ resource "null_resource" "output_directory" { } locals { - filename_key = var.key_filename != null ? var.key_filename : format("%v/%v.%v", local.output_file_directory, local.cert_dns, "key") - filename_csr = var.csr_filename != null ? var.csr_filename : format("%v/%v.%v", local.output_file_directory, local.cert_dns, "csr") - filename_crt = var.certificate_filename != null ? var.certificate_filename : format("%v/%v.%v", local.output_file_directory, local.cert_dns, "crt") - filename_chain = var.certificate_chain_filename != null ? var.certificate_chain_filename : format("%v/%v.%v", local.output_file_directory, local.cert_dns, "chain.crt") + filename_key = var.key_filename != null ? var.key_filename : format("%v/%v.%v", local.output_file_directory, local.cert_filename, "key") + filename_csr = var.csr_filename != null ? var.csr_filename : format("%v/%v.%v", local.output_file_directory, local.cert_filebame, "csr") + filename_crt = var.certificate_filename != null ? var.certificate_filename : format("%v/%v.%v", local.output_file_directory, local.cert_filename, "crt") + filename_chain = var.certificate_chain_filename != null ? var.certificate_chain_filename : format("%v/%v.%v", local.output_file_directory, local.cert_filename, "chain.crt") } resource "local_sensitive_file" "certificate_key" { diff --git a/acmpca/main.tf b/acmpca/main.tf index d923b3f..eec8676 100644 --- a/acmpca/main.tf +++ b/acmpca/main.tf @@ -9,42 +9,24 @@ * * It expects an SSM parameter `/enterprise/pki/ca1` for general purpose and `/enterprise/pki/ca2` for short term CA to exist in the account (distributed to all OUs from a central account). * If this parameter does not exist, this module will fail. -* -* It returns: * -* # Usage -* This shows the module call with how you would use it. +* You may select from the available templates for the specific CA from the [SSM Paramter](https://github.e.it.census.gov/terraform/cloud-information/blob/master/aws/documentation/organizations/shared-secrets-parameters/parameters/enterprise_pki.md). +* Currently, only the `end-entity` (used for typical server or LB certificates) and `subordinate-ca` types are permitted and shared to the organization. Client Auth, Server Auth, +* and Passthrough certificate types may be made availble in the future as need dictates. * -* ```hcl -* module "cert" { -* source = "git@github.e.it.census.gov:terraform-modules/aws-certificates//acm" +* We are also unable to support [custom attributes](https://docs.aws.amazon.com/privateca/latest/userguide/PcaIssueCert.html) at this time. * -* certificate_dns = "test.domain.census.gov" -* contact_email = "cio.engineering.alert.list@census.gov" -* -* ## optional -* ## add additional names to SAN -* # certificate_san = [ "otherdomain.domain.census.gov" ] -* } +* This module returns: * -* # associating it with the ALB listener -* resource "aws_lb_listener" "app_443" { -* count = module.cert.certificate_arn != null ? 1 : 0 -* load_balancer_arn = aws_lb.app.arn -* port = 443 -* protocol = "HTTPS" -* ssl_policy = "ELBSecurityPolicy-TLS-1-2-2017-01" -* certificate_arn = module.cert.certificate_arn -* -* default_action { -* type = "forward" -* target_group_arn = aws_lb_target_group.app.arn -* } -* } -* ``` +* # Usage +* This shows the module call with how you would use it. * * The output value to look at is `certificate_arn`. This is null if the certificate is incomplete or failed to load into ACM, or * the ARN if completed. You'll use the ARN for an AWS LB Listener. +* +* # Links +* * https://docs.aws.amazon.com/privateca/latest/userguide/UsingTemplates.html +* * https://docs.aws.amazon.com/privateca/latest/userguide/PcaIssueCert.html */ locals { diff --git a/acmpca/output.tf b/acmpca/output.tf index 43afa30..4a884f4 100644 --- a/acmpca/output.tf +++ b/acmpca/output.tf @@ -22,7 +22,7 @@ output "certificate_chain" { value = local.certificate_chain } -output "certificate_files" { +output "certificate_filenames" { description = "Map of certificate file names" sensitive = false value = { @@ -33,5 +33,3 @@ output "certificate_files" { chain = local.filename_chain } } - - diff --git a/acmpca/variables.tf b/acmpca/variables.tf index 5b500ae..3864104 100644 --- a/acmpca/variables.tf +++ b/acmpca/variables.tf @@ -1,6 +1,7 @@ variable "certificate_dns" { - description = "DNS Name to be used for the certificate. For ACM certificate, the subject and CN may not be customized." + description = "DNS Name to be used for the certificate. One of certificate_dns or certificate_cn must be provided." type = string + default = null } variable "certificate_san" { @@ -21,6 +22,18 @@ variable "certificate_cn" { default = null } +variable "certificate_ip_addresses" { + description = "List of IP Addresses to be used in the CSR. It is not recommended to use this for any service with auto-assigned addressing." + type = string + default = [] +} + +variable "certificate_uris" { + description = "List of URIs to be used in the CSR." + type = string + default = [] +} + variable "certificate_subject_overrides" { description = "Map of c, o, and ou to override certificate signing request settings. Note that only a single OU is permitted." type = map(string) diff --git a/common/version.tf b/common/version.tf index fa2705b..374ba43 100644 --- a/common/version.tf +++ b/common/version.tf @@ -1,3 +1,3 @@ locals { - _module_version = "1.0.0" + _module_version = "1.0.1" }