Создание пула пользователей Cognito с пользовательским доменным именем из AWS CDK

Я пытаюсь создать пул пользователей Cognito с собственным доменным именем через AWS CDK. Мне удается заставить все работать до точки, когда мне нужно было создать A запись в Rout53 размещенной зоне. Я просмотрел все документы, но не смог найти способа сделать это. Ниже мой код. Любая помощь будет очень приветствоваться.

      const cfnUserPool = new CfnUserPool(this, 'MyCognitoUserPool', {
            userPoolName: 'MyCognitoUserPool',
            adminCreateUserConfig: {
                allowAdminCreateUserOnly: false
            },
            policies: {
                passwordPolicy: {
                    minimumLength: 8,
                    requireLowercase: true,
                    requireNumbers: true,
                    requireSymbols: true,
                    requireUppercase: true,
                    temporaryPasswordValidityDays: 30
                }
            },
            usernameAttributes: [
                UserPoolAttribute.EMAIL
            ],
            schema: [
                {
                    attributeDataType: 'String',
                    name: UserPoolAttribute.EMAIL,
                    mutable: true,
                    required: true
                },
                {
                    attributeDataType: 'String',
                    name: UserPoolAttribute.FAMILY_NAME,
                    mutable: false,
                    required: true
                },
                {
                    attributeDataType: 'String',
                    name: UserPoolAttribute.GIVEN_NAME,
                    mutable: false,
                    required: true
                }
            ]
        });

      const cognitoAppDomain = new CfnUserPoolDomain(this, "PigletAuthDomainName", {
            domain: authDomainName,
            userPoolId: cfnUserPool.ref,
            customDomainConfig: {
                certificateArn: 'ACM Certificate arn'
            }
        });

    /* 
      TODO: Create an A record from the created cnfUserPoolDomain
    */

До этого момента все работает. Теперь вопрос в том, как создать запись A с помощью CfnUserPoolDomain

Любая помощь очень приветствуется.


person madu    schedule 27.11.2019    source источник
comment
У пользовательских пулов нет IP-адреса, поэтому вы не можете создавать такие записи DNS. Что ты пытаешься сделать?   -  person Joey Kilpatrick    schedule 28.11.2019
comment
@madu, я изменил свой ответ, чтобы использовать CustomResource, и он работает очень хорошо.   -  person quadroid    schedule 18.12.2019


Ответы (3)


Обновление май 2020 г.

Конструкция UserPoolDomain имеет был расширен, и UserPoolDomainTarget был добавлен для обеспечения этой функциональности.

Теперь все, что вам нужно сделать, это следующее:

const userPoolDomain = new cognito.UserPoolDomain(this, 'UserPoolDomain', {
  userPool,
  customDomain: {
    domainName: authDomainName,
    certificate,
  },
});

new route53.ARecord(this, 'UserPoolCloudFrontAliasRecord', {
  zone: hostedZone,
  recordName: authDomainName,
  target: route53.RecordTarget.fromAlias(new route53_targets.UserPoolDomainTarget(userPoolDomain)),
});
person mulles3008    schedule 28.05.2020
comment
Похоже, это должно сработать, но я все равно не получаю. Не удалось разрешить корневой домен. Убедитесь, что для корневого домена существует запись A. UserPoolDomain создается до записи A - person user3782299; 21.08.2020
comment
да. Конструкция UserPoolDomainTarget требует действительной записи A для корневого домена. См. Руководство разработчика Cognito. Вы можете добавить зависимость от ресурсов в A-записи, созданной вашим приложением CDK (например, с использованием someARecord.node.addDependency), или условно создать собственный домен (например, с помощью флага / свойства функции, установленного на false во время первого развертывания) - person mulles3008; 22.08.2020
comment
Извините, это моя ошибка. У меня была запись A для www.mydomain.com, но не для domain.com. Работает сейчас. - person user3782299; 24.08.2020
comment
Когда мой hostedZone от route53.HostedZone.fromHostedZoneId, я получаю сообщение об ошибке: _3 _... Я использую 1.109.0 пакеты CDK - person Kevin Wang; 22.06.2021
comment
Похоже, вместо этого работает .fromHostedZoneAttributes - person Kevin Wang; 22.06.2021

У меня была такая же проблема. Похоже, CloudFormation не имеет возвращаемого параметра для CfnUserPoolDomain AliasTarget. Это означает, что cdk также не может предоставить этот параметр.

В итоге я реализовал его с помощью AWS SDK (npm install aws-sdk) и получил значение с помощью API:


