Skip to content

feat(ses): https policy for custom tracking domain #34314

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

Merged
merged 18 commits into from
May 15, 2025

Conversation

badmintoncryer
Copy link
Contributor

@badmintoncryer badmintoncryer commented Apr 30, 2025

Issue # (if applicable)

None

Reason for this change

Cloudformation supports for configuring HttpsPolicy for custom tracking domain in ConfigurationSet but AWS CDK cannot do this.

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-ses-configurationset-trackingoptions.html#cfn-ses-configurationset-trackingoptions-httpspolicy

Description of changes

  • Define HttpsPolicy enum
  • Add customTrackingHttpsPolicy to ConfigurationSetProps

Describe any new or updated permissions being added

None

Description of how you validated changes

Add both unit and integ tests.

Checklist


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@aws-cdk-automation aws-cdk-automation requested a review from a team April 30, 2025 07:57
@github-actions github-actions bot added p2 distinguished-contributor [Pilot] contributed 50+ PRs to the CDK labels Apr 30, 2025
Copy link
Collaborator

@aws-cdk-automation aws-cdk-automation left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This review is outdated)

@badmintoncryer badmintoncryer changed the title feat feat(ses): https policy for custom tracking domain Apr 30, 2025
@aws-cdk-automation aws-cdk-automation dismissed their stale review April 30, 2025 08:01

✅ Updated pull request passes all PRLinter validations. Dismissing previous PRLinter review.

