Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(DMVP-5969): Add SES module #355

Merged
merged 4 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions modules/efs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,17 +101,17 @@ resource "aws_kms_key" "key" {
| <a name="input_availability_zone_prefix"></a> [availability\_zone\_prefix](#input\_availability\_zone\_prefix) | Availability zone prefix, concat later to region code | `string` | `""` | no |
| <a name="input_creation_token"></a> [creation\_token](#input\_creation\_token) | Creation token, same as unique name | `string` | `"EFS-creation-token"` | no |
| <a name="input_egress_with_cidr_blocks"></a> [egress\_with\_cidr\_blocks](#input\_egress\_with\_cidr\_blocks) | Additional CIDR blocks for egress | `list(map(string))` | `[]` | no |
| <a name="input_encrypted"></a> [encrypted](#input\_encrypted) | Weather make encrypted or not | `bool` | `false` | no |
| <a name="input_encrypted"></a> [encrypted](#input\_encrypted) | Weather make encrypted or not | `bool` | `true` | no |
| <a name="input_ingress_with_cidr_blocks"></a> [ingress\_with\_cidr\_blocks](#input\_ingress\_with\_cidr\_blocks) | Additional CIDR blocks for ingress | `list(map(string))` | `[]` | no |
| <a name="input_kms_key_id"></a> [kms\_key\_id](#input\_kms\_key\_id) | AWS kms key arn | `string` | `null` | no |
| <a name="input_lifecycle_policy"></a> [lifecycle\_policy](#input\_lifecycle\_policy) | A block representing the lifecycle policy for the file system. | `any` | <pre>{<br/> "transition_to_archive": "AFTER_60_DAYS",<br/> "transition_to_ia": "AFTER_30_DAYS",<br/> "transition_to_primary_storage_class": null<br/>}</pre> | no |
| <a name="input_lifecycle_policy"></a> [lifecycle\_policy](#input\_lifecycle\_policy) | A block representing the lifecycle policy for the file system. | `any` | <pre>{<br> "transition_to_archive": "AFTER_60_DAYS",<br> "transition_to_ia": "AFTER_30_DAYS",<br> "transition_to_primary_storage_class": null<br>}</pre> | no |
| <a name="input_mount_target_subnets"></a> [mount\_target\_subnets](#input\_mount\_target\_subnets) | Subnet in which to create mount target | `list(string)` | `[]` | no |
| <a name="input_name"></a> [name](#input\_name) | EFS name | `string` | `"EFS"` | no |
| <a name="input_performance_mode"></a> [performance\_mode](#input\_performance\_mode) | Performance mode for EFS | `string` | `null` | no |
| <a name="input_provisioned_throughput_in_mibps"></a> [provisioned\_throughput\_in\_mibps](#input\_provisioned\_throughput\_in\_mibps) | Throughput mibps for EFS, Only compliant when throughput mode is set to provisioned | `string` | `null` | no |
| <a name="input_security_group_description"></a> [security\_group\_description](#input\_security\_group\_description) | Security group description for EFS | `string` | `""` | no |
| <a name="input_security_group_name"></a> [security\_group\_name](#input\_security\_group\_name) | Security group name for EFS | `string` | `""` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | n/a | `map(any)` | <pre>{<br/> "Provisioner": "DasMeta"<br/>}</pre> | no |
| <a name="input_tags"></a> [tags](#input\_tags) | n/a | `map(any)` | <pre>{<br> "Provisioner": "DasMeta"<br>}</pre> | no |
| <a name="input_throughput_mode"></a> [throughput\_mode](#input\_throughput\_mode) | Throughput mode for the file system. Valid values: bursting, provisioned, or elastic. When using 'provisioned', also set 'provisioned\_throughput\_in\_mibps'. | `string` | `"elastic"` | no |
| <a name="input_vpc_id"></a> [vpc\_id](#input\_vpc\_id) | VPC ID to which EFS will have access | `string` | `""` | no |

Expand Down
2 changes: 1 addition & 1 deletion modules/efs/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ variable "availability_zone_prefix" {
variable "encrypted" {
description = "Weather make encrypted or not"
type = bool
default = false
default = true
}

variable "kms_key_id" {
Expand Down
58 changes: 58 additions & 0 deletions modules/ses/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# ses

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

No requirements.

## Providers

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

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [aws_iam_access_key.ses_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_access_key) | resource |
| [aws_iam_group.ses_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_group) | resource |
| [aws_iam_group_membership.ses_user_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_group_membership) | resource |
| [aws_iam_group_policy.ses_group_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_group_policy) | resource |
| [aws_iam_user.ses_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user) | resource |
| [aws_route53_record.dkim](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |
| [aws_route53_record.spf](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |
| [aws_ses_domain_dkim.ses_domain](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ses_domain_dkim) | resource |
| [aws_ses_domain_identity.ses_domain](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ses_domain_identity) | resource |
| [aws_ses_domain_identity.verified_domains](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ses_domain_identity) | resource |
| [aws_ses_email_identity.verified_email](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ses_email_identity) | resource |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_iam_policy_document.ses_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
| [aws_route53_zone.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_create_dkim_route53"></a> [create\_dkim\_route53](#input\_create\_dkim\_route53) | If DKIM records should be created in Route 53 | `bool` | `false` | no |
| <a name="input_create_spf_route53"></a> [create\_spf\_route53](#input\_create\_spf\_route53) | If TXT record for SPF should be created in Route 53 | `bool` | `false` | no |
| <a name="input_email_domain"></a> [email\_domain](#input\_email\_domain) | For which sender domain SES should be configured. | `string` | n/a | yes |
| <a name="input_mail_users"></a> [mail\_users](#input\_mail\_users) | User names for mail to create. | `list(string)` | n/a | yes |
| <a name="input_prefix"></a> [prefix](#input\_prefix) | Prefix for ses greoup be unique. | `string` | `""` | no |
| <a name="input_region"></a> [region](#input\_region) | The region where ressources should be managed. | `string` | `null` | no |
| <a name="input_verified_domains"></a> [verified\_domains](#input\_verified\_domains) | The domain name to assign to SES. | `list(string)` | `[]` | no |
| <a name="input_verified_email_users"></a> [verified\_email\_users](#input\_verified\_email\_users) | The emails address to assign to SES. | `list(string)` | `[]` | no |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_dkim_records"></a> [dkim\_records](#output\_dkim\_records) | DNS records for DKIM |
| <a name="output_secret_keys"></a> [secret\_keys](#output\_secret\_keys) | IAM Access Key ID and Secret |
| <a name="output_smtp_credentials"></a> [smtp\_credentials](#output\_smtp\_credentials) | SMTP Username and Passwort |
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
40 changes: 40 additions & 0 deletions modules/ses/iam.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}

data "aws_iam_policy_document" "ses_policy" {
statement {
actions = ["ses:SendEmail", "ses:SendRawEmail"]
effect = "Allow"
resources = [
"arn:aws:ses:${local.region}:${data.aws_caller_identity.current.account_id}:identity/*"
]
}
}

resource "aws_iam_group" "ses_group" {
name = "${var.prefix}ses_users"
path = "/"
}
Comment on lines +14 to +17

Check warning

Code scanning / defsec

IAM groups should have MFA enforcement activated. Warning

Multi-Factor authentication is not enforced for group

resource "aws_iam_user" "ses_user" {
count = length(var.mail_users)
name = "ses_${var.mail_users[count.index]}"
path = "/"
}

resource "aws_iam_group_membership" "ses_user_group" {
name = "SES users"
users = aws_iam_user.ses_user[*].name
group = aws_iam_group.ses_group.name
}

resource "aws_iam_group_policy" "ses_group_policy" {
name = "sendMailSES"
group = aws_iam_group.ses_group.name
policy = data.aws_iam_policy_document.ses_policy.json
}

resource "aws_iam_access_key" "ses_user" {
count = length(var.mail_users)
user = aws_iam_user.ses_user[count.index].name
}
24 changes: 24 additions & 0 deletions modules/ses/locals.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
locals {
dkim_record_0 = {
name : "${aws_ses_domain_dkim.ses_domain.dkim_tokens[0]}._domainkey.${var.email_domain}."
record : "${aws_ses_domain_dkim.ses_domain.dkim_tokens[0]}.dkim.amazonses.com."
type : "CNAME"
}
dkim_record_1 = {
name : "${aws_ses_domain_dkim.ses_domain.dkim_tokens[1]}._domainkey.${var.email_domain}."
record : "${aws_ses_domain_dkim.ses_domain.dkim_tokens[1]}.dkim.amazonses.com."
type : "CNAME"
}
dkim_record_2 = {
name : "${aws_ses_domain_dkim.ses_domain.dkim_tokens[2]}._domainkey.${var.email_domain}."
record : "${aws_ses_domain_dkim.ses_domain.dkim_tokens[2]}.dkim.amazonses.com."
type : "CNAME"
}

region = var.region == null ? data.aws_region.current.name : var.region
}

data "aws_route53_zone" "this" {
count = anytrue([var.create_spf_route53, var.create_dkim_route53]) ? 1 : 0
name = var.email_domain
}
35 changes: 35 additions & 0 deletions modules/ses/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
resource "aws_ses_email_identity" "verified_email" {
for_each = { for value in var.verified_email_users : value => value }
email = each.value
}

resource "aws_ses_domain_identity" "verified_domains" {
for_each = { for value in var.verified_domains : value => value }
domain = each.value
}

resource "aws_ses_domain_identity" "ses_domain" {
domain = var.email_domain
}

resource "aws_ses_domain_dkim" "ses_domain" {
domain = var.email_domain
}

resource "aws_route53_record" "spf" {
count = var.create_spf_route53 ? 1 : 0
zone_id = data.aws_route53_zone.this[0].zone_id
name = ""
type = "TXT"
records = ["v=spf1 include:amazonses.com ~all"]
ttl = 600
}

resource "aws_route53_record" "dkim" {
count = var.create_dkim_route53 ? 3 : 0
zone_id = data.aws_route53_zone.this[0].zone_id
name = "${element(aws_ses_domain_dkim.ses_domain.dkim_tokens, count.index)}._domainkey.${var.email_domain}"
type = "CNAME"
ttl = 600
records = ["${element(aws_ses_domain_dkim.ses_domain.dkim_tokens, count.index)}.dkim.amazonses.com"]
}
27 changes: 27 additions & 0 deletions modules/ses/ouputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
output "dkim_records" {
description = "DNS records for DKIM"
value = [local.dkim_record_0, local.dkim_record_1, local.dkim_record_2]
}

output "smtp_credentials" {
value = { for k, v in aws_iam_access_key.ses_user : k =>
{
user = v.user,
password = v.ses_smtp_password_v4
}
}
description = "SMTP Username and Passwort"
sensitive = true
}

output "secret_keys" {
value = { for v in aws_iam_access_key.ses_user : v.user =>
{
user = v.user,
id = v.id
secret = v.secret
}
}
description = "IAM Access Key ID and Secret"
sensitive = true
}
29 changes: 29 additions & 0 deletions modules/ses/tests/basic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# basic

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

No requirements.

## Providers

No providers.

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_ses"></a> [ses](#module\_ses) | ../../ | n/a |

## Resources

No resources.

## Inputs

No inputs.

## Outputs

No outputs.
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
6 changes: 6 additions & 0 deletions modules/ses/tests/basic/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module "ses" {
source = "../../"
email_domain = "devops.dasmeta.com"
mail_users = ["prod"]
verified_domains = ["devops.dasmeta.com"]
}
30 changes: 30 additions & 0 deletions modules/ses/tests/multiple/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# multiple

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

No requirements.

## Providers

No providers.

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_ses"></a> [ses](#module\_ses) | ../../ | n/a |
| <a name="module_ses-virginia"></a> [ses-virginia](#module\_ses-virginia) | ../../ | n/a |

## Resources

No resources.

## Inputs

No inputs.

## Outputs

No outputs.
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
25 changes: 25 additions & 0 deletions modules/ses/tests/multiple/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module "ses" {
source = "../../"
email_domain = "devops.dasmeta.com"
mail_users = ["prod"]
verified_domains = ["devops.dasmeta.com"]
}

module "ses-virginia" {
source = "../../"
email_domain = "devops.dasmeta.com"
mail_users = ["prod-virginia"]
verified_domains = ["devops.dasmeta.com"]
region = "us-east-1"
prefix = "virginia"

providers = {
aws = aws.virginia # Explicitly pass the AWS provider
}
}


provider "aws" {
region = "us-east-1" # Specify the desired AWS region here
alias = "virginia"
}
45 changes: 45 additions & 0 deletions modules/ses/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
variable "region" {
type = string
description = "The region where ressources should be managed."
default = null
}

variable "email_domain" {
type = string
description = "For which sender domain SES should be configured."
}

variable "prefix" {
type = string
description = "Prefix for ses greoup be unique."
default = ""
}

variable "mail_users" {
type = list(string)
description = "User names for mail to create."
}

variable "create_dkim_route53" {
type = bool
description = "If DKIM records should be created in Route 53"
default = false
}

variable "create_spf_route53" {
type = bool
description = "If TXT record for SPF should be created in Route 53"
default = false
}

variable "verified_email_users" {
type = list(string)
default = []
description = "The emails address to assign to SES."
}

variable "verified_domains" {
type = list(string)
default = []
description = "The domain name to assign to SES."
}
Loading