Обновление: лучшее решение - использовать AwsCustomResource. Вы можете увидеть подробный пример в aws / aws-cdk (# 6787):

const userPoolDomainDescription = new customResources.AwsCustomResource(this, 'user-pool-domain-description', {
  onCreate: {
    physicalResourceId: 'user-pool-domain-description',
    service: 'CognitoIdentityServiceProvider',
    action: 'describeUserPoolDomain',
    parameters: {
      Domain: userPoolDomain.domain
    }
  }
});

const dnsName = userPoolDomainDescription.getData('DomainDescription.CloudFrontDistribution').toString();

// 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: dnsName,
    }),
  }),
  zone,
})
person quadroid    schedule 07.12.2019
comment
Я не уверен, как его использовать, поскольку dnsName - это токен, aws-sdk не может использовать его напрямую. мне нужно создать еще один стек, который будет запускаться после этого и каким-то образом передать это значение (CfnOutput?) - person Roy Ca; 02.03.2020
comment
Что вы имеете в виду, говоря: «dnsName - это токен»? Вы пробовали использовать AwsCustomResource, как в сообщении? - person quadroid; 02.03.2020
comment
Да, я использую AwsCustomResource, как вы показали, и я знаю, что это работает, так как если я попытаюсь использовать значение dnsName (ошибочно), создав нормальную запись A, то я получаю сообщение об ошибке, что псевдоним облачного интерфейса не является действительным IP-адресом. . это означает, что это работает. но когда я пытаюсь использовать dnsName в вызове aws-sdk для создания записи псевдонима, я получаю сообщение об ошибке относительно его значения: $ {Token [Default.DomainDescription.CloudFrontDistribution.68]}. это токен cdk, который будет разрешен позже. aws-sdk не знает об этом и пытается использовать явное значение. у меня вопрос, как вы его используете? - person Roy Ca; 02.03.2020
comment
это означает, что он работает, я хотел сказать, что ошибка фактически показывает реальное значение цели псевдонима, которое соответствует тому, которое отображается в пользовательском интерфейсе пользовательского пула - раздел доменного имени - person Roy Ca; 02.03.2020
comment
@RoyCa см. Последние изменения выше и / или ознакомьтесь с полным примером в github.com/aws/aws-cdk/issues/6787#issuecomment-601432895, чтобы увидеть полностью рабочий пример того, как это сделать. - person Glenn 'devalias' Grant; 20.03.2020

Вот как это обойти. Предполагая, что у вас есть stack.yaml, который вы развертываете с помощью инструмента CI, скажем, через bash:

THE_STACK_NAME="my-cognito-stack"
THE_DOMAIN_NAME="auth.yourveryowndomain.org"

# get the alias target
# notice that it will be empty upon first launch (chicken and the egg problem)
ALIAS_TARGET=$(aws cognito-idp describe-user-pool-domain --domain ${THE_DOMAIN_NAME} | grep CloudFrontDistribution | cut -d \" -f4)

# create/update the deployment CloudFormation stack
# notice the AliasTarget parameter (which can be empty, it's okay!)
aws cloudformation deploy --stack-name ${THE_STACK_NAME} --template-file stack.yaml --parameter-overrides AliasTarget=${ALIAS_TARGET} DomainName=${THE_DOMAIN_NAME}

stack.yaml минимальная версия (не забудьте заполнить UserPool конфиг):

---
AWSTemplateFormatVersion: 2010-09-09

Parameters:
  DomainName:
    Type: String
    Default: auth.yourveryowndomain.org
    Description: The domain name to use to serve this project.

  ZoneName:
    Type: String
    Default: yourveryowndomain.org
    Description: The hosted zone name coming along with the DomainName used.

  AliasTarget: # no default value, can be empty
    Type: String
    Description: The UserPoolDomain alias target.

Conditions: # here's "the trick"
  HasAliasTarget: !Not [!Equals ['', !Ref AliasTarget]]

Resources:
  Certificate:
    Type: "AWS::CertificateManager::Certificate"
    Properties: 
      DomainName: !Ref ZoneName
      DomainValidationOptions:
        - DomainName: !Ref ZoneName
          ValidationDomain: !Ref ZoneName
      SubjectAlternativeNames:
        - !Ref DomainName

  UserPool:
    Type: AWS::Cognito::UserPool
    Properties:
      [... fill that with your configuration! ...]

  UserPoolDomain:
    Type: AWS::Cognito::UserPoolDomain
    Properties:
      UserPoolId: !Ref UserPool
      Domain: !Ref DomainName
      CustomDomainConfig:
        CertificateArn: !Ref Certificate

  DnsRecord: # if AliasTarget parameter is empty, well we just can't do that one!
    Condition: HasAliasTarget # and here's how we don't do it when we can't
    Type: AWS::Route53::RecordSet
    Properties:
      HostedZoneName: !Sub "${ZoneName}."
      AliasTarget:
        DNSName: !Ref AliasTarget
        EvaluateTargetHealth: false
        # HostedZoneId value for CloudFront is always this one
        # see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget.html
        HostedZoneId: Z2FDTNDATAQYW2
      Name: !Ref DomainName
      Type: A

Имейте в виду, что условия CloudFormation - это вовсе не "уловка": https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html. Мы просто используем это как трюк вместе с «первый запуск не сделает всего этого», чтобы обойти наш сценарий.

Довольно странно, но только для первого запуска! Запускаем еще раз: все нормально.


PS: не могу дождаться, чтобы избежать всего этого, просто указав цель псевдонима CloudFrontDistribution прямо в AWS::Cognito::UserPoolDomain возвращаемых значениях !!

person Clorichel    schedule 08.05.2020