@@ -189,6 +216,9 @@ export class ConfigurationSet extends Resource implements IConfigurationSet {
throw new ValidationError(`The maximum delivery duration must be less than or equal to 14 hours (50400 seconds), got: ${props.maxDeliveryDuration.toSeconds()} seconds.`, this);
}
}
if (props.customTrackingHttpsPolicy && !props.customTrackingRedirectDomain) {
Copy link
Contributor Author

@badmintoncryer badmintoncryer Apr 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cloudformation causes deployment error in this condition.

code

    new ses.ConfigurationSet(this, 'ConfigurationSet', {
      // customTrackingRedirectDomain: 'tracking.naonao.com',
      customTrackingHttpsPolicy: ses.HttpsPolicy.OPTIONAL,
    });

result

Resource handler returned message: "1 validation error detected: Value at 'trackingOptions.customRedirectDomain' failed to satisfy constraint: Member must not be null (Service: SesV2, Status Code: 400, Request ID: 866fb1c3-dd63-454f-94ec-2ca1bc7b7b1d)" (RequestToken: 05ae07af-ba64-77f8-0cbc-da45a39b8d5f, HandlerErrorCode: InvalidRequest)

/**
* The https policy to use for tracking open and click events.
*
* @default - HttpsPolicy.OPTIONAL if customTrackingRedirectDomain is set, otherwise undefined
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SES default behavior is described in here.

Optional – (Default behavior) Open tracking links will be wrapped using HTTP.

https://docs.aws.amazon.com/ses/latest/dg/creating-configuration-sets.html

@aws-cdk-automation aws-cdk-automation added the pr/needs-community-review This PR needs a review from a Trusted Community Member or Core Team Member. label Apr 30, 2025
Copy link
Contributor

@go-to-k go-to-k left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Left very minor comments. But I can approve it as is if it's better the way it is :)

Comment on lines 66 to 72
new integ.IntegTest(app, 'ConfigurationSetInteg', {
testCases: [new ConfigurationSetStack(app, 'ses-configuration-set-tracking-options-integ', {
hostedZoneId,
hostedZoneName,
domainName,
})],
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about specifying enableLookups: true and stackUpdateWorkflow: false options just in case we forget --disable-update-workflow for the integ command?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know that these options have the same meanings. Thanks!

Copy link
Contributor

@go-to-k go-to-k May 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I misunderstood. The fromHostedZoneAttributes does not look up, so the enableLookups: true was not needed. Could you please remove it?

interface TestStackProps extends StackProps {
hostedZoneId: string;
hostedZoneName: string;
domainName: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the domainName unnecessary?

"EmailIdentity7187767D": {
"Type": "AWS::SES::EmailIdentity",
"Properties": {
"EmailIdentity": "naonao.org"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it okay if you don't keep it hidden?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought there was no particular problem, but just to be safe, I'll use example.com!

Copy link
Contributor Author

@badmintoncryer badmintoncryer May 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that in CI, the domain name would always be example.com, but why were the tests passing without any problems..??

I noticed that this value is derived from not CDK_INTEG_DOMAIN_NAME but CDK_INTEG_HOSTED_ZONE_NAME. But I still don't understand why this integ test had passed. I'll wait for the CI result.

Copy link
Contributor

@go-to-k go-to-k May 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, I missed it.

new integ.IntegTest(app, 'ConfigurationSetInteg', {
  testCases: [new ConfigurationSetStack(app, 'ses-configuration-set-tracking-options-integ', {
    hostedZoneId,
    hostedZoneName,
  })],

Two stacks must be explicitly specified for testCases. The stack not specified would not be checked.

This means that we must generate the two stacks separately, define their dependencies with addDependency, and specify the stacks in testCases.

Also, you now specify ConfigurationSetStack for the scope of IdentityStack, but need to specify app instead.

P.S.

define their dependencies with addDependency

The value originally generated by IdentityStack is used by ConfigurationSetStack, so no explicit dependency is needed.

Copy link
Contributor

@go-to-k go-to-k May 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, if you make it a target of snapshot verification, this test can only be performed by you who own that domain in the future.
For this reason, we would need to either exclude the stack from the targets, or prompt developers to rewrite the generated template. (If it is good and safe to detect changes to the stack by other PRs about the EmailIdentity too, would the latter be a good idea...? like: https://github.com/aws/aws-cdk/blob/v2.195.0/packages/@aws-cdk-testing/framework-integ/test/aws-codepipeline-actions/test/integ.pipeline-ecr-build-and-publish-private.ts#L15)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, since domain verification on EmailIdentity takes several dozen seconds, when defined as two stacks with dependencies on the same app, the ConfigurationSetStack deployment begins before authentication is complete, resulting in a deployment error. At first, I had created this integ test like that.

As a workaround, I've made it a nested stack to significantly delay the start of ConfigurationSetStack deployment, ensuring that deployment executes after domain verification is complete.
(Therefore, I think this test deployment could be flaky and may fail in some cases.)

I'm wondering if it might be better to simply create EmailIdentity in advance and only test ConfigurationSetStack.
What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if it might be better to simply create EmailIdentity in advance and only test ConfigurationSetStack.

Agree with it! There should be no need to make this in CDK.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated integ test like that!

@badmintoncryer
Copy link
Contributor Author

@go-to-k Thank you for your review!! I've addressed your comments.

*
* Step 1: Create a public hosted zone in Route53
* Step 2: Create a email identity in SES and validate it with the hosted zone
* Step 3: Set the domain name as an env var "DOMAIN_NAME"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const domainName = process.env.CDK_INTEG_DOMAIN_NAME ?? process.env.DOMAIN_NAME;

In this case, CDK_INTEG_DOMAIN_NAME is set to '*.example.com' in integ-runner.

https://github.com/aws/aws-cdk-cli/blob/main/packages/@aws-cdk/integ-runner/lib/runner/runner-base.ts#L433

At this time, even if we set DOMAIN_NAME, it won't be reflected?

Copy link
Contributor Author

@badmintoncryer badmintoncryer May 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CDK_INTEG_DOMAIN_NAME is only set in CI environment and I could execute integ test with my domain by setting DOMAIN_NAME. (But I don't know why the CDK_INTEG_DOMAIN_NAME env is not set during local integ test execution.)

This implementation is used in other integ tests.

Additionally, I need to add to the procedure that the domain name must be corrected to example.com in the generated CloudFormation template.

if (!hostedZoneId) throw new Error('For this test you must provide your own HostedZoneId as an env var "HOSTED_ZONE_ID". See framework-integ/README.md for details.');
const hostedZoneName = process.env.CDK_INTEG_HOSTED_ZONE_NAME ?? process.env.HOSTED_ZONE_NAME;
if (!hostedZoneName) throw new Error('For this test you must provide your own HostedZoneName as an env var "HOSTED_ZONE_NAME". See framework-integ/README.md for details.');
const domainName = process.env.CDK_INTEG_DOMAIN_NAME ?? process.env.DOMAIN_NAME;
Copy link
Contributor

@go-to-k go-to-k May 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it CDK_INTEG_HOSTED_ZONE_NAME (example.com) instead of CDK_INTEG_DOMAIN_NAME (*.example.com)?

related: https://github.com/aws/aws-cdk/pull/34314/files#r2086912984

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are exactly right! I'll fix this.

Copy link
Contributor

@go-to-k go-to-k left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the changes, LGTM!

@badmintoncryer
Copy link
Contributor Author

@go-to-k Thanks always!

@aws-cdk-automation aws-cdk-automation added pr/needs-maintainer-review This PR needs a review from a Core Team Member and removed pr/needs-community-review This PR needs a review from a Trusted Community Member or Core Team Member. labels May 14, 2025
testCases: [new ConfigurationSetStack(app, 'ses-configuration-set-tracking-options-integ', {
hostedZoneName,
})],
stackUpdateWorkflow: false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wondering why disable the update workflow?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is described in here and I don't know why this is required..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Thanks for the pointer. Make sense to skip the update workflow as the fake hosted zone name will not deploy successfully.

@samson-keung samson-keung self-assigned this May 15, 2025
@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildv2Project1C6BFA3F-wQm2hXv2jqQv
  • Commit ID: f361776
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

Copy link
Contributor

@samson-keung samson-keung left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

testCases: [new ConfigurationSetStack(app, 'ses-configuration-set-tracking-options-integ', {
hostedZoneName,
})],
stackUpdateWorkflow: false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Thanks for the pointer. Make sense to skip the update workflow as the fake hosted zone name will not deploy successfully.

Copy link
Contributor

mergify bot commented May 15, 2025

Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

@mergify mergify bot merged commit 60d7aea into aws:main May 15, 2025
18 checks passed
Copy link
Contributor

Comments on closed issues and PRs are hard for our team to see.
If you need help, please open a new issue that references this one.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 15, 2025
@aws-cdk-automation aws-cdk-automation removed the pr/needs-maintainer-review This PR needs a review from a Core Team Member label May 15, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
distinguished-contributor [Pilot] contributed 50+ PRs to the CDK p2
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants