Cannot set a property of cognito userpool client via cloudformation
Asked Answered
J

5

7

I am trying to run congnito via cloudformation and everything works but there is section in cognito as follows:

enter image description here

As you see there is section "Enable identity providers" and I can not find where I can set it to my cognito user pool in cloudformation!

I tried this attributes but it says not supported.

SupportedIdentityProviders

Here is my code for user pool client:

  UserPoolClient:
Type: "AWS::Cognito::UserPoolClient"
Properties:
  ClientName: !Sub ${project}-client
  ExplicitAuthFlows:
   - ADMIN_NO_SRP_AUTH
   - USER_PASSWORD_AUTH
  GenerateSecret: false
  UserPoolId: !Ref UserPool
  RefreshTokenValidity: 30

and here is my user pool:

  UserPool:
Type: "AWS::Cognito::UserPool"
Properties:
  UserPoolName: !Sub ${project}-user-pool-test
  AutoVerifiedAttributes:
    - email
  UsernameAttributes:
    - email
  MfaConfiguration: "OFF"
  LambdaConfig:
    CustomMessage:
      Fn::ImportValue: !Sub ${project}-${EnvironmentApp}-lambda-cognito-custom-message-post
  Policies:
    PasswordPolicy:
      MinimumLength: !Ref MinimumLength
      RequireLowercase: !Ref RequireLowercase
      RequireNumbers: !Ref RequireNumbers
      RequireSymbols: !Ref RequireSymbols
      RequireUppercase: !Ref RequireUppercase
  Schema:
    -
        AttributeDataType: String
        DeveloperOnlyAttribute: false
        Mutable: true
        Name: !Sub ${project}-stg
        Required: false
    -
        AttributeDataType: String
        DeveloperOnlyAttribute: false
        Mutable: true
        Name: !Sub zuora-stg
        Required: false
    -
        AttributeDataType: String
        DeveloperOnlyAttribute: false
        Mutable: true
        Name: !Sub salesforce-stg
        Required: false

Is it supported in cloud formation? I appreciate any help?

Janiuszck answered 18/7, 2018 at 20:17 Comment(0)
I
2

As other answer suggest, this can't be done in CloudFormation natively as of yet. However, as ASR answer advises it is possible to do so through CloudFormation custom resource.

My employer has open sourced its collection of custom resources, including CognitoUserPool and CognitoDomainName (which is also not supported in CloudFormation). Custom resources source code can be found on github

Below are manual directions on setting this up - you can always automate things further by placing Custom Resource backing Lambda in CloudFormation as well.

All commands below are for Mac. You may need to modify base64 flags for other platforms

1. Create IAM Role For Lambda

aws iam create-role --role-name LambdaRoleCognito --assume-role-policy-document '{
      "Version": "2012-10-17",
      "Statement": [
      {
          "Effect": "Allow",
          "Principal": {
              "Service": "lambda.amazonaws.com"
          },
          "Action": "sts:AssumeRole"
      }
  ]
  }'
aws iam attach-role-policy --role-name LambdaRoleCognito \
  --policy-arn  arn:aws:iam::aws:policy/CloudWatchLogsFullAccess

aws iam attach-role-policy --role-name LambdaRoleCognito \
  --policy-arn  arn:aws:iam::aws:policy/AmazonCognitoPowerUser

2. Download lambda source code, upload to your local bucket, and create lambda

wget https://github.com/base2Services/cloudformation-custom-resources-nodejs/releases/download/1.0.0/ccr-nodejs-1.0.0.zip
account_id=$(aws sts get-caller-identity --query Account --output text)
aws s3 mb s3://${account_id}.cfncustomres.source
aws s3 cp ccr-nodejs-1.0.0.zip s3://${account_id}.cfncustomres.source/ccr-nodejs-1.0.0.zip

aws lambda create-function --function-name CfnCrCognitUPC --runtime nodejs6.10 \
    --role arn:aws:iam::${account_id}:role/LambdaRoleCognito  \
    --timeout 30 \
    --memory-size 512 \
    --code S3Bucket=${account_id}.cfncustomres.source,S3Key=ccr-nodejs-1.0.0.zip \
    --handler cognito-user-pool-client/index.handler

3. Optional Test lambda by invoking with test payload

aws lambda invoke --function-name CfnCrCognitUPC --payload '{
  "StackId": "arn:aws:cloudformation:us-west-2:EXAMPLE/stack-name/guid",
  "ResponseURL": "http://pre-signed-S3-url-for-response",
  "ResourceProperties": {
    "ClientName": "MyCCRCreatedUP",
    "SupportedIdentityProviders": [
      "COGNITO"
    ],
    "UserPoolId":"!! REPLACE WITH YOUR USER POOL ID !!"
  },
  "RequestType": "Create",
  "ResourceType": "Custom::TestResource",
  "RequestId": "unique id for this create request",
  "LogicalResourceId": "MyTestResource"
}' --log-type Tail --invocation-type RequestResponse output.txt --query LogResult --output text | base64 -D

4. Create custom resource in CloudFormation template

For list of all supported properties checkout custom resource JSON schema

Resources:
  MyPoolApplication:
    Type: Custom::CognitoUserPool
    Properties:
      ServiceToken: arn:aws:lambda:<<REPLACE_WITH_YOUR_REGION>>:<<REPLACE_WITH_YOUR_ACCOUNT_ID>>:function:CfnCrCognitUPC
      ClientName: ApplicationClientNameHere
      UserPoolId: 
        Ref: UserPool
      SupportedIdentityProviders:
        - COGNITO
      .... other support properties .... 
Indulgent answered 20/7, 2018 at 3:12 Comment(2)
hi @toske, I want to use the CognitoDomainName cfn template, can you give me a hint how to...Packsaddle
Use this generic custom resource provider, with provided demo to spin up Cognito IdP, domain, etc. github.com/ab77/cfn-generic-custom-resource#cognito-demoCoronado
S
2

As ASR says, this doesn't seem to be supported in Cloudformation yet.

We ended up trying out Terraform - which does support it e.g.

resource "aws_cognito_user_pool_client" "my_client" {
  ...
  supported_identity_providers = ["COGNITO"]
}

We've now switched everything to using terraform as it's orders of magnitude easier to understand, read, and write than Cloudformation.

I know that's probably not the answer you want but I hope it helps.

Shabuoth answered 19/7, 2018 at 2:5 Comment(1)
Thanks for the insightJaniuszck
I
2

As other answer suggest, this can't be done in CloudFormation natively as of yet. However, as ASR answer advises it is possible to do so through CloudFormation custom resource.

My employer has open sourced its collection of custom resources, including CognitoUserPool and CognitoDomainName (which is also not supported in CloudFormation). Custom resources source code can be found on github

Below are manual directions on setting this up - you can always automate things further by placing Custom Resource backing Lambda in CloudFormation as well.

All commands below are for Mac. You may need to modify base64 flags for other platforms

1. Create IAM Role For Lambda

aws iam create-role --role-name LambdaRoleCognito --assume-role-policy-document '{
      "Version": "2012-10-17",
      "Statement": [
      {
          "Effect": "Allow",
          "Principal": {
              "Service": "lambda.amazonaws.com"
          },
          "Action": "sts:AssumeRole"
      }
  ]
  }'
aws iam attach-role-policy --role-name LambdaRoleCognito \
  --policy-arn  arn:aws:iam::aws:policy/CloudWatchLogsFullAccess

aws iam attach-role-policy --role-name LambdaRoleCognito \
  --policy-arn  arn:aws:iam::aws:policy/AmazonCognitoPowerUser

2. Download lambda source code, upload to your local bucket, and create lambda

