AWSTemplateFormatVersion: "2010-09-09" Description: "" Parameters: ChatFlowId: Type: String DestinationPhoneNumber: Type: String ContactEmailAddress: Type: String ConnectInstanceId: Type: String QueueId: Type: String Currency: Type: String Default: USD Language: Type: String Default: en AllowedValues: - en - es S3BucketAssets: Type: String Mappings: LanguageMap: es: "code": "es-MX" en: "code": "en-US" Resources: ##DynamoTables TableInteractionsApp: Type: "AWS::DynamoDB::Table" Properties: AttributeDefinitions: - AttributeName: "customerId" AttributeType: "S" - AttributeName: "interactionDateTime" AttributeType: "S" TableName: "multichannel-interactions-app" KeySchema: - AttributeName: "customerId" KeyType: "HASH" - AttributeName: "interactionDateTime" KeyType: "RANGE" BillingMode: "PAY_PER_REQUEST" TableInteractionsVoice: Type: "AWS::DynamoDB::Table" Properties: AttributeDefinitions: - AttributeName: "customerId" AttributeType: "S" - AttributeName: "interactionId" AttributeType: "S" TableName: "multichannel-interactions-voice" KeySchema: - AttributeName: "customerId" KeyType: "HASH" - AttributeName: "interactionId" KeyType: "RANGE" BillingMode: "PAY_PER_REQUEST" TableInteractionsChat: Type: "AWS::DynamoDB::Table" Properties: AttributeDefinitions: - AttributeName: "customerId" AttributeType: "S" - AttributeName: "interactionDateTime" AttributeType: "S" TableName: "multichannel-interactions-chatbot" KeySchema: - AttributeName: "customerId" KeyType: "HASH" - AttributeName: "interactionDateTime" KeyType: "RANGE" BillingMode: "PAY_PER_REQUEST" TableOffices: Type: "AWS::DynamoDB::Table" Properties: AttributeDefinitions: - AttributeName: "name" AttributeType: "S" TableName: "multichannel-offices" KeySchema: - AttributeName: "name" KeyType: "HASH" BillingMode: "PAY_PER_REQUEST" TableCustomerInfo: Type: "AWS::DynamoDB::Table" Properties: AttributeDefinitions: - AttributeName: "Id" AttributeType: "S" TableName: "multichannel-customer-info" KeySchema: - AttributeName: "Id" KeyType: "HASH" BillingMode: "PAY_PER_REQUEST" TableLocalization: Type: "AWS::DynamoDB::Table" Properties: AttributeDefinitions: - AttributeName: "messageId" AttributeType: "S" - AttributeName: "locale" AttributeType: "S" TableName: "multichannel-localization" KeySchema: - AttributeName: "messageId" KeyType: "HASH" - AttributeName: "locale" KeyType: "RANGE" BillingMode: "PAY_PER_REQUEST" ##Lambda Functions PopulateDynamoLambda: Type: AWS::Lambda::Function Properties: Role: !GetAtt 'LambdaPopulateRole.Arn' Runtime: "nodejs14.x" Timeout: 20 Handler: "index.handler" Code: S3Bucket: !Ref S3BucketAssets S3Key: lambda-functions/populateDynamoDB.zip Environment: Variables: "bucketName": !Ref S3BucketAssets "key" : "data/localization.csv" "tableNameLocalization" : !Ref TableLocalization "tableNameCustomer" : !Ref TableCustomerInfo "Phone" : !Ref DestinationPhoneNumber MyCustomResource1: Type: "Custom::LambdatoDynamoStart" Properties: ServiceToken: !GetAtt 'PopulateDynamoLambda.Arn' LambdaLex: Type: AWS::Lambda::Function Properties: FunctionName: multichannel-lex-bot Role: !GetAtt 'LambdalexRole.Arn' Runtime: "python3.7" Timeout: 20 Handler: "lambda_function.lambda_handler" Code: S3Bucket: !Ref S3BucketAssets S3Key: lambda-functions/botLex.zip Layers: - !Ref LambdaLayer Environment: Variables: "EVENT_TABLE_NAME": !Ref TableInteractionsChat "SKILL_NAME": "Banca Nube - Bot" "SNS_TOPIC_ARN": !Sub "arn:aws:sns:${AWS::Region}:${AWS::AccountId}:multichannel_notification" "CONNECT_CONTACT_FLOW_ID": Ref: ChatFlowId "CONNECT_INSTANCE_ID": Ref: ConnectInstanceId "CONNECT_QUEUE_ID": Ref: QueueId "LOCALE" : !FindInMap - LanguageMap - !Ref 'Language' - code "ENABLE_OMNICHANNEL_INTEGRATION": "1" "LOCALIZATION_TABLE_NAME": !Ref TableLocalization "CUSTOMER_TABLE_NAME": !Ref TableCustomerInfo "OFFICE_TABLE_NAME": !Ref TableOffices "CURRENCY_CODE": Ref: Currency LambdaAlexa: Type: AWS::Lambda::Function Properties: FunctionName: multichannel-alexa-bot Role: !GetAtt 'LambdalexRole.Arn' Runtime: "python3.7" Timeout: 20 Layers: - !Ref LambdaLayer Handler: "lambda_function.lambda_handler" Code: S3Bucket: !Ref S3BucketAssets S3Key: lambda-functions/botAlexa.zip Environment: Variables: "EVENT_TABLE_NAME": !Ref TableInteractionsChat "SKILL_NAME": "Banca Nube - Bot" "SNS_TOPIC_ARN": !Sub "arn:aws:sns:${AWS::Region}:${AWS::AccountId}:multichannel_notification" "CONNECT_CONTACT_FLOW_ID": Ref: ChatFlowId "CONNECT_INSTANCE_ID": Ref: ConnectInstanceId "CONNECT_QUEUE_ID": Ref: QueueId "ENABLE_OMNICHANNEL_INTEGRATION": "1" "LOCALIZATION_TABLE_NAME": !Ref TableLocalization "CUSTOMER_TABLE_NAME": !Ref TableCustomerInfo "OFFICE_TABLE_NAME": !Ref TableOffices "CURRENCY_CODE": Ref: Currency DeleteLambdaLex: Type: AWS::Lambda::Function Properties: Role: !GetAtt 'DeleteCodeBuildRole.Arn' Runtime: "python3.7" Timeout: 13 Handler: "index.lambda_handler" Code: ZipFile: | import json import cfnresponse import boto3 import os import time from botocore.exceptions import ClientError def lambda_handler(event, context): client = boto3.client('lex-models') cb = boto3.client('codebuild') print(event) if event['RequestType'] == "Delete" : try: bot= client.get_bot( name='multichannel_lex_bot', versionOrAlias='prod', ) response = client.delete_bot_alias(name='prod', botName='multichannel_lex_bot') time.sleep(10) response2 = client.delete_bot(name='multichannel_lex_bot') print ('Lex Deleted') print (response2) cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) except ClientError as e: if e.response['Error']['Code'] == 'BadRequestException': cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) return("No such Bot yet") else: print ('error') cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) return("Unexpected error: %s" % e.response['Error']['Code']) raise if event['RequestType'] == 'Create': response= cb.start_build(projectName='multichannel-codebuild-lex') print (response) cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) return ('Created') MyCustomResource2: Type: "Custom::DeleteLambdaLex" DependsOn: ['CodeBuildProject'] Properties: ServiceToken: !GetAtt 'DeleteLambdaLex.Arn' LambdaLayer: Type: "AWS::Lambda::LayerVersion" Properties: Description: "" CompatibleRuntimes: - "python3.7" LayerName: "BotBackendLayer" Content: S3Bucket: !Ref S3BucketAssets S3Key: lambda-functions/botBackendLayer.zip ##IAM Roles and policies LambdaPopulateRole: DependsOn: ["IAMDynamoDBManagedPolicy"] Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole - !Sub "arn:aws:iam::${AWS::AccountId}:policy/service-role/MultiChannelDynamoDbPolicy-${AWS::Region}" - arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess LambdalexRole: DependsOn: ["IAMDynamoDBManagedPolicy","IAMSNSManagedPolicy", "IAMConnectManagedPolicy"] Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole - !Sub "arn:aws:iam::${AWS::AccountId}:policy/service-role/MultiChannelDynamoDbPolicy-${AWS::Region}" - arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess - !Sub "arn:aws:iam::${AWS::AccountId}:policy/service-role/MultiChannelSNSPolicy-${AWS::Region}" - !Sub "arn:aws:iam::${AWS::AccountId}:policy/service-role/MultiChannelConnectPolicy-${AWS::Region}" executeQueryRoleConnect: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole - arn:aws:iam::aws:policy/AmazonConnect_FullAccess DeleteCodeBuildRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/AWSCodeBuildAdminAccess - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole - arn:aws:iam::aws:policy/AmazonLexFullAccess IAMManagedPolicy: Type: "AWS::IAM::ManagedPolicy" Properties: ManagedPolicyName: !Sub "Omnichannel-CodeBuildS3ReadOnlyPolicy-bash-${AWS::Region}" Path: "/service-role/" PolicyDocument: !Sub | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:GetObjectVersion" ], "Resource": [ "arn:aws:s3:::${S3BucketAssets}", "arn:aws:s3:::${S3BucketAssets}/*" ] }, { "Effect": "Allow", "Resource": [ "arn:aws:s3:::${S3BucketAssets}" ], "Action": [ "s3:ListBucket", "s3:GetBucketAcl", "s3:GetBucketLocation" ] } ] } IAMDynamoDBManagedPolicy: Type: "AWS::IAM::ManagedPolicy" Properties: ManagedPolicyName: !Sub "MultiChannelDynamoDbPolicy-${AWS::Region}" Path: "/service-role/" PolicyDocument: !Sub | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "dynamodb:PutItem", "dynamodb:Scan", "dynamodb:Query", "dynamodb:UpdateItem", "dynamodb:GetItem", "dynamodb:GetRecords" ], "Resource": [ "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${TableCustomerInfo}", "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${TableOffices}", "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${TableInteractionsChat}", "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${TableLocalization}" ] } ] } IAMSNSManagedPolicy: Type: "AWS::IAM::ManagedPolicy" Properties: ManagedPolicyName: !Sub "MultiChannelSNSPolicy-${AWS::Region}" Path: "/service-role/" PolicyDocument: !Sub | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sns:Publish", "Resource": "arn:aws:sns:${AWS::Region}:${AWS::AccountId}:multichannel_notification" } ] } IAMConnectManagedPolicy: Type: "AWS::IAM::ManagedPolicy" Properties: ManagedPolicyName: !Sub "MultiChannelConnectPolicy-${AWS::Region}" Path: "/service-role/" PolicyDocument: !Sub | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "connect:StartOutboundVoiceContact", "Resource": "arn:aws:connect:${AWS::Region}:${AWS::AccountId}:instance/${ConnectInstanceId}/contact/*" } ] } IAMManagedPolicy2: Type: "AWS::IAM::ManagedPolicy" Properties: ManagedPolicyName: !Sub "CodeBuildBasePolicy-bash-${AWS::Region}" Path: "/service-role/" PolicyDocument: !Sub | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Resource": [ "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/bash", "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/bash:*", "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/*" ], "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ] }, { "Effect": "Allow", "Resource": [ "arn:aws:s3:::codepipeline-${AWS::Region}-*" ], "Action": [ "s3:PutObject", "s3:GetObject", "s3:GetObjectVersion", "s3:GetBucketAcl", "s3:GetBucketLocation" ] }, { "Effect": "Allow", "Action": [ "codebuild:CreateReportGroup", "codebuild:CreateReport", "codebuild:UpdateReport", "codebuild:BatchPutTestCases" ], "Resource": [ "arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/bash-*" ] } ] } executeCodeBuildRole: DependsOn: ["IAMManagedPolicy2", "IAMManagedPolicy"] Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - codebuild.amazonaws.com Action: - sts:AssumeRole Path: "/service-role/" ManagedPolicyArns: - arn:aws:iam::aws:policy/AWSLambda_FullAccess - arn:aws:iam::aws:policy/AmazonLexFullAccess - !Sub "arn:aws:iam::${AWS::AccountId}:policy/service-role/Omnichannel-CodeBuildS3ReadOnlyPolicy-bash-${AWS::Region}" - !Sub "arn:aws:iam::${AWS::AccountId}:policy/service-role/CodeBuildBasePolicy-bash-${AWS::Region}" ## CodeBuild CodeBuildProject: Type: "AWS::CodeBuild::Project" Properties: Name: "multichannel-codebuild-lex" Source: BuildSpec: !Sub | version: 0.2 #env: #variables: # key: "value" # key: "value" #parameter-store: # key: "value" # key: "value" #secrets-manager: # key: secret-id:json-key:version-stage:version-id # key: secret-id:json-key:version-stage:version-id #exported-variables: # - variable # - variable #git-credential-helper: yes phases: #install: #If you use the Ubuntu standard image 2.0 or later, you must specify runtime-versions. #If you specify runtime-versions and use an image other than Ubuntu standard image 2.0, the build fails. #runtime-versions: # name: version # name: version #commands: # - command # - command pre_build: commands: - curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" - unzip awscliv2.zip - chmod +x ./aws/install - ./aws/install - aws --version # - command build: commands: - echo ${Language} - chmod +x import-bot.sh - ./import-bot.sh ${Language} # - command # - command #post_build: #commands: # - command # - command #reports: #report-name-or-arn: #files: # - location # - location #base-directory: location #discard-paths: yes #file-format: JunitXml | CucumberJson #artifacts: #files: # - location # - location #name: $(date +%Y-%m-%d) #discard-paths: yes #base-directory: location #cache: #paths: # - paths InsecureSsl: false Location: !Sub "${S3BucketAssets}/bot-definition/amazon-lex/" Type: "S3" Artifacts: Type: "NO_ARTIFACTS" Cache: Type: "NO_CACHE" Environment: ComputeType: "BUILD_GENERAL1_MEDIUM" Image: "aws/codebuild/amazonlinux2-x86_64-standard:3.0" ImagePullCredentialsType: "CODEBUILD" PrivilegedMode: false Type: "LINUX_CONTAINER" ServiceRole: !GetAtt executeCodeBuildRole.Arn TimeoutInMinutes: 60 QueuedTimeoutInMinutes: 480 BadgeEnabled: false LogsConfig: CloudWatchLogs: Status: "ENABLED" S3Logs: Status: "DISABLED" EncryptionDisabled: false ## SNS Topic SNSTopic: Type: "AWS::SNS::Topic" Properties: DisplayName: "multichannel_notification" TopicName: "multichannel_notification" KmsMasterKeyId: alias/aws/sns SNSTopicPolicy: Type: "AWS::SNS::TopicPolicy" Properties: PolicyDocument: !Sub "{\"Version\":\"2008-10-17\",\"Id\":\"__default_policy_ID\",\"Statement\":[{\"Sid\":\"__default_statement_ID\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"*\"},\"Action\":[\"SNS:GetTopicAttributes\",\"SNS:SetTopicAttributes\",\"SNS:AddPermission\",\"SNS:RemovePermission\",\"SNS:DeleteTopic\",\"SNS:Subscribe\",\"SNS:ListSubscriptionsByTopic\",\"SNS:Publish\",\"SNS:Receive\"],\"Resource\":\"${SNSTopic}\",\"Condition\":{\"StringEquals\":{\"AWS:SourceOwner\":\"${AWS::AccountId}\"}}}]}" Topics: - !Ref SNSTopic SNSSubscription: Type: "AWS::SNS::Subscription" Properties: TopicArn: !Ref SNSTopic Endpoint: !Ref DestinationPhoneNumber Protocol: "sms" Region: !Ref AWS::Region SNSSubscriptionEmail: Type: "AWS::SNS::Subscription" Properties: TopicArn: !Ref SNSTopic Endpoint: !Ref ContactEmailAddress Protocol: "email" Region: !Ref AWS::Region Outputs: LambdaLex: Description: ARN of the lambda backend Amazon Lex Value: !GetAtt LambdaLex.Arn LambdaAlexa: Description: ARN of the Lambda Backend Amazon Alexa Value: !GetAtt LambdaAlexa.Arn DynamoDBTableCustomerInteractionsApp: Description: Customer Interactions App Table Value: !Ref 'TableInteractionsApp' DynamoDBTableCustomerInteractionsVoice: Description: Customer Interactions Voice Table Value: !Ref 'TableInteractionsVoice' DynamoDBTableCustomerInteractionsChat: Description: Customer Interactions Chatbot Table Value: !Ref 'TableInteractionsChat' DynamoDBTableOffices: Description: Cloud Bank Office Information Value: !Ref 'TableOffices' DynamoDBTableCustomerInfo: Description: Cloud Bank Customer Information Value: !Ref 'TableCustomerInfo' DynamoDBTableLocalization: Description: Cloud Bank Message Localization Value: !Ref 'TableLocalization'