From 9f92e856d3bbb4f0f310126fb56febb98e28f587 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 1 Oct 2025 16:02:04 +0100 Subject: [PATCH] set up of AWS SES --- infrastructure/terraform/main.tf | 13 ++++ infrastructure/terraform/modules/ses/main.tf | 50 ++++++++++++++ .../terraform/modules/ses/outputs.tf | 66 +++++++++++++++++++ .../terraform/modules/ses/variables.tf | 9 +++ 4 files changed, 138 insertions(+) create mode 100644 infrastructure/terraform/modules/ses/main.tf create mode 100644 infrastructure/terraform/modules/ses/outputs.tf create mode 100644 infrastructure/terraform/modules/ses/variables.tf diff --git a/infrastructure/terraform/main.tf b/infrastructure/terraform/main.tf index 10ef31c2..c2840d62 100644 --- a/infrastructure/terraform/main.tf +++ b/infrastructure/terraform/main.tf @@ -261,4 +261,17 @@ module "cloudfront_distribution" { bucket_arn = module.s3.bucket_arn bucket_domain_name = module.s3.bucket_domain_name stage = var.stage +} + +################################################ +# SES - Email sending +################################################ +module "ses" { + source = "./modules/ses" + domain_name = "domna.homes" + stage = var.stage +} + +output "ses_dns_records" { + value = module.ses.dns_records } \ No newline at end of file diff --git a/infrastructure/terraform/modules/ses/main.tf b/infrastructure/terraform/modules/ses/main.tf new file mode 100644 index 00000000..e8f183ae --- /dev/null +++ b/infrastructure/terraform/modules/ses/main.tf @@ -0,0 +1,50 @@ +resource "aws_ses_domain_identity" "this" { + domain = var.domain_name +} + +# DKIM signing +resource "aws_ses_domain_dkim" "this" { + domain = aws_ses_domain_identity.this.domain +} + +# IAM user for SES SMTP +resource "aws_iam_user" "ses_user" { + name = "${var.stage}-ses-user" +} + +resource "aws_iam_user_policy" "ses_send_policy" { + name = "AllowSESSendEmail" + user = aws_iam_user.ses_user.name + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "ses:SendEmail", + "ses:SendRawEmail" + ] + Resource = "*" + } + ] + }) +} + +resource "aws_iam_access_key" "ses_user" { + user = aws_iam_user.ses_user.name +} + +# Store SMTP credentials in AWS Secrets Manager +resource "aws_secretsmanager_secret" "ses_smtp" { + name = "${var.stage}/ses/smtp_credentials" + description = "SMTP credentials for SES (${var.stage})" +} + +resource "aws_secretsmanager_secret_version" "ses_smtp" { + secret_id = aws_secretsmanager_secret.ses_smtp.id + secret_string = jsonencode({ + username = aws_iam_access_key.ses_user.id + password = aws_iam_access_key.ses_user.ses_smtp_password_v4 + }) +} \ No newline at end of file diff --git a/infrastructure/terraform/modules/ses/outputs.tf b/infrastructure/terraform/modules/ses/outputs.tf new file mode 100644 index 00000000..de708983 --- /dev/null +++ b/infrastructure/terraform/modules/ses/outputs.tf @@ -0,0 +1,66 @@ +# These are our DNS records that will need to be added to our Krystal account + +# TXT record +output "verification_record" { + description = "TXT record required to verify the domain with SES" + value = { + name = "_amazonses.${aws_ses_domain_identity.this.domain}" + type = "TXT" + value = aws_ses_domain_identity.this.verification_token + } +} + +# DKIM CNAME records +output "dkim_records" { + description = "CNAME records required to enable DKIM for SES" + value = [ + for dkim in aws_ses_domain_dkim.this.dkim_tokens : { + name = "${dkim}._domainkey.${aws_ses_domain_identity.this.domain}" + type = "CNAME" + value = "${dkim}.dkim.amazonses.com" + } + ] +} + +# SMTP credentials - send them to secrets manager +output "ses_smtp_secret_arn" { + description = "ARN of the SES SMTP credentials stored in Secrets Manager" + value = aws_secretsmanager_secret.ses_smtp.arn +} + +output "smtp_password" { + value = aws_iam_access_key.ses_user.ses_smtp_password_v4 + sensitive = true + description = "SMTP password for SES" +} + +output "dns_records" { + description = "All DNS records required for SES verification and recommended deliverability" + value = concat( + [ + { + name = "_amazonses.${aws_ses_domain_identity.this.domain}" + type = "TXT" + value = aws_ses_domain_identity.this.verification_token + }, + { + name = var.domain_name + type = "TXT" + value = "v=spf1 include:amazonses.com -all" + }, + { + name = "_dmarc.${var.domain_name}" + type = "TXT" + value = "v=DMARC1; p=quarantine; rua=mailto:postmaster@${var.domain_name}" + } + ], + [ + for dkim in aws_ses_domain_dkim.this.dkim_tokens : { + name = "${dkim}._domainkey.${aws_ses_domain_identity.this.domain}" + type = "CNAME" + value = "${dkim}.dkim.amazonses.com" + } + ] + ) +} + diff --git a/infrastructure/terraform/modules/ses/variables.tf b/infrastructure/terraform/modules/ses/variables.tf new file mode 100644 index 00000000..d8c97d6d --- /dev/null +++ b/infrastructure/terraform/modules/ses/variables.tf @@ -0,0 +1,9 @@ +variable "domain_name" { + description = "The domain to verify with SES (e.g. domna.homes)" + type = string +} + +variable "stage" { + description = "Deployment stage (e.g. dev, prod)" + type = string +}