wget https://github.com/base2Services/cloudformation-custom-resources-nodejs/releases/download/1.0.0/ccr-nodejs-1.0.0.zip
account_id=$(aws sts get-caller-identity --query Account --output text)
aws s3 mb s3://${account_id}.cfncustomres.source
aws s3 cp ccr-nodejs-1.0.0.zip s3://${account_id}.cfncustomres.source/ccr-nodejs-1.0.0.zip

aws lambda create-function --function-name CfnCrCognitUPC --runtime nodejs6.10 \
    --role arn:aws:iam::${account_id}:role/LambdaRoleCognito  \
    --timeout 30 \
    --memory-size 512 \
    --code S3Bucket=${account_id}.cfncustomres.source,S3Key=ccr-nodejs-1.0.0.zip \
    --handler cognito-user-pool-client/index.handler

3. Optional Test lambda by invoking with test payload

aws lambda invoke --function-name CfnCrCognitUPC --payload '{
  "StackId": "arn:aws:cloudformation:us-west-2:EXAMPLE/stack-name/guid",
  "ResponseURL": "http://pre-signed-S3-url-for-response",
  "ResourceProperties": {
    "ClientName": "MyCCRCreatedUP",
    "SupportedIdentityProviders": [
      "COGNITO"
    ],
    "UserPoolId":"!! REPLACE WITH YOUR USER POOL ID !!"
  },
  "RequestType": "Create",
  "ResourceType": "Custom::TestResource",
  "RequestId": "unique id for this create request",
  "LogicalResourceId": "MyTestResource"
}' --log-type Tail --invocation-type RequestResponse output.txt --query LogResult --output text | base64 -D

4. Create custom resource in CloudFormation template

For list of all supported properties checkout custom resource JSON schema

Resources:
  MyPoolApplication:
    Type: Custom::CognitoUserPool
    Properties:
      ServiceToken: arn:aws:lambda:<<REPLACE_WITH_YOUR_REGION>>:<<REPLACE_WITH_YOUR_ACCOUNT_ID>>:function:CfnCrCognitUPC
      ClientName: ApplicationClientNameHere
      UserPoolId: 
        Ref: UserPool
      SupportedIdentityProviders:
        - COGNITO
      .... other support properties .... 
Indulgent answered 20/7, 2018 at 3:12 Comment(2)
hi @toske, I want to use the CognitoDomainName cfn template, can you give me a hint how to...Packsaddle
Use this generic custom resource provider, with provided demo to spin up Cognito IdP, domain, etc. github.com/ab77/cfn-generic-custom-resource#cognito-demoCoronado
M
2

As other answers stated, there is now a way to setup a UserPoolClient using CloudFormation however I arrived to this question looking for specific examples because I was struggle with some parameters. I want to put it here the example just in case someone is also looking for an example.

In my example I've also included a federated logon with google to make it more complete. If you don't want to login with google just remove it from SupportedIdentityProviders.

Template below:

AWSTemplateFormatVersion: 2010-09-09
Parameters: 
  envParameter: 
    Type: String
    Default: dev
    AllowedValues: [ dev, staging, prod ]
    Description: Suffix to be added for names.
