Skip to content

(cognito): UserPoolDomain baseUrl is incorrect in us-gov-west-1 #20182

Closed
@laurelmay

Description

@laurelmay

Describe the bug

In the us-gov-west-1 region, the Cognito Hosted UI always uses the fips endpoint (<domain-prefix>.auth-fips.<region>.amazoncognito.com). The UserPoolDomain.baseUrl function assumes the endpoint is always <prefix>.auth.<region>.amazoncognito.com. This results in a value that does not work in us-gov-west-1.

Expected Behavior

I expected calling baseUrl to return a URL that works in my current region.

Current Behavior

Calling baseUrl() returns a URL that does not work in us-gov-west-1.

Reproduction Steps

import 'source-map-support/register';
import * as cdk from "aws-cdk-lib";
import * as cognito from "aws-cdk-lib/aws-cognito";

const UNIQUE_PREFIX = "sample";

const app = new cdk.App();
const stack = new cdk.Stack(app, "DomainBroken");
const userPool = new cognito.UserPool(stack, "UserPool");
const domain = userPool.addDomain("domain", {
  cognitoDomain: {
    domainPrefix: UNIQUE_PREFIX,
  },
});
new cdk.CfnOutput(stack, "Domain", { value: domain.baseUrl() });

Change the UNIQUE_PREFIX constant to actually contain a unique value and deploy this stack to us-gov-west-1 and try to navigate to the URL contained in the DomainBroken.Domain output. The name does not resolve.

Because I understand that not everyone has access to GovCloud, I have deployed a sample stack setting UNIQUE_PREFIX to govrepro. The CDK returns https://govrepro.auth.us-gov-west-1.amazoncognito.com; however, that does not resolve. https://govrepro.auth-fips.us-gov-west-1.amazoncognito.com does.

Possible Solution

Adding a parameter to baseUrl

This could be fixed by adding an optional fips?: boolean parameter to baseUrl (that defaults to false). The nice side effect here is that you'd be able to get FIPS URLs for Hosted UIs in US East/West and other regions that support it; the downside is that users may pass true in regions that do not support FIPS endpoints.

Code for adding FIPS parameter
diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool-domain.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool-domain.ts
index b201b3153..a9859b7c5 100644
--- a/packages/@aws-cdk/aws-cognito/lib/user-pool-domain.ts
+++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-domain.ts
@@ -152,10 +152,13 @@ export class UserPoolDomain extends Resource implements IUserPoolDomain {
 
   /**
    * The URL to the hosted UI associated with this domain
+   *
+   * @param fips whether to return the fips variant of the hosted UI
    */
-  public baseUrl(): string {
+  public baseUrl(fips?: boolean): string {
     if (this.isCognitoDomain) {
-      return `https://${this.domainName}.auth.${Stack.of(this).region}.amazoncognito.com`;
+      const authBase = 'auth' + (fips ? '-fips' : '');
+      return `https://${this.domainName}.${authBase}.${Stack.of(this).region}.amazoncognito.com`;
     }
     return `https://${this.domainName}`;
   }

Using a CfnCondition

Because this only impacts a single region (for now), it's possible baseUrl could return a CloudFormation condition but that scales poorly and adds a condition in the stack.

Code for using a CloudFormation condition
diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool-domain.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool-domain.ts
index b201b3153..dc958f01f 100644
--- a/packages/@aws-cdk/aws-cognito/lib/user-pool-domain.ts
+++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-domain.ts
@@ -1,5 +1,5 @@
 import { ICertificate } from '@aws-cdk/aws-certificatemanager';
-import { IResource, Resource, Stack, Token } from '@aws-cdk/core';
+import { CfnCondition, Fn, IResource, Resource, Stack, Token } from '@aws-cdk/core';
 import { AwsCustomResource, AwsCustomResourcePolicy, AwsSdkCall, PhysicalResourceId } from '@aws-cdk/custom-resources';
 import { Construct } from 'constructs';
 import { CfnUserPoolDomain } from './cognito.generated';
@@ -154,10 +154,17 @@ export class UserPoolDomain extends Resource implements IUserPoolDomain {
    * The URL to the hosted UI associated with this domain
    */
   public baseUrl(): string {
-    if (this.isCognitoDomain) {
-      return `https://${this.domainName}.auth.${Stack.of(this).region}.amazoncognito.com`;
+    if (!this.isCognitoDomain) {
+      return `https://${this.domainName}`;
     }
-    return `https://${this.domainName}`;
+    const isGovCondition = new CfnCondition(this, "IsGovWest", {
+      expression: Fn.conditionEquals(Stack.of(this).region, "us-gov-west-1")
+    });
+    return Fn.conditionIf(
+      isGovCondition.logicalId,
+      `https://${this.domainName}.auth-fips.${Stack.of(this).region}.amazoncognito.com`,
+      `https://${this.domainName}.auth.${Stack.of(this).region}.amazoncognito.com`
+    ).toString();
   }
 
   /**

Using region-info

This also feels like a good use case for a region-info in some ways, though, us-gov-west-1 is really the only "special" region I am aware of. The service is not yet available in other US government regions nor are User Pools available yet in aws-cn.

Adding Documentation

It would also be possible to just add documentation saying that the function doesn't work in GovCloud and to provide a workaround.

Documentation patch
diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool-domain.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool-domain.ts
index b201b3153..5f71fdf25 100644
--- a/packages/@aws-cdk/aws-cognito/lib/user-pool-domain.ts
+++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-domain.ts
@@ -152,6 +152,10 @@ export class UserPoolDomain extends Resource implements IUserPoolDomain {
 
   /**
    * The URL to the hosted UI associated with this domain
+   *
+   * The URL returned by this method will not work in us-gov-west-1 as it does not return
+   * a FIPS-compliant endpoint URL. Instead, build the URL manually using a format such as:
+   * `https://${domain.domainName}.auth-fips.${Stack.of(domain).region}.amazoncognito.com`.
    */
   public baseUrl(): string {
     if (this.isCognitoDomain) {

Additional Information/Context

The Amazon Cognito service in AWS GovCloud (US) does not support custom domains, so the only available option is a prefixed Cognito domain.

FIPS endpoints are available but not required in us-east-1, us-east-2, us-west-1, and us-west-2.

CDK CLI Version

2.22.0

Framework Version

No response

Node.js Version

16.14.1

OS

Fedora

Language

Typescript

Language Version

No response

Other information

I am happy to help implement a fix for this issue.

Metadata

Metadata

Assignees

Labels

@aws-cdk/aws-cognitoRelated to Amazon CognitobugThis issue is a bug.needs-triageThis issue or PR still needs to be triaged.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions