constructor()

in lib/afd-friction-cdk-stack.js [37:290]


  constructor(scope, id, props) {
    super(scope, id, props);

    //Get IAM Policies
    const policies = getPolicies();

    // Custom IAM Role for Lambda Functions
    const CustomRole = new iam.Role(this, 'afd-Lambda-Execution-Role-1',{
      roleName: 'afd-Lambda-Execution-Role-1',
      assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
      managedPolicies: policies
    });

    // export Lambda Role for cross-stack reference
    new cdk.CfnOutput(this, 'lambda-exec-role-ref', {
      value: CustomRole.roleArn,
      description: 'Lambda Role ARN',
      exportName: 'lambda-exec-role',
    });

    const afdUserTableNew = new dynamodb.Table(this, 'afd-user-signup-scores-tbl', {
      partitionKey: {
        name: 'EMAIL',
        type: dynamodb.AttributeType.STRING
      },
      tableName: 'afd-user-signup-scores-tbl',
      encryption: TableEncryption.AWS_MANAGED,
      // The default removal policy is RETAIN, which means that cdk destroy will not attempt to delete
      // the new table, and it will remain in your account until manually deleted. By setting the policy to 
      // DESTROY, cdk destroy will delete the table (even if it has data in it)
      removalPolicy: cdk.RemovalPolicy.DESTROY
    });

    // export Table name for cross-stack reference
    new cdk.CfnOutput(this, 'afd-dd-table-name-new', {
      value: afdUserTableNew.tableName,
      description: 'DynamoDB Table Name',
      exportName: 'afd-dd-table-name-new',
    });

    // Lmabda Pre-Signup Trigger
    const preSignUpLambda = new lambda.Function(this, 'afd-cog-pre-signup', {
      code: new lambda.AssetCode('src/afd-cog-pre-signup'),
      handler: 'afd-cog-pre-signup.handler',
      runtime: lambda.Runtime.NODEJS_14_X,
      functionName: 'afd-cog-pre-signup',
      description: 'Amazon Fraud Detector- Cognito Pre-signup Trigger',      
      role: CustomRole,
      environment: {
        AFD_DETECTOR: `${process.env.AFD_DETECTOR_NAME}`,
        AFD_ENTITY_TYPE: `${process.env.AFD_ENTITY_TYPE}`,
        AFD_EVENT_TYPE: `${process.env.AFD_EVENT_TYPE}`,
        AFD_DETECTOR_VERSION: `${process.env.AFD_DETECTOR_VERSION}`,
        USER_TABLE: afdUserTableNew.tableName
      }      
    });

    // User Pool
    const userPool = new cognito.UserPool(this, 'afd-userpool', {
      userPoolName: 'afd-user-pool',
      selfSignUpEnabled: true,
      signInAliases: {
        email: true,
      },
      autoVerify: {
        email: true,
      },
      standardAttributes: {
        givenName: {
          required: true,
          mutable: true,
        },
        familyName: {
          required: true,
          mutable: true,
        },
        email:{
          required: true,
          mutable: false
        }
      },
      customAttributes: {
        registration_ip: new cognito.StringAttribute({mutable: true}),
        reg_user_agent: new cognito.StringAttribute({mutable: true}),
        billing_postal: new cognito.StringAttribute({mutable: true}),
      },
      passwordPolicy: {
        minLength: 8,
        requireLowercase: true,
        requireDigits: true,
        requireUppercase: true,
        requireSymbols: true,
      },
      accountRecovery: cognito.AccountRecovery.EMAIL_ONLY,
      removalPolicy: cdk.RemovalPolicy.RETAIN,
      lambdaTriggers:{
        preSignUp: preSignUpLambda
      }
    });

    //export user pool id
    new cdk.CfnOutput(this, 'userPoolId', {
      value: userPool.userPoolId,
      description: 'User Pool ID',
      exportName: 'userPoolId',
    });

    // User Pool Client Attributes
    const standardCognitoAttributes = {
          address: true,
          email: true,
          familyName: true,
          givenName: true,
          locale: true,
          phoneNumber: true          
    };

    const clientReadAttributes = new cognito.ClientAttributes()
    .withStandardAttributes(standardCognitoAttributes)
    .withCustomAttributes(...['registration_ip', 'reg_user_agent', 'billing_postal']);

    const clientWriteAttributes = new cognito.ClientAttributes()
    .withStandardAttributes(standardCognitoAttributes)
    .withCustomAttributes(...['registration_ip', 'reg_user_agent', 'billing_postal']);

    const client = userPool.addClient('afd-app-client', {
      enableTokenRevocation: true,
      generateSecret: false,
      authFlows:{        
        adminUserPassword: false,
        custom: true,
        userPassword: false,
        userSrp: true
      },      
      readAttributes: clientReadAttributes,
      writeAttributes: clientWriteAttributes,
      oAuth:{
        flows:{
          authorizationCodeGrant: true
        },
        scopes:[cognito.OAuthScope.EMAIL, cognito.OAuthScope.PHONE, cognito.OAuthScope.PROFILE, cognito.OAuthScope.OPENID]
      }
    });
    const clientId = client.userPoolClientId;

    //export web client id
    new cdk.CfnOutput(this, 'userPoolWebClientId', {
      value: clientId,
      description: 'User Pool Web Client ID',
      exportName: 'userPoolWebClientId',
    });

    // Add permission Lambda as an inline policy with the cognito ARN
    preSignUpLambda.role.attachInlinePolicy(new iam.Policy(this, 'afd-userpool-policy', {
      statements: [ new iam.PolicyStatement({
        actions: ['cognito-idp:DescribeUserPool'],
        resources: [userPool.userPoolArn],
      }) ]
    }));

    //Create a Cognito Identity Pool
    const identityPool = new cognito.CfnIdentityPool(this, 'afd-identity-pool', {
      identityPoolName: 'afd_friction_identity_pool',
      allowUnauthenticatedIdentities: true,
      cognitoIdentityProviders: [
        {
          clientId: clientId,
          providerName: userPool.userPoolProviderName,
        },
      ],
    });

    //export Identity id
    new cdk.CfnOutput(this, 'IdentityPoolId', {
      value: identityPool.ref,
      description: 'Identity Pool  ID',
      exportName: 'IdentityPoolId',
    });

    //Create Unauth and Auth Roles for the identity pool
    const identityUnauthRole = new iam.Role(
      this,
      'afd-cognito-unauth-role',
      {
        roleName: 'afd-cognito-unauth-role',
        description: 'Default role for anonymous users',
        assumedBy: new iam.FederatedPrincipal(
          'cognito-identity.amazonaws.com',
          {
            StringEquals: {
              'cognito-identity.amazonaws.com:aud': identityPool.ref,
            },
            'ForAnyValue:StringLike': {
              'cognito-identity.amazonaws.com:amr': 'unauthenticated',
            },
          },
          'sts:AssumeRoleWithWebIdentity',
        ),
      },
    );

    identityUnauthRole.addToPolicy(new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: ["mobileanalytics:PutEvents", "cognito-sync:*"],
        resources: ["*"],
    }))

    const identityAuthRole = new iam.Role(
      this, 
      'afd-cognito-auth-role', 
      {
        roleName: 'afd-cognito-auth-role',
        description: 'Default role for authenticated users',
        assumedBy: new iam.FederatedPrincipal(
          'cognito-identity.amazonaws.com',
          {
            StringEquals: {
              'cognito-identity.amazonaws.com:aud': identityPool.ref,
            },
            'ForAnyValue:StringLike': {
              'cognito-identity.amazonaws.com:amr': 'authenticated',
            },
          },
          'sts:AssumeRoleWithWebIdentity',
        ),
    });

    identityAuthRole.addToPolicy(new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: ["mobileanalytics:PutEvents",
                    "cognito-sync:*",
                    "cognito-identity:*"],
        resources: ["*"],
    }))

    new cognito.CfnIdentityPoolRoleAttachment(
      this,
      'identity-pool-role-attachment',
      {
        identityPoolId: identityPool.ref,
        roles: {
          authenticated: identityAuthRole.roleArn,
          unauthenticated: identityUnauthRole.roleArn,
        },
      },
    );
    
    //export User Pool Region
    new cdk.CfnOutput(this, 'region', {
      value: process.env.AWS_REGION,
      description: 'User Pool Region',
      exportName: 'region',
    });
  }