# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 AWSTemplateFormatVersion: 2010-09-09 Description: > Amazon Connect instance CloudFormation template. Creates an Amazon Connect Instance, Hours of Operation, Contact Flow. Creates an Agent user for calls to be directed to. Creates an Admin user to manage Amazon Connect. Passwords for the Agent and Admin are stored as Secure Strings in AWS Systems Manager Parameter Store. Parameters: Environment: Type: String Default: dev Description: Environment to deploy into AllowedValues: [dev, uat, prod] Resources: AmazonConnectInstance: Type: AWS::Connect::Instance Properties: Attributes: ContactflowLogs: true InboundCalls: true OutboundCalls: false IdentityManagementType: CONNECT_MANAGED InstanceAlias: !Sub - ${prefix}-${randomString}-${environment} - prefix: summit-demo randomString: !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]] environment: !Ref Environment HoursOfOperation: Type: AWS::Connect::HoursOfOperation Properties: Name: Office Hours Description: Office Hours InstanceArn: !GetAtt AmazonConnectInstance.Arn TimeZone: Asia/Singapore Config: - Day: MONDAY EndTime: Hours: 19 Minutes: 0 StartTime: Hours: 9 Minutes: 30 - Day: TUESDAY EndTime: Hours: 19 Minutes: 0 StartTime: Hours: 9 Minutes: 30 - Day: WEDNESDAY EndTime: Hours: 19 Minutes: 0 StartTime: Hours: 9 Minutes: 30 - Day: THURSDAY EndTime: Hours: 19 Minutes: 0 StartTime: Hours: 9 Minutes: 30 - Day: FRIDAY EndTime: Hours: 19 Minutes: 0 StartTime: Hours: 9 Minutes: 30 CustomResourceGetSecurityProfileAgent: Type: Custom::S3CustomResource Properties: ServiceToken: !GetAtt LambdaFunctionGetSecurityProfile.Arn SecurityProfileName: Agent LambdaFunctionGetSecurityProfile: Type: AWS::Lambda::Function Metadata: cfn_nag: rules_to_suppress: - id: W58 reason: Permission to write to CloudWatch logs is part of the managed policy AWSLambdaBasicExecutionRole - id: W89 reason: Lambda function does not interact with resources in the VPC and does not handle sensitive data - id: W92 reason: This lambda function does not require ReservedConcurrentExecutions Properties: Handler: index.lambda_handler Description: > Get Security Profile ID, ARN Role: !GetAtt GetSecurityProfileRole.Arn Runtime: python3.10 MemorySize: 128 Timeout: 30 Environment: Variables: LOG_LEVEL: INFO INSTANCE_ID: !Ref AmazonConnectInstance Code: ZipFile: | import boto3 import logging import os import cfnresponse client = boto3.client('connect') LOG_LEVEL = os.getenv('LOG_LEVEL') INSTANCE_ID = os.getenv('INSTANCE_ID') def lambda_handler(event, context): global log_level log_level = str(LOG_LEVEL).upper() if log_level not in { 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL' }: log_level = 'ERROR' logging.getLogger().setLevel(log_level) logging.info(f'Event: {event}') request_type = event['RequestType'] if request_type == 'Delete': cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) return if request_type in {'Create', 'Update'}: try: security_profile_name = event['ResourceProperties']['SecurityProfileName'] marker = None while True: paginator = client.get_paginator('list_security_profiles') response_iterator = paginator.paginate( InstanceId=INSTANCE_ID, PaginationConfig={ 'PageSize': 10, 'StartingToken': marker } ) for page in response_iterator: security_profiles = page['SecurityProfileSummaryList'] for security_profile in security_profiles: if security_profile['Name'] == security_profile_name: response_data = { 'SecurityProfileId': security_profile['Id'], 'SecurityProfileArn': security_profile['Arn'], } cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data) return try: marker = response_iterator['Marker'] except Exception as e: logging.error(e) cfnresponse.send(event, context, cfnresponse.FAILED, {'message': f'ERROR: {e}'}) break except Exception as e: logging.error(e) cfnresponse.send(event, context, cfnresponse.FAILED, {'message': f'ERROR: {e}'}) return GetSecurityProfileRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: listConnectSecurityProfiles PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - connect:ListSecurityProfiles Resource: !Sub arn:${AWS::Partition}:connect:${AWS::Region}:${AWS::AccountId}:instance* Condition: StringEquals: connect:InstanceId: !GetAtt AmazonConnectInstance.Id CustomResourceGetRoutingProfileBasic: Type: Custom::S3CustomResource Properties: ServiceToken: !GetAtt LambdaFunctionGetRoutingProfile.Arn RoutingProfileName: Basic Routing Profile LambdaFunctionGetRoutingProfile: Type: AWS::Lambda::Function Metadata: cfn_nag: rules_to_suppress: - id: W58 reason: Permission to write to CloudWatch logs is part of the managed policy AWSLambdaBasicExecutionRole - id: W89 reason: Lambda function does not interact with resources in the VPC and does not handle sensitive data - id: W92 reason: This lambda function does not require ReservedConcurrentExecutions Properties: Handler: index.lambda_handler Description: > Get Routing Profile ID, ARN Role: !GetAtt GetRoutingProfileRole.Arn Runtime: python3.10 MemorySize: 128 Timeout: 30 Environment: Variables: LOG_LEVEL: INFO INSTANCE_ID: !Ref AmazonConnectInstance Code: ZipFile: | import boto3 import logging import os import cfnresponse client = boto3.client('connect') LOG_LEVEL = os.getenv('LOG_LEVEL') INSTANCE_ID = os.getenv('INSTANCE_ID') def lambda_handler(event, context): global log_level log_level = str(LOG_LEVEL).upper() if log_level not in { 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL' }: log_level = 'ERROR' logging.getLogger().setLevel(log_level) logging.info(f'Event: {event}') request_type = event['RequestType'] if request_type == 'Delete': cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) return if request_type in {'Create', 'Update'}: try: routing_profile_name = event['ResourceProperties']['RoutingProfileName'] marker = None while True: paginator = client.get_paginator('list_routing_profiles') response_iterator = paginator.paginate( InstanceId=INSTANCE_ID, PaginationConfig={ 'PageSize': 10, 'StartingToken': marker } ) for page in response_iterator: routing_profiles = page['RoutingProfileSummaryList'] for routing_profile in routing_profiles: if routing_profile['Name'] == routing_profile_name: response_data = { 'RoutingProfileId': routing_profile['Id'], 'RoutingProfileArn': routing_profile['Arn'], } cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data) return try: marker = response_iterator['Marker'] except Exception as e: logging.error(e) cfnresponse.send(event, context, cfnresponse.FAILED, {'message': f'ERROR: {e}'}) break except Exception as e: logging.error(e) cfnresponse.send(event, context, cfnresponse.FAILED, {'message': f'ERROR: {e}'}) return GetRoutingProfileRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: listConnectRoutingProfiles PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - connect:ListRoutingProfiles Resource: !Sub arn:${AWS::Partition}:connect:${AWS::Region}:${AWS::AccountId}:instance* Condition: StringEquals: connect:InstanceId: !GetAtt AmazonConnectInstance.Id CustomResourceGenerateRandomStringAgent: Type: Custom::S3CustomResource Properties: ServiceToken: !GetAtt LambdaFunctionGenerateRandomString.Arn StringLength: 15 # Specify minimum 4, max 60 SecurityProfileName: Agent LambdaFunctionGenerateRandomString: Type: AWS::Lambda::Function Metadata: cfn_nag: rules_to_suppress: - id: W58 reason: Permission to write to CloudWatch logs is part of the managed policy AWSLambdaBasicExecutionRole - id: W89 reason: Lambda function does not interact with resources in the VPC and does not handle sensitive data - id: W92 reason: This lambda function does not require ReservedConcurrentExecutions Properties: Handler: index.lambda_handler Description: > Generate random string Role: !GetAtt GenerateRandomStringRole.Arn Runtime: python3.10 MemorySize: 128 Timeout: 3 Environment: Variables: LOG_LEVEL: INFO Code: ZipFile: | import boto3 import botocore import random import logging import os import cfnresponse import string client = boto3.client('ssm') LOG_LEVEL = os.getenv('LOG_LEVEL') def lambda_handler(event, context): global log_level log_level = str(LOG_LEVEL).upper() if log_level not in { 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL' }: log_level = 'ERROR' logging.getLogger().setLevel(log_level) logging.info(f'Event: {event}') request_type = event['RequestType'] if request_type == 'Delete': security_profile_name = event['ResourceProperties']['SecurityProfileName'] try: response = client.delete_parameter( Name=f'amazon-connect-temp-{security_profile_name}-password' ) cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) return except botocore.exceptions.ClientError as err: if err.response['Error']['Code'] == 'ParameterNotFound': cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) return else: logging.error(err) cfnresponse.send(event, context, cfnresponse.FAILED, {'message': f'ERROR: {err}'}) return except Exception as e: logging.error(e) cfnresponse.send(event, context, cfnresponse.FAILED, {'message': f'ERROR: {e}'}) return if request_type in {'Create', 'Update'}: try: string_length = event['ResourceProperties']['StringLength'] security_profile_name = event['ResourceProperties']['SecurityProfileName'] valid_characters = string.ascii_letters + string.digits + "!@#$%^&*_=-" # First 4 specifies a mix of from each combination random_string = random.SystemRandom().choice(string.ascii_lowercase) random_string += random.SystemRandom().choice(string.ascii_uppercase) random_string += random.SystemRandom().choice(string.digits) random_string += random.SystemRandom().choice('!@#$%^&*_=-') for i in range(int(string_length)-4): random_string += random.SystemRandom().choice(valid_characters) response = client.put_parameter( Name=f'amazon-connect-temp-{security_profile_name}-password', Description=f'SSM Parameter to store the temporary Amazon Connect {security_profile_name} Password', Value=random_string, Type='SecureString', Overwrite=True, Tier='Standard' ) response_data = { 'RandomString': random_string } cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data) except Exception as e: logging.error(e) cfnresponse.send(event, context, cfnresponse.FAILED, {'message': f'ERROR: {e}'}) return GenerateRandomStringRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: putAndDeleteSSMParameters PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - ssm:DeleteParameter - ssm:PutParameter Resource: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter* ConnectUserAgent: Type: AWS::Connect::User Properties: IdentityInfo: FirstName: demo LastName: user PhoneConfig: PhoneType: DESK_PHONE AutoAccept: true DeskPhoneNumber: '+12345678902' AfterContactWorkTimeLimit: 10 Username: demouser InstanceArn: !GetAtt AmazonConnectInstance.Arn RoutingProfileArn: !GetAtt CustomResourceGetRoutingProfileBasic.RoutingProfileArn SecurityProfileArns: [!GetAtt CustomResourceGetSecurityProfileAgent.SecurityProfileArn] Password: !GetAtt CustomResourceGenerateRandomStringAgent.RandomString PhoneNumber: Type: AWS::Connect::PhoneNumber Properties: TargetArn: !GetAtt AmazonConnectInstance.Arn Description: AnyCompany Phone Number Type: DID CountryCode: US Tags: - Key: Name Value: basicPhoneNumber CustomResourceAssociatePhoneNumberToContactFlow: Type: Custom::S3CustomResource Properties: ServiceToken: !GetAtt LambdaFunctionAssociatePhoneNumberToContactFlow.Arn LambdaFunctionAssociatePhoneNumberToContactFlow: Type: AWS::Lambda::Function Metadata: cfn_nag: rules_to_suppress: - id: W58 reason: Permission to write to CloudWatch logs is part of the managed policy AWSLambdaBasicExecutionRole - id: W89 reason: Lambda function does not interact with resources in the VPC and does not handle sensitive data - id: W92 reason: This lambda function does not require ReservedConcurrentExecutions Properties: Handler: index.lambda_handler Description: > Associate phone number to contact flow Role: !GetAtt AssociatePhoneNumberToContactFlowRole.Arn Runtime: python3.10 MemorySize: 128 Timeout: 30 Environment: Variables: LOG_LEVEL: INFO INSTANCE_ID: !GetAtt AmazonConnectInstance.Id PHONE_NUMBER_ID: !Select [1, !Split ['/', !Ref PhoneNumber]] CONTACT_FLOW_ID: !Select [3, !Split ['/', !Ref Flow]] Code: ZipFile: | import boto3 import logging import os import cfnresponse client = boto3.client('connect') LOG_LEVEL = os.getenv('LOG_LEVEL') INSTANCE_ID = os.getenv('INSTANCE_ID') PHONE_NUMBER_ID = os.getenv('PHONE_NUMBER_ID') CONTACT_FLOW_ID = os.getenv('CONTACT_FLOW_ID') def lambda_handler(event, context): global log_level log_level = str(LOG_LEVEL).upper() if log_level not in { 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL' }: log_level = 'ERROR' logging.getLogger().setLevel(log_level) logging.info(f'Event: {event}') request_type = event['RequestType'] if request_type == 'Delete': try: response = client.disassociate_phone_number_contact_flow( InstanceId=INSTANCE_ID, PhoneNumberId=PHONE_NUMBER_ID ) cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) return except Exception as e: logging.error(e) cfnresponse.send(event, context, cfnresponse.FAILED, {'message': f'ERROR: {e}'}) return if request_type in {'Create', 'Update'}: try: response = client.associate_phone_number_contact_flow( InstanceId=INSTANCE_ID, PhoneNumberId=PHONE_NUMBER_ID, ContactFlowId=CONTACT_FLOW_ID ) cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) return except Exception as e: logging.error(e) cfnresponse.send(event, context, cfnresponse.FAILED, {'message': f'ERROR: {e}'}) return AssociatePhoneNumberToContactFlowRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: associatePhoneNumberContactFlow PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - connect:AssociatePhoneNumberContactFlow Resource: - !Sub arn:${AWS::Partition}:connect:${AWS::Region}:${AWS::AccountId}:instance/${AmazonConnectInstance.Id}/contact-flow* - !Sub arn:${AWS::Partition}:connect:${AWS::Region}:${AWS::AccountId}:phone-number* Condition: StringEquals: connect:InstanceId: !GetAtt AmazonConnectInstance.Id - Effect: Allow Action: - connect:DisassociatePhoneNumberContactFlow Resource: - !Sub arn:${AWS::Partition}:connect:${AWS::Region}:${AWS::AccountId}:phone-number* Condition: StringEquals: connect:InstanceId: !GetAtt AmazonConnectInstance.Id CustomResourceGetContactFlowCustomerQueue: Type: Custom::S3CustomResource Properties: ServiceToken: !GetAtt LambdaFunctionGetContactFlow.Arn ContactFlowName: Default customer queue ContactFlowTypes: [CUSTOMER_QUEUE] LambdaFunctionGetContactFlow: Type: AWS::Lambda::Function Metadata: cfn_nag: rules_to_suppress: - id: W58 reason: Permission to write to CloudWatch logs is part of the managed policy AWSLambdaBasicExecutionRole - id: W89 reason: Lambda function does not interact with resources in the VPC and does not handle sensitive data - id: W92 reason: This lambda function does not require ReservedConcurrentExecutions Properties: Handler: index.lambda_handler Description: > Get Contact Flow ID, ARN Role: !GetAtt GetContactFlowRole.Arn Runtime: python3.10 MemorySize: 128 Timeout: 30 Environment: Variables: LOG_LEVEL: INFO INSTANCE_ID: !Ref AmazonConnectInstance Code: ZipFile: | import boto3 import logging import os import cfnresponse client = boto3.client('connect') LOG_LEVEL = os.getenv('LOG_LEVEL') INSTANCE_ID = os.getenv('INSTANCE_ID') def lambda_handler(event, context): global log_level log_level = str(LOG_LEVEL).upper() if log_level not in { 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL' }: log_level = 'ERROR' logging.getLogger().setLevel(log_level) logging.info(f'Event: {event}') request_type = event['RequestType'] if request_type == 'Delete': cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) return if request_type in {'Create', 'Update'}: try: contact_flow_name = event['ResourceProperties']['ContactFlowName'] contact_flow_types = event['ResourceProperties']['ContactFlowTypes'] marker = None while True: paginator = client.get_paginator('list_contact_flows') response_iterator = paginator.paginate( InstanceId=INSTANCE_ID, ContactFlowTypes=contact_flow_types, PaginationConfig={ 'PageSize': 10, 'StartingToken': marker } ) for page in response_iterator: contact_flows = page['ContactFlowSummaryList'] for contact_flow in contact_flows: if contact_flow['Name'] == contact_flow_name: response_data = { 'ContactFlowId': contact_flow['Id'], 'ContactFlowArn': contact_flow['Arn'], } cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data) return try: marker = response_iterator['Marker'] except Exception as e: logging.error(e) cfnresponse.send(event, context, cfnresponse.FAILED, {'message': f'ERROR: {e}'}) break except Exception as e: logging.error(e) cfnresponse.send(event, context, cfnresponse.FAILED, {'message': f'ERROR: {e}'}) return GetContactFlowRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: listConnectContactFlows PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - connect:ListContactFlows Resource: !Sub arn:${AWS::Partition}:connect:${AWS::Region}:${AWS::AccountId}:instance* Condition: StringEquals: connect:InstanceId: !GetAtt AmazonConnectInstance.Id Flow: Type: AWS::Connect::ContactFlow Properties: Name: AnyCompany Main Flow Description: flow created using cfn InstanceArn: !GetAtt AmazonConnectInstance.Arn Type: CONTACT_FLOW Content: !Sub | { "Version": "2019-10-30", "StartAction": "8a1b1f06-0b60-40a7-9cee-77b1b8a93634", "Metadata": { "entryPointPosition": { "x": -408, "y": 171.2 }, "ActionMetadata": { "6737f241-656c-4ab9-b5ce-781ca4ea7d58": { "position": { "x": -23.2, "y": 548 } }, "8a1b1f06-0b60-40a7-9cee-77b1b8a93634": { "position": { "x": -285.6, "y": 179.2 }, "parameters": { "HoursOfOperationId": { "displayName": "HoursOfOperation" } }, "Hours": { "id": "${HoursOfOperation.HoursOfOperationArn}", "text": "HoursOfOperation" } }, "eb8dce1a-15ee-4c37-a795-d812ca64e70c": { "position": { "x": 944, "y": 336 } }, "5ea8ece2-ad30-43c7-a758-64ae2bd33dfc": { "position": { "x": 8.8, "y": 194.4 } }, "06d0e1d7-5c1b-41ae-b401-052ed7283f97": { "position": { "x": 738.4, "y": 271.2 } }, "6d7fd93b-430b-4406-9cfc-ec9e329ec8ae": { "position": { "x": 500, "y": 189.6 }, "parameters": { "AgentId": { "displayName": "demouser (demo user)" } }, "queue": { "text": "demouser (demo user)" } }, "8f95c6f4-4ef8-4503-a332-a012d9ae0b0b": { "position": { "x": 733.6, "y": 38.4 }, "parameters": { "EventHooks": { "CustomerQueue": { "displayName": "Default customer queue" } } }, "contactFlow": { "text": "Default customer queue", "id": "${CustomResourceGetContactFlowCustomerQueue.ContactFlowArn}" }, "customerOrAgent": true } } }, "Actions": [ { "Parameters": { "Text": "Sorry, we are currently closed. Please call back during our operating hours. Our operating hours are from 9.30am to 7pm from Mondays to Fridays." }, "Identifier": "6737f241-656c-4ab9-b5ce-781ca4ea7d58", "Type": "MessageParticipant", "Transitions": { "NextAction": "eb8dce1a-15ee-4c37-a795-d812ca64e70c", "Errors": [ { "NextAction": "eb8dce1a-15ee-4c37-a795-d812ca64e70c", "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { "HoursOfOperationId": "${HoursOfOperation.HoursOfOperationArn}" }, "Identifier": "8a1b1f06-0b60-40a7-9cee-77b1b8a93634", "Type": "CheckHoursOfOperation", "Transitions": { "NextAction": "6737f241-656c-4ab9-b5ce-781ca4ea7d58", "Conditions": [ { "NextAction": "5ea8ece2-ad30-43c7-a758-64ae2bd33dfc", "Condition": { "Operator": "Equals", "Operands": [ "True" ] } }, { "NextAction": "6737f241-656c-4ab9-b5ce-781ca4ea7d58", "Condition": { "Operator": "Equals", "Operands": [ "False" ] } } ], "Errors": [ { "NextAction": "6737f241-656c-4ab9-b5ce-781ca4ea7d58", "ErrorType": "NoMatchingError" } ] } }, { "Parameters": {}, "Identifier": "eb8dce1a-15ee-4c37-a795-d812ca64e70c", "Type": "DisconnectParticipant", "Transitions": {} }, { "Parameters": { "Text": "Welcome to AnyCompany hotline. Please hold while we direct you to an agent." }, "Identifier": "5ea8ece2-ad30-43c7-a758-64ae2bd33dfc", "Type": "MessageParticipant", "Transitions": { "NextAction": "6d7fd93b-430b-4406-9cfc-ec9e329ec8ae", "Errors": [ { "NextAction": "6d7fd93b-430b-4406-9cfc-ec9e329ec8ae", "ErrorType": "NoMatchingError" } ] } }, { "Parameters": {}, "Identifier": "06d0e1d7-5c1b-41ae-b401-052ed7283f97", "Type": "TransferContactToQueue", "Transitions": { "NextAction": "eb8dce1a-15ee-4c37-a795-d812ca64e70c", "Errors": [ { "NextAction": "eb8dce1a-15ee-4c37-a795-d812ca64e70c", "ErrorType": "QueueAtCapacity" }, { "NextAction": "eb8dce1a-15ee-4c37-a795-d812ca64e70c", "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { "AgentId": "${ConnectUserAgent.UserArn}" }, "Identifier": "6d7fd93b-430b-4406-9cfc-ec9e329ec8ae", "Type": "UpdateContactTargetQueue", "Transitions": { "NextAction": "8f95c6f4-4ef8-4503-a332-a012d9ae0b0b", "Errors": [ { "NextAction": "8f95c6f4-4ef8-4503-a332-a012d9ae0b0b", "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { "EventHooks": { "CustomerQueue": "${CustomResourceGetContactFlowCustomerQueue.ContactFlowArn}" } }, "Identifier": "8f95c6f4-4ef8-4503-a332-a012d9ae0b0b", "Type": "UpdateContactEventHooks", "Transitions": { "NextAction": "06d0e1d7-5c1b-41ae-b401-052ed7283f97", "Errors": [ { "NextAction": "06d0e1d7-5c1b-41ae-b401-052ed7283f97", "ErrorType": "NoMatchingError" } ] } } ] } ConnectUserAdmin: Type: AWS::Connect::User Properties: IdentityInfo: FirstName: admin LastName: user PhoneConfig: PhoneType: 'DESK_PHONE' AutoAccept: true DeskPhoneNumber: '+12345678902' AfterContactWorkTimeLimit: 10 Username: adminuser InstanceArn: !GetAtt AmazonConnectInstance.Arn RoutingProfileArn: !GetAtt CustomResourceGetRoutingProfileBasic.RoutingProfileArn SecurityProfileArns: [!GetAtt CustomResourceGetSecurityProfileAdmin.SecurityProfileArn] Password: !GetAtt CustomResourceGenerateRandomStringAdmin.RandomString CustomResourceGenerateRandomStringAdmin: Type: Custom::S3CustomResource Properties: ServiceToken: !GetAtt LambdaFunctionGenerateRandomString.Arn StringLength: 15 SecurityProfileName: Admin CustomResourceGetSecurityProfileAdmin: Type: Custom::S3CustomResource Properties: ServiceToken: !GetAtt LambdaFunctionGetSecurityProfile.Arn SecurityProfileName: Admin