Open beanaroo opened 4 years ago
@beanaroo did you ever find a workaround or solution to this problem? I'm having the same issue trying to implement SES across multiple accounts.
@jnewton03 Unfortunately no solution but a less than ideal workaround...
We've moved all SES and ACM resources into our Route53 module that's used by a single state. This now requires some double-handling when introducing/removing resources and introduced tight coupling between our environment states and the common resources account state that hosts Route53.
We'd still benefit from the above capability.
@jnewton03 After struggling with this for a long time I ended up with the following solution:
# Create the Verification Token
resource aws_ses_domain_identity example_com {
domain = "example.com"
}
# Read the existing SES TXT record from DNS
data dns_txt_record_set ses_txt {
host = "_amazonses.example.com"
}
# Write (or overwrite) the verification TXT record adding the new record to the
# existing records (if it isn't already there)
resource aws_route53_record ses_txt {
allow_overwrite = true
zone_id = data.aws_route53_zone.example_com.id
name = "_amazonses.example.com"
ttl = 600
type = "TXT"
records = toset(concat(data.dns_txt_record_set.ses_txt.records, [
aws_ses_domain_identity.example_com.verification_token]))
lifecycle {
prevent_destroy = true
}
}
The trick is that allow_overwrite = true
will allow multiple Terraform workspaces to write to the "same" record. The prevent_destroy = true
option prevents the record from being deleted. This is also the biggest problem, tokens are never removed. If SES instances are being brought up and torn down regularly, that might be a problem.
I would love to hear if anyone can find other drawbacks to this approach. It's definitely a hack but it's all I can come up with.
I would also like to know why Amazon's SES verification records can't be like the DKIM records where the name of the TXT record includes a unique token.
@mousedownmike that's a nice trick!. Works for me and handles the problem good enough. Thanks for your msg.
Superb solution would be (don't ask me what, I think it doesn't exist) something that could customize the resource while destroying. omething like : "If [destroying] then parse all existing records, EXCLUDE my verification token, and save the rest." And after apply, discard the tfstate resource. I know, that's all logic beyond the design pattern of Terraform. But using null providers and that dirty hacks, maybe we could do some create-maintain-delete lifecycle for this scenarios: multi-account DNS maintenance. (SES, ACM, etc)
I ran into this limitation today too. In my case, I was trying to replace a TXT record with a consistent prefix (specifically a SPF record) so I was able to update the record in-place.
# Read the existing TXT record from DNS
# See the DNS provider: https://registry.terraform.io/providers/hashicorp/dns/latest/docs
data dns_txt_record_set example_txt {
host = "example.com"
}
# Declare the desired SPF record
locals {
spf_record = "v=spf1 ?all"
}
# Create/update the SPF record, preserving all other TXT records.
resource aws_route53_record spf_txt {
allow_overwrite = true
zone_id = data.aws_route53_zone.example_com.id
name = "example.com"
ttl = 600
type = "TXT"
# ⭐ HERE'S THE MAGIC BIT ⭐
records = toset(concat([ # 💡 Deduplicate the TXT records
for r in data.dns_txt_record_set.example_txt.records :
startswith(r, "v=spf1") ? local.spf_record : r # 💡(update) Replace existing SPF record(s) with the declared one
], [local.spf_record])) # 💡 (create) Add the SPF record to the list
# ⭐ END MAGIC ⭐
lifecycle {
prevent_destroy = true
}
}
This approach ensures the desired SPF record appears once in the TXT record set, preserving all other existing TXT records. The for expression replaces all existing SPF records with the declared one. Then, the declared SPF record is concat
enated into the list to handle the case where no SPF record yet exists. But since the concat
duplicates the SPF record when it already exists, toset
is required to remove that duplication.
Note that this approach fails when a TXT entry has more than 255 characters since that entry will span multiple records, resulting in only a partial replacement.
Community Note
Description
This poses a problem when sharing a domain across states (accounts/environments/stages) for things like ACM (SSL) and SES (Email).
For example, AWS Workmail will create a TXT record for
_amazonses.acme.com.
Terraforming an SES domain identity along with validation fails because the above record already exists. The same is true when adding any additional SES domain identity for the same domain in another region and/or account.
Since Amazon does not permit multiple TXT records for a domain, it would be ideal if Terraform could manage the values independently.
New or Affected Resource(s)
Potential Terraform Configuration
Alternatives
If someone can provide alternative solutions to sharing a TXT record across states/accounts/regions/stages/environments, recommendations are welcome.