aws-ses: DKIM records are created with incorrect name from EmailIdentity
See original GitHub issueDescribe the bug
When creating a new ses.EmailIdentity
construct, the names of the DKIM records that get created in Route53 are incorrect.
Expected Behavior
If the DKIM record name is x.y.example.com
, and the hosted zone is y.example.com
, the name of the record that gets set in Route53 should be x.y.example.com
Current Behavior
If the DKIM record name is x.y.example.com
, and the hosted zone is y.example.com
, the name of the record that gets set in Route53 should is x.y.example.com.y.example.com
Reproduction Steps
Here is a simple reproduction case:
const myHostedZone = ...; // However you're grabbing or creating your hosted zone
const sesIdentity = new ses.EmailIdentity(this, "ses-identity", {
identity: ses.Identity.publicHostedZone(hostedZone),
mailFromDomain: `mail.${hostedZoneDomain}`,
});
Possible Solution
The reason for the incorrect record names is because of the function here in the source code:.
It calls route53.CnameRecord
, which accepts a record name excluding the hosted zone suffix - eg. for x.y.example.com
where the hosted zone is y.example.com
, the record name should just be x
.
However, it’s passing in dkimDnsTokenName1
etc, which according to the Cloudformation docs, is the entire host for the record, including the hosted zone.
This means that route53.CnameRecord
tried to append the hosted zone name onto the end of the record name which already includes the hosted zone name, leading to the duplication.
This can be seen in a cdk synth
:
...
Type: AWS::Route53::RecordSet
Properties:
Name:
Fn::Join:
- ""
- - Fn::GetAtt:
- <Our SES Entity ID>
- DkimDNSTokenName1
- .y.example.com.
Type: CNAME
...
There are 2 fixes that I can think of:
- Call
CfnRecordSet
rather thanCnameRecord
- eg:
new route53.CfnRecordSet(emailIdentity, "DkimDnsToken1", {
hostedZoneName: hostedZone.zoneName + ".",
name: Lazy.string({ produce: () => emailIdentity.dkimDnsTokenName1 }),
type: "CNAME",
resourceRecords: [Lazy.string({ produce: () => emailIdentity.dkimDnsTokenValue1 })],
ttl: "1800",
})
- Use a hacky workaround to lop off the suffix before passing to
CnameRecord
- by combiningcdk.Fn.select
andcdk.Fn.split
to remove the last part of the string. Here’s how that would look:
// This function removes a string from the end of another string using Cfn functions.
// For example, calling it on "abcd" with suffix "cd" would return "ab".
// We accomplish this by splitting by the suffix (which gives ["ab"]), then selecting the 0th value.
const hackyCfnRemoveSuffix = (sourceString: string, suffixToRemove: string) =>
cdk.Fn.select(0, cdk.Fn.split(suffixToRemove, sourceString));
// Then use it in the bind function
new route53.CnameRecord(emailIdentity, 'DkimDnsToken1', {
zone: hostedZone,
recordName: hackyCfnRemoveSuffix(Lazy.string({ produce: () => emailIdentity.dkimDnsTokenName1 }), "." + hostedZone.zoneName),
domainName: Lazy.string({ produce: () => emailIdentity.dkimDnsTokenValue1 }),
});
Additional Information/Context
No response
CDK CLI Version
2.29.0 (build 47d7ec4)
Framework Version
2.33.0
Node.js Version
v16.15.1
OS
MacOS
Language
Typescript
Language Version
No response
Other information
Workaround
For anyone else experiencing this issue - we’ve opted to go with the CfnRecordSet
option as it’s a bit simpler to see what’s going on. Simply map through each of the dkimRecords
after creating the EmailIdentity
and create the correct records - note that this won’t remove the incorrect ones unfortunately.
Code below:
// Create SES email identity based on Route53 hosted zone
const sesIdentity = new ses.EmailIdentity(this, "ses-identity", {
identity: ses.Identity.publicHostedZone(hostedZone),
mailFromDomain: `mail.${hostedZone.zoneName}`,
});
// Temporary workaround: There is a bug with the EmailIdentity construct where if the DKIM record is x.y.example.com,
// and the hosted zone is y.example.com, the record that gets set is x.y.example.com.y.example.com. For now, we are
// manually creating the correct records.
const dkimCnameRecords = sesIdentity.dkimRecords.map(
(dkimRecord, index) =>
new route53.CfnRecordSet(this, `dkim-record-${index}`, {
hostedZoneName: hostedZone.zoneName + ".",
name: dkimRecord.name,
type: "CNAME",
resourceRecords: [dkimRecord.value],
ttl: "1800",
})
);
Issue Analytics
- State:
- Created a year ago
- Reactions:4
- Comments:6 (3 by maintainers)
Thanks for the fix! Just a note for @derekmurawsky and anyone else that was using the workaround I mentioned in the original issue and is wanting to upgrade to the fixed version of CDK.
When upgrading the version to get rid of the need for the workaround, we weren’t able to do it all in 1 deployment, as the DKIM records created by the workaround got deleted, but did not get re-created by the now fixed EmailIdentity.
We had to do the following:
CfnRecordSet
s (see above) and deploy. This will temporarily remove your correct DKIM records.OK, got it, I see the duplication in the record.