AWSTemplateFormatVersion: "2010-09-09" Description: "Amazon Connect Chat backend" Mappings: FunctionMap: Configuration: S3Bucket: "amazon-connect-advanced-customer-chat-cfn" S3Key: "deployment/" Parameters: CustomerPortalUrl: Type: String Description: domain name (without https://) of the Customer Portal CloudFront distribution. ConnectChatFlowId: Type: String Description: The contact flow id that the customer will interact with while chatting. This should be the id of the Basic Contact Flow you uploaded. AllowedPattern: '\w{8}-\w{4}-\w{4}-\w{4}-\w{12}' ConnectInstanceId: Type: String Description: The instance id of the Amazon Connect instance that the customer will interact with while chatting. You can find this in the Amazon Connect console when viewing your instance details. AllowedPattern: '\w{8}-\w{4}-\w{4}-\w{4}-\w{12}' ConnectS3BucketName: Type: String Default: "chat-transcript-s3-bucket" Description: > Enter the name of the bucket that holds the chat transcripts for your Amazon Connect instance. You can find this in the Amazon Connect console when viewing the Data Storage section in your instance details. E.g. If your instance has connect-xxx/connect/instanceName/ChatTranscripts, enter 'connect-xxx' AllowedPattern: '(?=^.{3,63}$)(?!^(\d+\.)+\d+$)(^(([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\.)*([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])$)' TranscriptPath: Type: String Description: > The path in the S3 bucket that contains the chat transcripts. You can find this in the Amazon Connect console when viewing the Data Storage section in your instance details. E.g. If your instance has connect-xxx/connect/instanceName/ChatTranscripts, enter 'connect/instanceName/ChatTranscripts' Default: connect/instanceName/ChatTranscripts ComprehendTranscriptLambdaArn: Type: String ExecuteTranscriptionStateMachineArn: Type: String S3BucketAssets: Type: String Resources: #### Lambda ##### ChatSDKLayer: Type: AWS::Lambda::LayerVersion Properties: CompatibleRuntimes: - "nodejs14.x" Content: S3Bucket: !Join - "." - - !Ref "AWS::Region" - !FindInMap [FunctionMap, Configuration, S3Bucket] S3Key: !Join [ "", [!FindInMap [FunctionMap, Configuration, S3Key], "ChatSDK.zip"], ] Description: The AWS SDK including Amazon Connect Chat APIs. InitiateChatLambda: Type: "AWS::Lambda::Function" Properties: Description: AWS Lambda Function to initiate the chat with the end user Handler: "startChatContact.handler" Role: !GetAtt InitiateChatLambdaExecutionRole.Arn Runtime: "nodejs14.x" MemorySize: 128 Timeout: 30 Layers: - !Ref ChatSDKLayer Environment: Variables: INSTANCE_ID: !Ref ConnectInstanceId CONTACT_FLOW_ID: !Ref ConnectChatFlowId CF_DISTRIBUTION: !Ref CustomerPortalUrl CHAT_DATA_TABLE: !Ref chatContactDataTable Code: S3Bucket: !Ref S3BucketAssets S3Key: lambda-functions/initiateChat.zip InitiateChatLambdaExecutionRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: Service: - "lambda.amazonaws.com" Action: - "sts:AssumeRole" Path: "/" Policies: - PolicyName: initiate-chat-execution-policy PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:PutLogEvents" Resource: - !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*" - Effect: "Allow" Action: - "connect:StartChatContact" Resource: - !Sub "arn:${AWS::Partition}:connect:${AWS::Region}:${AWS::AccountId}:instance/${ConnectInstanceId}" - !Sub "arn:${AWS::Partition}:connect:${AWS::Region}:${AWS::AccountId}:instance/${ConnectInstanceId}/*" - Effect: "Allow" Action: - "dynamodb:Query" - "dynamodb:UpdateItem" - "dynamodb:PutItem" Resource: - !GetAtt chatContactDataTable.Arn - !Sub "${chatContactDataTable.Arn}/index/*" UpdateDdbWithS3LocationLambda: Type: "AWS::Lambda::Function" Properties: Description: AWS Lambda Function to update the DDB with the S3 location of the chat transcript Handler: "updateChatDdbWithS3Key.handler" Role: !GetAtt UpdateDdbWithS3LocationLambdaExecutionRole.Arn Runtime: "nodejs14.x" MemorySize: 128 Timeout: 30 Environment: Variables: S3_BUCKET_NAME: !Ref ConnectS3BucketName CHAT_DATA_TABLE: !Ref chatContactDataTable Code: S3Bucket: !Join - "." - - !Ref "AWS::Region" - !FindInMap [FunctionMap, Configuration, S3Bucket] S3Key: !Join [ "", [ !FindInMap [FunctionMap, Configuration, S3Key], "update-chat-ddb.zip", ], ] UpdateDdbWithS3LocationLambdaExecutionRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: Service: - "lambda.amazonaws.com" Action: - "sts:AssumeRole" Path: "/" Policies: - PolicyName: get-previous-chat-policy PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - "dynamodb:UpdateItem" Resource: - !GetAtt chatContactDataTable.Arn - Effect: "Allow" Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:PutLogEvents" Resource: - !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*" #### S3 Lambda Trigger #### ExistingBucketConfiguration: Type: Custom::LoadLambda DependsOn: - BucketPermission Properties: customAction: "configureNotification" ServiceToken: !GetAtt S3BucketConfigurationLambda.Arn Bucket: !Ref ConnectS3BucketName Prefix: !Ref TranscriptPath LambdaFunctionArnChatTranscripts: !GetAtt UpdateDdbWithS3LocationLambda.Arn LambdaFunctionArnTranscripts: !Ref ComprehendTranscriptLambdaArn LambdaFunctionArnRecordings: !Ref ExecuteTranscriptionStateMachineArn S3BucketConfigurationLambda: Type: AWS::Lambda::Function Properties: Description: S3 Object Custom Resource Handler: S3NotificationConfiguration.handler Role: !GetAtt S3BucketConfigurationLambdaExecutionRole.Arn Code: S3Bucket: !Ref S3BucketAssets S3Key: "lambda-functions/S3BucketConfigurationLambda.zip" Timeout: 30 Runtime: "nodejs14.x" S3BucketConfigurationLambdaExecutionRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: Service: - "lambda.amazonaws.com" Action: - "sts:AssumeRole" Path: "/" Policies: - PolicyName: get-previous-chat-policy PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - "s3:putBucketNotification" Resource: - !Sub "arn:aws:s3:::${ConnectS3BucketName}" - Effect: "Allow" Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:PutLogEvents" Resource: - !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*" BucketPermission: Type: AWS::Lambda::Permission Properties: Action: "lambda:InvokeFunction" FunctionName: !Ref UpdateDdbWithS3LocationLambda Principal: s3.amazonaws.com SourceAccount: !Ref "AWS::AccountId" SourceArn: !Sub "arn:aws:s3:::${ConnectS3BucketName}" #### DynamoDb #### chatContactDataTable: Type: AWS::DynamoDB::Table Properties: TableName: "multichannel-chat-history" BillingMode: "PAY_PER_REQUEST" AttributeDefinitions: - AttributeName: "contactId" AttributeType: "S" - AttributeName: "nextContactId" AttributeType: "S" - AttributeName: "userDisplayHash" AttributeType: "S" KeySchema: - AttributeName: "contactId" KeyType: "HASH" GlobalSecondaryIndexes: - IndexName: "userDisplayHash-nextContactId-index" KeySchema: - AttributeName: "userDisplayHash" KeyType: "HASH" - AttributeName: "nextContactId" KeyType: "RANGE" Projection: ProjectionType: "ALL" TimeToLiveSpecification: AttributeName: "date" Enabled: true CustomResourceHelper: Type: AWS::Lambda::Function Properties: Code: S3Bucket: !Join - "." - - !Ref "AWS::Region" - !FindInMap [FunctionMap, Configuration, S3Bucket] S3Key: !Join [ "", [ !FindInMap [FunctionMap, Configuration, S3Key], "custom-resource-helper.zip", ], ] Description: Solution Accelerator for Amazon Connect customer side Chat Handler: customResourceHelper.handler MemorySize: 256 Role: !GetAtt CustomResourceHelperIamRole.Arn Runtime: nodejs14.x Timeout: 300 CustomResourceHelperIamRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: Service: - "lambda.amazonaws.com" Action: - "sts:AssumeRole" Path: "/" Policies: - PolicyName: connect-chat-resource-helper PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:PutLogEvents" Resource: - !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*" - Effect: "Allow" Action: - "s3:GetObject" Resource: - !Join - "" - - "arn:" - !Ref "AWS::Partition" - ":s3:::" - !Ref "AWS::Region" - "." - !FindInMap [FunctionMap, Configuration, S3Bucket] - "/*" Outputs: initiateChatLambda: Description: The ARN of the Lambda function created to initiate chat Value: !GetAtt InitiateChatLambda.Arn chatContactDataTable: Description: Name of the new table to store the contact data related to chats. Value: !Ref chatContactDataTable