diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b71d691..6f20ddd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/antonbabenko/pre-commit-terraform - rev: v1.47.0 + rev: v1.48.0 hooks: # - id: terraform_validate - id: terraform_fmt @@ -8,9 +8,10 @@ repos: args: ['table'] exclude: common/*.tf exclude: version.tf - + - id: terraform_tflint + args: [ "--args=--config=__GIT_WORKING_DIR__/.tflint.hcl"] - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.1.0 + rev: v3.4.0 hooks: - id: check-symlinks - id: detect-aws-credentials diff --git a/.tflint.hcl b/.tflint.hcl new file mode 100644 index 0000000..fcc2fa8 --- /dev/null +++ b/.tflint.hcl @@ -0,0 +1,21 @@ +config { + module = true + force = false + disabled_by_default = false + +# ignore_module = { +# "terraform-aws-modules/vpc/aws" = true +# "terraform-aws-modules/security-group/aws" = true +# } + +# varfile = ["example1.tfvars", "example2.tfvars"] +# variables = ["foo=bar", "bar=[\"baz\"]"] +} + +rule "aws_instance_invalid_type" { + enabled = true +} + +plugin "aws" { + enabled = true +} diff --git a/CHANGELOG.md b/CHANGELOG.md index eef7c92..74faa1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,3 +43,7 @@ * v1.7.3 -- 20210324 - iam-general-policies - fix bad arn + +* v1.7.4 -- 20210326 + - ses-domain + - add code to enable move to production, runs aws cli script diff --git a/common/version.tf b/common/version.tf index 19a45aa..4d1d42c 100644 --- a/common/version.tf +++ b/common/version.tf @@ -1,3 +1,3 @@ locals { - _module_version = "1.7.3" + _module_version = "1.7.4" } diff --git a/ses-domain/README.md b/ses-domain/README.md index 12649bd..bcf41ed 100644 --- a/ses-domain/README.md +++ b/ses-domain/README.md @@ -1,20 +1,21 @@ # aws-inf-setup :: ses-domain -This sets up the domain identity for SES. We create by default `{account_id}.aws.mail.census.gov` -as a sender domain, and generate the details which are to be submitted to TCO for inclusion in DNS. -The contents of the file `${path.root}/setup/ses_dns.md` contain the text which goes to TCO. A future enhancement -to this will include the ability to automatically incorporate the changes into DNS. This is a multi-step +This sets up the domain identity for SES. We create by default `{account_id}.aws.mail.census.gov` +as a sender domain, and generate the details which are to be submitted to TCO for inclusion in DNS. +The contents of the file `${path.root}/setup/ses_dns.md` contain the text which goes to TCO. A future enhancement +to this will include the ability to automatically incorporate the changes into DNS. This is a multi-step setup: -1. Create initial resources -1. Provide TCO Details for DNS Update +1. Create initial resources +1. Provide TCO Details for DNS Update 1. Complete domain validation +1. Enable for production ## Select proper region -Note that at this time, this needs to be done from the `us-gov-west-1` region for GovCloud. For East/West, any US region -will work. Ideally, this will check that the west zone is selected for gov, and not create any resources if in the incorrect region. -However, that's not current possible with Terraform 0.12, and we need to get to 0.13 to make that possible. You will see this +Note that at this time, this needs to be done from the `us-gov-west-1` region for GovCloud. For East/West, any US region +will work. Ideally, this will check that the west zone is selected for gov, and not create any resources if in the incorrect region. +However, that's not current possible with Terraform 0.12, and we need to get to 0.13 to make that possible. You will see this error if in the incorrect region: ```console % tf-apply @@ -29,17 +30,21 @@ Error: Error requesting SES domain identity verification: SignatureDoesNotMatch: ## Request TCO/OIS approval for 3rd Party Domain -A submission of a form authorizing 3rd party mail is required to TCO, who then puts in a ticket to OIS. This has +A submission of a form authorizing 3rd party mail is required to TCO, who then puts in a ticket to OIS. This has been done for the AWS accounts as whole, using the default format. Any variation (that is, using a custom `ses_domain_name` requires this form be filled out. Details are available on the [TCO Wiki Mail Section](https://wiki.apps.tco.census.gov/index.php/Services#Mail) or in [Sending Mail](https://wiki.apps.tco.census.gov/index.php/Sending_Mail). -# Usage +# Usage This can be used without any variables to get the default configuration. ```hcl module "ses" { source = "git@github.e.it.census.gov:terraform-modules/aws-inf-setup.git//ses-domain" + profile = var.profile + ## once validated, get out of sandbox + # ses_enable_production = true + ## optional, changing this is not recommended # ses_domain_name = "123456789012.postal.census.gov" ## while these can be changed, it is not advised @@ -56,8 +61,8 @@ module "ses" { See and example [ses\_dns.md](example.ses\_dns.md). This file will be in `setup/ses_dns.md`. Submit this to TCO to get the records added to DNS. -## After DNS is updated -Once DNS has been updated, you can run `tf-apply` on the resource again. It will look for a non-empty value +## After DNS is updated +Once DNS has been updated, you can run `tf-apply` on the resource again. It will look for a non-empty value for the TXT record and if so, complete the validation process. Here is an example: ```console % tf-apply -target=module.ses @@ -76,6 +81,35 @@ Plan: 1 to add, 0 to change, 0 to destroy. module.ses.aws_ses_domain_identity_verification.this[0]: Creating... module.ses.aws_ses_domain_identity_verification.this[0]: Creation complete after 1s [id=817869416306.aws.mail.census.gov] ``` +## Getting out of the Sandbox +Reference: https://docs.aws.amazon.com/ses/latest/DeveloperGuide/request-production-access.html + +Use the variable `ses_enable_production=true` to do this. There is no terraform resource for this. +This enables the use of a script which requires the AWS CLIv2, and it will fail otherwise. + +```hcl +module "ses" { + source = "git@github.e.it.census.gov:terraform-modules/aws-inf-setup.git//ses-domain" + + profile = var.profile + ses_enable_production = true +} +``` +then run `tf-apply` +```console +% tf-apply -target=module.ses +Resource actions are indicated with the following symbols: +-/+ destroy and then create replacement + +Terraform will perform the following actions: + + # module.ses.null_resource.to_production[0] is tainted, so must be replaced +-/+ resource "null_resource" "to_production" { + ~ id = "283142555786980861" -> (known after apply) + } + +Plan: 1 to add, 0 to change, 1 to destroy. +``` # Sample Output ```hcl @@ -110,8 +144,6 @@ ses_domain_verification = { "value" = "/Pz6+wpIUfumhdG8l0NkdfLx+wHMp+/Za2Nf5jOQTos=" } ``` -# Getting out of the Sandbox -Refence: https://docs.aws.amazon.com/ses/latest/DeveloperGuide/request-production-access.html ## Requirements @@ -121,44 +153,51 @@ No requirements. | Name | Version | |------|---------| -| aws | n/a | -| external | n/a | -| null | n/a | +| [aws](#provider\_aws) | n/a | +| [external](#provider\_external) | n/a | +| [null](#provider\_null) | n/a | ## Modules -No Modules. +No modules. ## Resources -| Name | -|------| -| [aws_arn](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/arn) | -| [aws_caller_identity](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | -| [aws_region](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | -| [aws_ses_domain_dkim](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ses_domain_dkim) | -| [aws_ses_domain_identity](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ses_domain_identity) | -| [aws_ses_domain_identity_verification](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ses_domain_identity_verification) | -| [external_external](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external) | -| [null_resource](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | +| Name | Type | +|------|------| +| [aws_ses_domain_dkim.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ses_domain_dkim) | resource | +| [aws_ses_domain_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ses_domain_identity) | resource | +| [aws_ses_domain_identity_verification.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ses_domain_identity_verification) | resource | +| [null_resource.this_output](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource | +| [null_resource.to_production](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource | +| [aws_arn.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/arn) | data source | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | +| [external_external.ses_dns_txt](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external) | data source | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| account\_alias | AWS Account Alias | `string` | `""` | no | -| account\_id | AWS Account ID (default will pull from current user) | `string` | `""` | no | -| override\_prefixes | Override built-in prefixes by component (efs, s3, ebs, kms, role, policy, security-group). This should be used primarily for common infrastructure things | `map(string)` | `{}` | no | -| ses\_base\_dkim\_domain\_name | SES Base DKIM Domain Name | `string` | `"dkim.amazonses.com"` | no | -| ses\_base\_domain\_name | SES Base Domain Name | `string` | `"aws.mail.census.gov"` | no | -| ses\_domain\_name | SES Fully Qualified Domain Name (default: {account\_id}.aws.mail.census.gov) | `string` | `""` | no | -| tags | AWS Tags to apply to appropriate resources (S3, KMS). Do not include safeguard tags here, use the data\_safeguard field for such things. | `map(string)` | `{}` | no | +| [account\_alias](#input\_account\_alias) | AWS Account Alias | `string` | `""` | no | +| [account\_id](#input\_account\_id) | AWS Account ID (default will pull from current user) | `string` | `""` | no | +| [override\_prefixes](#input\_override\_prefixes) | Override built-in prefixes by component (efs, s3, ebs, kms, role, policy, security-group). This should be used primarily for common infrastructure things | `map(string)` | `{}` | no | +| [profile](#input\_profile) | AWS Config profile (required for calling the aws cli) | `string` | `""` | no | +| [region](#input\_region) | AWS Region (default takes from current executing region) | `string` | `""` | no | +| [ses\_additional\_contact\_email](#input\_ses\_additional\_contact\_email) | SES Additional Contact email address list (for move to production) | `list(string)` | `[]` | no | +| [ses\_base\_dkim\_domain\_name](#input\_ses\_base\_dkim\_domain\_name) | SES Base DKIM Domain Name | `string` | `"dkim.amazonses.com"` | no | +| [ses\_base\_domain\_name](#input\_ses\_base\_domain\_name) | SES Base Domain Name | `string` | `"aws.mail.census.gov"` | no | +| [ses\_domain\_name](#input\_ses\_domain\_name) | SES Fully Qualified Domain Name (default: {account\_id}.aws.mail.census.gov) | `string` | `""` | no | +| [ses\_enable\_production](#input\_ses\_enable\_production) | SES Enable calling of AWS CLI to move from sandbox to production | `bool` | `false` | no | +| [ses\_use\_case\_description](#input\_ses\_use\_case\_description) | SES use case description (for move to production) | `string` | `""` | no | +| [ses\_website\_url](#input\_ses\_website\_url) | SES website URL (for move to production) | `string` | `"https://census.gov"` | no | +| [tags](#input\_tags) | AWS Tags to apply to appropriate resources (S3, KMS). Do not include safeguard tags here, use the data\_safeguard field for such things. | `map(string)` | `{}` | no | ## Outputs | Name | Description | |------|-------------| -| ses\_dkim\_values | DNS entries to add for DKIM | -| ses\_domain\_identity | SES Domain Identity | -| ses\_domain\_identity\_arn | SES Domain Identity ARN | -| ses\_domain\_verification | DNS entries to add for domain verification | +| [ses\_dkim\_values](#output\_ses\_dkim\_values) | DNS entries to add for DKIM | +| [ses\_domain\_identity](#output\_ses\_domain\_identity) | SES Domain Identity | +| [ses\_domain\_identity\_arn](#output\_ses\_domain\_identity\_arn) | SES Domain Identity ARN | +| [ses\_domain\_verification](#output\_ses\_domain\_verification) | DNS entries to add for domain verification | diff --git a/ses-domain/bin/move-to-production.sh b/ses-domain/bin/move-to-production.sh old mode 100644 new mode 100755 index 2ffd271..6ee3bcb --- a/ses-domain/bin/move-to-production.sh +++ b/ses-domain/bin/move-to-production.sh @@ -12,38 +12,54 @@ $AWS sesv2 help >/dev/null 2>&1 status=$? if [ $status != 0 ] then - echo "* aws sesv2 CLI missing" + echo "* aws sesv2 CLI missing or error with profile/region status=$status" exit 1 fi -if [[ -z $AWS_PROFILE ]] || [[ -z $AWS_DEFAULT_REGION ] +if [[ -z $AWS_PROFILE ]] || [[ -z $AWS_DEFAULT_REGION ]] then - echo "* missing AWS_PROFILE=$AWS_PROFILE or AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION" + echo "* missing AWS_PROFILE='$AWS_PROFILE' or AWS_DEFAULT_REGION='$AWS_DEFAULT_REGION'" exit 1 fi if [ -z $SES_USE_CASE_DESCRIPTION ] then - SES_USE_CASE_DESCRIPTION="Used for alerting and notification from lambda and other applications to users within our own enterprise mail system" + SES_USE_CASE_DESCRIPTION="Used for alerting and notification from lambda and other applications to users registered within our own enterprise mail system." fi if [ -z $SES_ADDITIONAL_CONTACT_EMAIL ] then - SES_ADDITIONAL_CONTACT_EMAIL="donald.e.badrak.ii@census.gov,roy.d.ashley.jr@census.gov" + SES_ADDITIONAL_CONTACT_EMAIL="donald.e.badrak.ii@census.gov roy.d.ashley.jr@census.gov" fi -$AWS sesv2 put-account-details \ ---production-access-enabled \ ---mail-type TRANSACTIONAL \ ---use-case-description "$SES_USE_CASE_DESCRIPTION" \ ---additional-contact-email-addresses "$SES_ADDITIONAL_CONTACT_EMAIL" \ ---contact-language EN +if [ -z $SES_WEBSITE_URL ] +then + SES_WEBSITE_URL="https://census.gov" +fi + +if [ ! -z $SES_DEBUG ] +then + SES_DEBUG="true" +fi + +$SES_DEBUG $AWS sesv2 put-account-details \ + --production-access-enabled \ + --mail-type TRANSACTIONAL \ + --website-url "$SES_WEBSITE_URL" \ + --use-case-description "$SES_USE_CASE_DESCRIPTION" \ + --additional-contact-email-addresses $SES_ADDITIONAL_CONTACT_EMAIL \ + --contact-language EN status=$? if [ $status != 0 ] then echo "* error requesting production access for SES" + exit $status fi + +# now, get the details +$SES_DEBUG $AWS sesv2 get-account + exit $status # unused options @@ -54,3 +70,4 @@ exit $status # AWS_PROFILE # SES_ADDITIONAL_CONTACT_EMAIL # SES_USE_CASE_DESCRIPTION +# SES_WEBSITE_URL diff --git a/ses-domain/main.tf b/ses-domain/main.tf index f566a72..29273d3 100644 --- a/ses-domain/main.tf +++ b/ses-domain/main.tf @@ -10,6 +10,7 @@ * 1. Create initial resources * 1. Provide TCO Details for DNS Update * 1. Complete domain validation +* 1. Enable for production * * ## Select proper region * @@ -41,6 +42,10 @@ * module "ses" { * source = "git@github.e.it.census.gov:terraform-modules/aws-inf-setup.git//ses-domain" * +* profile = var.profile +* ## once validated, get out of sandbox +* # ses_enable_production = true +* * ## optional, changing this is not recommended * # ses_domain_name = "123456789012.postal.census.gov" * ## while these can be changed, it is not advised @@ -77,6 +82,35 @@ * module.ses.aws_ses_domain_identity_verification.this[0]: Creating... * module.ses.aws_ses_domain_identity_verification.this[0]: Creation complete after 1s [id=817869416306.aws.mail.census.gov] * ``` +* ## Getting out of the Sandbox +* Reference: https://docs.aws.amazon.com/ses/latest/DeveloperGuide/request-production-access.html +* +* Use the variable `ses_enable_production=true` to do this. There is no terraform resource for this. +* This enables the use of a script which requires the AWS CLIv2, and it will fail otherwise. +* +* ```hcl +* module "ses" { +* source = "git@github.e.it.census.gov:terraform-modules/aws-inf-setup.git//ses-domain" +* +* profile = var.profile +* ses_enable_production = true +* } +* ``` +* then run `tf-apply` +* ```console +* % tf-apply -target=module.ses +* Resource actions are indicated with the following symbols: +* -/+ destroy and then create replacement +* +* Terraform will perform the following actions: +* +* # module.ses.null_resource.to_production[0] is tainted, so must be replaced +* -/+ resource "null_resource" "to_production" { +* ~ id = "283142555786980861" -> (known after apply) +* } +* +* Plan: 1 to add, 0 to change, 1 to destroy. +* ``` * * # Sample Output * ```hcl @@ -111,8 +145,6 @@ * "value" = "/Pz6+wpIUfumhdG8l0NkdfLx+wHMp+/Za2Nf5jOQTos=" * } * ``` -* # Getting out of the Sandbox -* Refence: https://docs.aws.amazon.com/ses/latest/DeveloperGuide/request-production-access.html */ locals { @@ -183,3 +215,22 @@ resource "null_resource" "this_output" { command = "echo '${local.ses_output}' > setup/ses_dns.md" } } + +resource "null_resource" "to_production" { + count = var.ses_enable_production ? 1 : 0 + triggers = { + contact_email = length(var.ses_additional_contact_email) > 0 ? join(" ", var.ses_additional_contact_email) : "" + use_case = var.ses_use_case_description + website_url = var.ses_website_url + } + provisioner "local-exec" { + command = "${path.module}/bin/move-to-production.sh" + environment = { + AWS_DEFAULT_REGION = var.region == "" ? data.aws_region.current.name : var.region + AWS_PROFILE = var.profile == "" ? "default" : var.profile + SES_ADDITIONAL_CONTACT_EMAIL = length(var.ses_additional_contact_email) > 0 ? join(" ", var.ses_additional_contact_email) : "" + SES_USE_CASE_DESCRIPTION = var.ses_use_case_description + SES_WEBSITE_URL = var.ses_website_url + } + } +} diff --git a/ses-domain/variables.tf b/ses-domain/variables.tf index 3f0911b..6f517e6 100644 --- a/ses-domain/variables.tf +++ b/ses-domain/variables.tf @@ -1,3 +1,9 @@ +# variable "component_tags" { +# description = "Additional tags for Components (s3, kms, ddb)" +# type = map(map(string)) +# default = { "s3" = {}, "kms" = {}, "ddb" = {} } +# } + variable "ses_domain_name" { description = "SES Fully Qualified Domain Name (default: {account_id}.aws.mail.census.gov)" type = string @@ -16,8 +22,38 @@ variable "ses_base_dkim_domain_name" { default = "dkim.amazonses.com" } -# variable "component_tags" { -# description = "Additional tags for Components (s3, kms, ddb)" -# type = map(map(string)) -# default = { "s3" = {}, "kms" = {}, "ddb" = {} } -# } +variable "ses_enable_production" { + description = "SES Enable calling of AWS CLI to move from sandbox to production" + type = bool + default = false +} + +variable "ses_additional_contact_email" { + description = "SES Additional Contact email address list (for move to production)" + type = list(string) + default = [] +} + +variable "ses_use_case_description" { + description = "SES use case description (for move to production)" + type = string + default = "" +} + +variable "ses_website_url" { + description = "SES website URL (for move to production)" + type = string + default = "https://census.gov" +} + +variable "region" { + description = "AWS Region (default takes from current executing region)" + type = string + default = "" +} + +variable "profile" { + description = "AWS Config profile (required for calling the aws cli)" + type = string + default = "" +}