Skip to content

Commit

Permalink
feat(cognito): new cloudFrontEndpoint method for user pool domain w…
Browse files Browse the repository at this point in the history
…ithout custom resource (#31402)

### Issue # (if applicable)

Closes #31342.

### Reason for this change



`UserPoolDomain` creates a custom resource to get CloudFront endpoint. However, CFn exposes the attribute natively now (see the issue). No custom resource is better if it is not needed.

### Description of changes



I propose a new method `cloudFrontEndpoint` without a custom resource.

Three ways were originally considered. This method was chosen as it was the most reasonable of all.

#### 1. Create a new method

This is the method submitted in this PR.

#### 2. Rewrite an existing method directly

This causes destructive changes. Custom resources are not directly used in the user's application. However, this change will result in resource deletion in the user's CDK stack. This causes confusion for users and should be avoided.

Also, the existing integ tests that use the method will fail because the changes are considered as destructive changes.

```
Tests:    1 failed, 1 total
Failed: /aws-cdk/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-domain-cfdist.js
!!! This test contains destructive changes !!!
    Stack: integ-user-pool-domain-cfdist - Resource: UserPoolDomainCloudFrontDomainNameE213E594 - Impact: WILL_DESTROY
    Stack: integ-user-pool-domain-cfdist - Resource: UserPoolDomainCloudFrontDomainNameCustomResourcePolicy7DE54188 - Impact: WILL_DESTROY
    Stack: integ-user-pool-domain-cfdist - Resource: AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2 - Impact: WILL_DESTROY
    Stack: integ-user-pool-domain-cfdist - Resource: AWS679f53fac002430cb0da5b7982bd22872D164C4C - Impact: WILL_DESTROY
!!! If these destructive changes are necessary, please indicate this on the PR !!!
Error: Some changes were destructive!
    at main (/aws-cdk/packages/@aws-cdk/integ-runner/lib/cli.js:183:15)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
```

#### 3. Rewrite an existing method with a feature flag

An alternative to way 2, but a feature flag was avoided in this case as it leads to complexity. The [design guidelines](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md#dealing-with-breaking-behavior-changes) also recommend a new method.

### Additional information

I avoided the feature flag in this PR, but there are situations where there are constructs that use an existing method, but cannot provide a new method for the constructs because it is used by a method implemented in the interface. 

https://github.com/go-to-k/aws-cdk/blob/fcbdc769e681f1f915cdc8cd7aa3a565d807884d/packages/aws-cdk-lib/aws-route53-targets/lib/userpool-domain.ts#L14

I will make changes to those cases using a feature flag in a separate PR.

#31403

### Description of how you validated changes



Both unit and integ tests.

### Checklist
- [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md)

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
go-to-k authored Nov 27, 2024
1 parent af5345e commit deeb2ad
Show file tree
Hide file tree
Showing 13 changed files with 105 additions and 19 deletions.

This file was deleted.

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@
"S3Bucket": {
"Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}"
},
"S3Key": "746da84b10e215c552e68b6d2061024e4429f0386f43a35ef5e4d2940655692e.zip"
"S3Key": "9e8936ba1db43e0919ba2fc8265d50686eeaca82830c471ff8b7b0672c5970ec.zip"
},
"Handler": "index.handler",
"Role": {
Expand Down Expand Up @@ -186,6 +186,14 @@
"DomainDescription.CloudFrontDistribution"
]
}
},
"CloudFrontEndpoint": {
"Value": {
"Fn::GetAtt": [
"UserPoolDomainD0EA232A",
"CloudFrontDistribution"
]
}
}
},
"Mappings": {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ new CfnOutput(stack, 'Domain', {
new CfnOutput(stack, 'CloudFrontDomainName', {
value: domain.cloudFrontDomainName,
});

new CfnOutput(stack, 'CloudFrontEndpoint', {
value: domain.cloudFrontEndpoint,
});
18 changes: 17 additions & 1 deletion packages/aws-cdk-lib/aws-cognito/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw
- [Table of Contents](#table-of-contents)
- [User Pools](#user-pools)
- [Sign Up](#sign-up)
- [Code Verification](#code-verification)
- [Link Verification](#link-verification)
- [Sign In](#sign-in)
- [Attributes](#attributes)
- [Attribute verification](#attribute-verification)
Expand Down Expand Up @@ -925,7 +927,6 @@ const fullAccessClient = pool.addClient('full-access-client', {
});
```


### Domains

After setting up an [app client](#app-clients), the address for the user pool's sign-up and sign-in webpages can be
Expand Down Expand Up @@ -994,6 +995,21 @@ Existing domains can be imported into CDK apps using `UserPoolDomain.fromDomainN
const myUserPoolDomain = cognito.UserPoolDomain.fromDomainName(this, 'my-user-pool-domain', 'domain-name');
```

To get the domain name of the CloudFront distribution associated with the user pool domain, use `cloudFrontEndpoint` method.

```ts
const userpool = new cognito.UserPool(this, 'UserPool');
const domain = userpool.addDomain('Domain', {
cognitoDomain: {
domainPrefix: 'my-awesome-app',
},
});

new CfnOutput(this, 'CloudFrontEndpoint', {
value: domain.cloudFrontEndpoint,
});
```

### Deletion protection

Deletion protection can be enabled on a user pool to prevent accidental deletion:
Expand Down
16 changes: 14 additions & 2 deletions packages/aws-cdk-lib/aws-cognito/lib/user-pool-domain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export class UserPoolDomain extends Resource implements IUserPoolDomain {
private isCognitoDomain: boolean;

private cloudFrontCustomResource?: AwsCustomResource;
private readonly resource: CfnUserPoolDomain;

constructor(scope: Construct, id: string, props: UserPoolDomainProps) {
super(scope, id);
Expand All @@ -114,18 +115,29 @@ export class UserPoolDomain extends Resource implements IUserPoolDomain {
this.isCognitoDomain = !!props.cognitoDomain;

const domainName = props.cognitoDomain?.domainPrefix || props.customDomain?.domainName!;
const resource = new CfnUserPoolDomain(this, 'Resource', {
this.resource = new CfnUserPoolDomain(this, 'Resource', {
userPoolId: props.userPool.userPoolId,
domain: domainName,
customDomainConfig: props.customDomain ? { certificateArn: props.customDomain.certificate.certificateArn } : undefined,
});

this.domainName = resource.ref;
this.domainName = this.resource.ref;
}

/**
* The domain name of the CloudFront distribution associated with the user pool domain.
*/
public get cloudFrontEndpoint(): string {
return this.resource.getAtt('CloudFrontDistribution').toString();
}

/**
* The domain name of the CloudFront distribution associated with the user pool domain.
*
* This method creates a custom resource internally to get the CloudFront domain name.
*
* @deprecated use `cloudFrontEndpoint` method instead.
*/
public get cloudFrontDomainName(): string {
if (!this.cloudFrontCustomResource) {
const sdkCall: AwsSdkCall = {
Expand Down
26 changes: 24 additions & 2 deletions packages/aws-cdk-lib/aws-cognito/test/user-pool-domain.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { testDeprecated } from '@aws-cdk/cdk-build-tools';
import { Template } from '../../assertions';
import { Certificate } from '../../aws-certificatemanager';
import { CfnParameter, Stack } from '../../core';
Expand Down Expand Up @@ -103,7 +104,7 @@ describe('User Pool Domain', () => {
})).not.toThrow();
});

test('custom resource is added when cloudFrontDomainName property is used', () => {
testDeprecated('custom resource is added when cloudFrontDomainName property is used', () => {
// GIVEN
const stack = new Stack();
const pool = new UserPool(stack, 'Pool');
Expand Down Expand Up @@ -137,7 +138,7 @@ describe('User Pool Domain', () => {
});
});

test('cloudFrontDomainName property can be called multiple times', () => {
testDeprecated('cloudFrontDomainName property can be called multiple times', () => {
const stack = new Stack();
const pool = new UserPool(stack, 'Pool');
const domain = pool.addDomain('Domain', {
Expand All @@ -152,6 +153,27 @@ describe('User Pool Domain', () => {
expect(cfDomainNameSecond).toEqual(cfDomainNameFirst);
});

test('cloudFrontEndpoint property can be called without custom resource', () => {
const stack = new Stack();
const pool = new UserPool(stack, 'Pool');
const domain = pool.addDomain('Domain', {
cognitoDomain: {
domainPrefix: 'cognito-domain-prefix',
},
});

const cloudFrontEndpoint = domain.cloudFrontEndpoint;

expect(stack.resolve(cloudFrontEndpoint)).toEqual({
'Fn::GetAtt': [
'PoolDomainCFC71F56',
'CloudFrontDistribution',
],
});

Template.fromStack(stack).resourceCountIs('Custom::UserPoolCloudFrontDomainName', 0);
});

test('import', () => {
// GIVEN
const stack = new Stack();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Fixture with packages imported, but nothing else
import { Duration, Stack } from 'aws-cdk-lib';
import { CfnOutput, Duration, Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as certificatemanager from 'aws-cdk-lib/aws-certificatemanager';
import * as cognito from 'aws-cdk-lib/aws-cognito';
Expand Down

0 comments on commit deeb2ad

Please sign in to comment.