Resources:
  myUserPool:
    DependsOn: [ cognitoSMSRole ]
    Type: AWS::Cognito::UserPool
    Properties:
      AccountRecoverySetting:
        RecoveryMechanisms: 
          - Name: verified_email
            Priority: 1
          - Name: verified_phone_number
            Priority: 2
      AdminCreateUserConfig: 
          AllowAdminCreateUserOnly: False
      AutoVerifiedAttributes: 
        - phone_number
      EnabledMfas: 
        - SMS_MFA
      MfaConfiguration: OPTIONAL
      Policies: 
        PasswordPolicy: 
          MinimumLength: 8
          RequireLowercase: True
          RequireNumbers: True
          RequireSymbols: True
          RequireUppercase: True
          TemporaryPasswordValidityDays: 7
      Schema: 
        - AttributeDataType: String
          DeveloperOnlyAttribute: False
          Mutable: False
          Name: name
          Required: True
        - AttributeDataType: String
          DeveloperOnlyAttribute: False
          Mutable: False
          Name: last_name
          Required: False
      SmsConfiguration:
          ExternalId: !Sub cognito-sms-role-${envParameter}
          SnsCallerArn: !GetAtt cognitoSMSRole.Arn
      UsernameAttributes: 
        - phone_number
      UsernameConfiguration: 
        CaseSensitive: False
      UserPoolName: !Sub UserPool-${envParameter}

  cognitoSMSRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument: 
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal: 
              Service: 
                - "cognito-idp.amazonaws.com"
            Action: 
              - "sts:AssumeRole"
      Policies:
        - PolicyName: "CognitoSNSPolicy"
          PolicyDocument: 
            Version: "2012-10-17"
            Statement: 
              - Effect: "Allow"
                Action: "sns:publish"
                Resource: "*"

  cognitoClient:
    DependsOn: [ myUserPool, googleProvider ]
    Type: AWS::Cognito::UserPoolClient
    Properties: 
      AllowedOAuthFlows: 
        - code
        - implicit
      AllowedOAuthFlowsUserPoolClient: True
      AllowedOAuthScopes: 
        - email
        - openid
        - profile
      CallbackURLs: 
        - http://google.co.uk
      ClientName: !Sub cognito-appid-${envParameter}
      GenerateSecret: False
      LogoutURLs: 
        - http://google.co.uk
      PreventUserExistenceErrors: ENABLED 
      RefreshTokenValidity: 1
      SupportedIdentityProviders: 
        - COGNITO
        - Google
      UserPoolId: !Ref myUserPool
  googleProvider:
    DependsOn: [ myUserPool ]
    Type: AWS::Cognito::UserPoolIdentityProvider
    Properties: 
      AttributeMapping:
        name: emailAddress
        sub: Username
      ProviderDetails: 
        client_id: client_id.apps.googleusercontent.com
        client_secret: this_is_the_client_secret
        authorize_scopes: email openid profile
      ProviderName: Google
      ProviderType: Google
      UserPoolId: !Ref myUserPool


Outputs:
 userPool:
    Description: "User pool ID"
    Value: !Ref myUserPool
 identityPool:
    Description: "Identity pool ID"
    Value: !Ref cognitoClient

Mariselamarish answered 2/3, 2020 at 10:36 Comment(1)
This works! Thank you. If anyone is interested, the same syntax works for Serverless.com YML too. I needed AllowedOAuthFlows and SupportedIdentityProviders, they work perfectly.Skvorak
A
1

I ran into the same problem last month. This property is not supported in CFN yet. So I ended up using CFN custom resource to create the pool client. More here about CFN Custom Resource. Essentially, I have CFN call a Lambda function to create the user pool client (all properties are supported in SDK).

Alina answered 18/7, 2018 at 20:30 Comment(1)
Thanks for the answerJaniuszck
M
1

As of October 2019 cognito resources are now support by cloudformation. Resources are created with the expected types of AWS::Cognito::UserPool, AWS::Cognito::UserPoolClient, AWS::Cognito::UserPoolDomain, etc.

To enable identity providers, the relevant following CF attributes will need to be set.

  UserPoolClient:
    Type: AWS::Cognito::UserPoolClient
      UserPoolId: !Ref UserPool
      SupportedIdentityProviders:
        - COGNITO
        - Facebook
        - Google
        - LoginWithAmazon
        ...

The documentation for cloudformation is available here.

Merci answered 28/11, 2019 at 12:54 Comment(2)
Can you explain how this actually solves the OP's question? I can't find anywhere in the documentation you listed that will actually enable the Cognito Pool on the client side, as described in the screenshot.Woods
Updated answer to include relevant cloud formation attributes to enable identity providers.Merci

© 2022 - 2024 — McMap. All rights reserved.