Since I work with multiple accounts in the same computer I always configure a profile on my backend configuration.
# backend.tf
terraform {
backend "s3" {
dynamodb_table = "my-terraform-ddb-lock-table"
bucket = "my-terraform-bucket"
key = "accounts/production/environments/myapp/ses.tfstate"
region = "us-east-1"
encrypt = true
profile = "my-profile"
}
}
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4.0"
}
}
}All my DNS configurations are on CloudFlare.
I always use AWS Secret Manager as my single source of truth for secrets. The service provides important features like key rotation, make sure those secrets are encrypted at rest and only enable specific keys to access these secrets. It makes things easier on CI/CD as well.
I have a specific secret resource for Terraform-related secrets where i stored my CloudFlare API Token as CLOUDFLARE_API_TOKEN.
First, the AWS provider will be loaded since it already has my credentials, fetch the key and then initialize the CloudFlare provider.
The current AWS region will be used later to configure a DNS record.
# data.tf
data "aws_region" "current" {}
data "aws_secretsmanager_secret" "secrets" {
name = "terraform"
}
data "aws_secretsmanager_secret_version" "current" {
secret_id = data.aws_secretsmanager_secret.secrets.id
}# providers.tf
provider "aws" {
region = "us-east-1"
profile = "my-profile"
}
provider "cloudflare" {
api_token = jsondecode(data.aws_secretsmanager_secret_version.current.secret_string)["CLOUDFLARE_API_TOKEN"]
}The domain name will be used to fetch the CloudFlare zone and create the DNS records. You can also read from a variable.
# locals.tf
locals {
domain = "my-domain.com"
}AWS recommends using a subdomain for sending emails so we will do everything based on a subdomain hello. configured in aws_ses_domain_mail_from.
Now we can easily create domains for DKIM, SPF and DMARC and start sending e-mails.
# main.tf
resource "aws_ses_domain_identity" "this" {
domain = local.domain
}
resource "aws_ses_domain_mail_from" "this" {
domain = aws_ses_domain_identity.this.domain
mail_from_domain = "hello.${aws_ses_domain_identity.this.domain}"
}
resource "aws_ses_domain_dkim" "this" {
domain = aws_ses_domain_identity.this.domain
}
data "cloudflare_zones" "this" {
filter {
name = local.domain
}
}
resource "cloudflare_record" "dkim" {
count = 3
zone_id = data.cloudflare_zones.this.zones[0].id
name = "${aws_ses_domain_dkim.this.dkim_tokens[count.index]}._domainkey"
value = "${aws_ses_domain_dkim.this.dkim_tokens[count.index]}.dkim.amazonses.com"
type = "CNAME"
ttl = 600
}
resource "cloudflare_record" "spf_mx" {
zone_id = data.cloudflare_zones.this.zones[0].id
name = aws_ses_domain_mail_from.this.mail_from_domain
value = "feedback-smtp.${data.aws_region.current.name}.amazonses.com"
priority = 10
type = "MX"
ttl = 300
}
resource "cloudflare_record" "spf_txt" {
zone_id = data.cloudflare_zones.this.zones[0].id
name = aws_ses_domain_mail_from.this.mail_from_domain
value = "\"v=spf1 include:amazonses.com ~all\""
type = "TXT"
ttl = 600
}
resource "cloudflare_record" "dmarc" {
zone_id = data.cloudflare_zones.this.zones[0].id
value = "\"v=DMARC1; p=none;\""
name = "_dmarc.${local.domain}"
type = "TXT"
ttl = 300
}