aws / aws-cdk-rfcs

RFCs for the AWS CDK

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cognito Construct Library

nija-at opened this issue · comments

PR Champion
#91 @eladb

Description

Increase coverage of CDK construct library for Cognito to cover a lot more features than it currently does. Where necessary, re-design the APIs so they are more ergonomic and extendible.

Progress

  • Tracking Issue Created
  • RFC PR Created
  • Core Team Member Assigned
  • Initial Approval / Final Comment Period
  • Ready For Implementation
    • implement User Pool construct
    • implement UserPoolUser and UserPoolGroup constructs
    • implement IdentityPool & IdentityPoolRoleAttachment constructs
    • open issues to track unimplemented features
  • Resolved

Curious if there is a current ETA on these features landing/if they are actively being worked on at the moment?

Some of these have started landing - https://github.com/aws/aws-cdk/commits/master/packages/%40aws-cdk/aws-cognito/lib, however, we don't have an ETA.

Is there a particular feature you're looking for?

I'm basically looking to setup a new cognito auth stack, custom domain, some federated logins, attach some custom lambda hooks, etc.

I saw the cognito construct features that landed very recently, but haven't incorporated those yet. So far i've been working around with everything else as required at the Cfn* CloudFormation level + using escape hatches.


Another issue I have just run into (though it's a CloudFormation deficiency, so beyond the scope of CDK, unless you were to roll a custom resource to resolve it) is that it's not currently possible to retrieve the CloudFront target when setting a custom domain, as per aws-cloudformation/cloudformation-coverage-roadmap#356 (Edit: added an example custom resource workaround in my comment)


Also, tangentially related, it would be nice if we could construct a CloudFrontTarget from a string of the distribution's domain name:

A very quick and dirty hacky workaround example:

class CloudFrontFromStringTarget {
  constructor(distributionDomainName) {
    this.distributionDomainName = distributionDomainName
  }
  bind(_record) {
    return {
      // CloudFront Zone ID
      hostedZoneId: 'Z2FDTNDATAQYW2',
      dnsName: this.distributionDomainName
    }
  }
}

For reference, I'll include some code snippets from my project that cover some of the things i needed that aren't yet supported here.

Example: Using a custom domain name with UserPool
const cdk = require('@aws-cdk/core')
const cognito = require('@aws-cdk/aws-cognito')
const cr = require('@aws-cdk/custom-resources')
const route53 = require('@aws-cdk/aws-route53')

/**
 * Configures the UserPool domain used for authentication.
 *
 * @see https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.CfnUserPoolDomain.html
 * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-userpooldomain.html
 * @see https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-assign-domain.html
 */
const userPoolDomain = new cognito.CfnUserPoolDomain(
  this,
  'UserPoolDomain',
  {
    userPoolId: userPool.userPoolId,
    domain: authDomain,
    customDomainConfig: {
      certificateArn,
    },
  }
)
userPoolDomain.node.addDependency(userPool)
new cdk.CfnOutput(this, 'UserPoolDomainValue', {
  value: userPoolDomain.domain,
})

// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CognitoIdentityServiceProvider.html#describeUserPoolDomain-property
const describeCognitoUserPoolDomain = new cr.AwsCustomResource(
  this,
  'DescribeCognitoUserPoolDomain',
  {
    resourceType: 'Custom::DescribeCognitoUserPoolDomain',
    onCreate: {
      region: 'us-east-1',
      service: 'CognitoIdentityServiceProvider',
      action: 'describeUserPoolDomain',
      parameters: {
        Domain: userPoolDomain.domain,
      },
      physicalResourceId: cr.PhysicalResourceId.of(userPoolDomain.domain),
    },
    // TODO: can we restrict this policy more? Get the ARN for the user pool domain? Or the user pool maybe?
    policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
      resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
    }),
  }
)
describeCognitoUserPoolDomain.node.addDependency(userPoolDomain)

const userPoolDomainDistribution = describeCognitoUserPoolDomain.getResponseField(
  'DomainDescription.CloudFrontDistribution'
)
new cdk.CfnOutput(this, 'UserPoolDomainDistribution', {
  value: userPoolDomainDistribution,
})

// Route53 alias record for the UserPoolDomain CloudFront distribution
new route53.ARecord(this, 'UserPoolDomainAliasRecord', {
  recordName: userPoolDomain.domain,
  target: route53.RecordTarget.fromAlias({
    bind: _record => ({
      hostedZoneId: 'Z2FDTNDATAQYW2', // CloudFront Zone ID
      dnsName: userPoolDomainDistribution,
    }),
  }),
  zone,
})
Example: Getting the UserPoolClient secret

Ref: aws/aws-cdk#3037 (comment)

const describeCognitoUserPoolClient = new cr.AwsCustomResource(
  this,
  'DescribeCognitoUserPoolClient',
  {
    resourceType: 'Custom::DescribeCognitoUserPoolClient',
    onCreate: {
      region: 'us-east-1',
      service: 'CognitoIdentityServiceProvider',
      action: 'describeUserPoolClient',
      parameters: {
        UserPoolId: userPool.userPoolId,
        ClientId: userPoolClient.userPoolClientId,
      },
      physicalResourceId: cr.PhysicalResourceId.of(userPoolClient.userPoolClientId),
    },
    // TODO: can we restrict this policy more?
    policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
      resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
    }),
  }
)

const userPoolClientSecret = describeCognitoUserPoolClient.getResponseField(
  'UserPoolClient.ClientSecret'
)
new cdk.CfnOutput(this, 'UserPoolClientSecret', {
  value: userPoolClientSecret,
})

Apologies, but I have removed this comment. Please file a separate bug for issues you are facing. (see aws/aws-cdk#6811) Thanks!
-- @nija-at

Please continue tracking progress on Cognito here - aws/aws-cdk#6765

Resolving this issue.