AWSTemplateFormatVersion: '2010-09-09' Transform: 'AWS::Serverless-2016-10-31' Description: AWS CloudFormation template for Amazon IVS Transcribe demo - suffix Parameters: # Translate feature flag EnableTranslate: Type: String Description: "Enable or disable Translate" AllowedValues: - 'true' - 'false' AudioLanguageCode: Type: String Description: ISO 639-1 code of the audio language to be transcribed Default: en AudioLanguageTranscribeCode: Type: String Description: Amazon Transcribe code of the audio language to be transcribed Default: en-US # Lambda functions parameters LambdaOnConnectFunctionName: Type: String Description: Name of the lambda-on-connect function Default: ivs-transcribe-demo-on-connect- LambdaOnDisconnectFunctionName: Type: String Description: Name of the lambda-on-disconnect function Default: ivs-transcribe-demo-on-disconnect- LambdaSendTranscriptionFunctionName: Type: String Description: Name of the lambda-send-transcription function Default: ivs-transcribe-demo-send-transcription- LambdaSendTranscriptionChunksFunctionName: Type: String Description: Name of the lambda-send-transcription-chunks function Default: ivs-transcribe-demo-send-transcription-chunks- LambdaDeleteStaleConnectionFunctionName: Type: String Description: Name of the lambda-delete-stale-connection function Default: ivs-transcribe-demo-delete-stale-connection- # ECS resources parameters ECSClusterName: Type: String Description: Name of the ECS Cluster Default: ivs-transcribe-demo-cluster- StreamServiceName: Type: String Description: Name of the Stream service Default: ivs-transcribe-demo-stream-service- TranscribeServiceName: Type: String Description: Name of the Transcribe service Default: ivs-transcribe-demo-transcribe-service- TranslateServiceName: Type: String Description: Name of the Translate service Default: ivs-transcribe-demo-translate-service- StreamTaskDefinitionName: Type: String Description: Name of the Stream service task definition Default: ivs-transcribe-demo-stream-task-definition- TranscribeTaskDefinitionName: Type: String Description: Name of the Transcribe service task definition Default: ivs-transcribe-demo-transcribe-task-definition- TranslateTaskDefinitionName: Type: String Description: Name of the Translate service task definition Default: ivs-transcribe-demo-translate-task-definition- StreamContainerDefinitionName: Type: String Description: Name of the Stream service container definition Default: ivs-transcribe-demo-stream-container-definition- TranscribeContainerDefinitionName: Type: String Description: Name of the Transcribe service container definition Default: ivs-transcribe-demo-transcribe-container-definition- TranslateContainerDefinitionName: Type: String Description: Name of the Translate service container definition Default: ivs-transcribe-demo-translate-container-definition- StreamServiceLogGroupName: Type: String Description: Name of the Stream service CloudWatch log group Default: /ecs/ivs-transcribe-demo-stream-logs- TranscribeServiceLogGroupName: Type: String Description: Name of the Transcribe service CloudWatch log group Default: /ecs/ivs-transcribe-demo-transcribe-logs- TranslateServiceLogGroupName: Type: String Description: Name of the Translate service CloudWatch log group Default: /ecs/ivs-transcribe-demo-translate-logs- PrivateDNSNamespaceName: Type: String Description: Name of the private DNS Namespace Default: rtmp StreamServiceDiscoveryName: Type: String Description: Name of the Stream Service Discovery Default: stream-service-discovery TranslateServiceDiscoveryName: Type: String Description: Name of the Stream Service Discovery Default: translate-service-discovery ECRStreamRepositoryName: Type: String Description: Name of the private DNS Namespace Default: ivs-transcribe-demo-stream-images- ECRTranscribeRepositoryName: Type: String Description: Name of the private DNS Namespace Default: ivs-transcribe-demo-transcribe-images- ECRTranslateRepositoryName: Type: String Description: Name of the private DNS Namespace Default: ivs-transcribe-demo-translate-images- TranslateServiceTranslationsLanguageCodes: Type: String Description: Language codes of the translations to be performed # S3 resources parameters VocabularyConfigurationBucketName: Type: String Description: Name of the Transcribe service configuration bucket that contains the custom vocabulary and vocabulary filter Default: ivs-transcribe-demo-vocabulary-config- PlayerAppBucketName: Type: String Description: Name of the Player App bucket Default: ivs-transcribe-demo-player-app- LambdaFunctionsBucketName: Type: String Description: Name of the bucket that contains the Lambda functions zip files Default: ivs-transcribe-demo-lambda-functions- IVSChannelName: Type: String Description: Name of the IVS Channel Default: ivs-transcribe-demo-channel- WriterWebSocketName: Type: String Description: Name of the writer WebSocket used to send transcriptions to clients (players) Default: ivs-transcribe-demo-writer-websocket- ReaderWebSocketName: Type: String Description: Name of the reader WebSocket used to keep track of the client (player) connections Default: ivs-transcribe-demo-reader-websocket- # DynamoDB resources parameters DynamoDBOverlaysTableName: Type: String Description: Name of the overlays configuration table Default: ivs-transcribe-demo-overlays- DynamoDBConnectionsTableName: Type: String Description: Name of the connections table Default: ivs-transcribe-demo-connections- # Other TranscribeCustomVocabularyName: Type: String Description: Name of the custom vocabulary that will be configured in Transcribe Default: ivs-transcribe-demo-custom-vocabulary- TranscribeVocabularyFilterName: Type: String Description: Name of the vocabulary filter that will be configured in Transcribe Default: ivs-transcribe-demo-vocabulary-filter- #Check conditions of translate Conditions: TranslateEnabled: !Equals - !Ref EnableTranslate - 'true' Mappings: SubnetConfig: VPC: CIDR: '24.0.0.0/16' Subnet: CIDR: '24.0.0.0/24' Resources: # Lambda functions resources LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Policies: - PolicyName: root PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: # Rules for DynamoDB - 'dynamodb:Query' - 'dynamodb:PutItem' - 'dynamodb:DeleteItem' # Rules for CloudWatch - 'logs:CreateLogGroup' - 'logs:CreateLogStream' - 'logs:PutLogEvents' # Rules for API Gateway - 'execute-api:ManageConnections' # Rules for lambdas - 'lambda:InvokeFunction' Resource: '*' LambdaOnConnect: Type: AWS::Lambda::Function Properties: Role: !GetAtt LambdaExecutionRole.Arn Code: S3Bucket: !Ref LambdaFunctionsBucketName S3Key: lambda-on-connect.zip FunctionName: !Ref LambdaOnConnectFunctionName Handler: app.handler Runtime: nodejs14.x Environment: Variables: TABLE_NAME: !Ref DynamoDBConnectionsTableName LambdaOnDisconnect: Type: AWS::Lambda::Function Properties: Role: !GetAtt LambdaExecutionRole.Arn Code: S3Bucket: !Ref LambdaFunctionsBucketName S3Key: lambda-on-disconnect.zip FunctionName: !Ref LambdaOnDisconnectFunctionName Handler: app.handler Runtime: nodejs14.x Environment: Variables: TABLE_NAME: !Ref DynamoDBConnectionsTableName LambdaSendTranscription: Type: AWS::Lambda::Function Properties: Role: !GetAtt LambdaExecutionRole.Arn Code: S3Bucket: !Ref LambdaFunctionsBucketName S3Key: lambda-send-transcription.zip FunctionName: !Ref LambdaSendTranscriptionFunctionName Handler: app.handler Runtime: nodejs14.x Environment: Variables: TABLE_NAME: !Ref DynamoDBConnectionsTableName GATEWAY_DOMAIN: !Sub "${ReaderWebSocket}.execute-api.${AWS::Region}.amazonaws.com/demo" LAMBDA_SEND_TRANSCRIPTION_CHUNKS_NAME: !Ref LambdaSendTranscriptionChunksFunctionName LAMBDA_DELETE_STALE_CONNECTION_NAME: !Ref LambdaDeleteStaleConnectionFunctionName LambdaSendTranscriptionChunks: Type: AWS::Lambda::Function Properties: Role: !GetAtt LambdaExecutionRole.Arn Code: S3Bucket: !Ref LambdaFunctionsBucketName S3Key: lambda-send-transcription-chunks.zip FunctionName: !Ref LambdaSendTranscriptionChunksFunctionName Handler: app.handler Runtime: nodejs14.x Environment: Variables: TABLE_NAME: !Ref DynamoDBConnectionsTableName GATEWAY_DOMAIN: !Sub "${ReaderWebSocket}.execute-api.${AWS::Region}.amazonaws.com/demo" LAMBDA_DELETE_STALE_CONNECTION_NAME: !Ref LambdaDeleteStaleConnectionFunctionName LambdaDeleteStaleConnection: Type: AWS::Lambda::Function Properties: Role: !GetAtt LambdaExecutionRole.Arn Code: S3Bucket: !Ref LambdaFunctionsBucketName S3Key: lambda-delete-stale-connection.zip FunctionName: !Ref LambdaDeleteStaleConnectionFunctionName Handler: app.handler Runtime: nodejs14.x Environment: Variables: TABLE_NAME: !Ref DynamoDBConnectionsTableName ################################# ECS Resources # VPC VPC: Type: 'AWS::EC2::VPC' Properties: CidrBlock: !FindInMap ['SubnetConfig', 'VPC', 'CIDR'] EnableDnsHostnames: true EnableDnsSupport: true Subnet: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC CidrBlock: !FindInMap ['SubnetConfig', 'Subnet', 'CIDR'] MapPublicIpOnLaunch: true InternetGateway: Type: AWS::EC2::InternetGateway DependsOn: VPC VPCGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway RouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Route: Type: AWS::EC2::Route DependsOn: VPCGatewayAttachment Properties: RouteTableId: !Ref RouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway SubnetRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref Subnet RouteTableId: !Ref RouteTable PrivateDnsNamespace: Type: AWS::ServiceDiscovery::PrivateDnsNamespace Properties: Name: !Ref PrivateDNSNamespaceName Vpc: !Ref VPC ## Security groups StreamServiceSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security Group for ECS Stream service VpcId: !Ref VPC StreamServiceSecurityGroupInboundRule: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !GetAtt StreamServiceSecurityGroup.GroupId IpProtocol: tcp FromPort: 1935 ToPort: 1935 CidrIp: 0.0.0.0/0 StreamServiceSecurityGroupOutboundRule: Type: AWS::EC2::SecurityGroupEgress Properties: GroupId: !GetAtt StreamServiceSecurityGroup.GroupId IpProtocol: -1 CidrIp: 0.0.0.0/0 TranscribeServiceSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security Group for ECS Transcribe service VpcId: !Ref VPC TranscribeServiceSecurityGroupInboundRule: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !GetAtt TranscribeServiceSecurityGroup.GroupId IpProtocol: tcp FromPort: 1935 ToPort: 1935 CidrIp: 0.0.0.0/0 TranscribeServiceSecurityGroupOutboundRule: Type: AWS::EC2::SecurityGroupEgress Properties: GroupId: !GetAtt TranscribeServiceSecurityGroup.GroupId IpProtocol: -1 CidrIp: 0.0.0.0/0 TranslateServiceSecurityGroup: Condition: TranslateEnabled Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security Group for ECS Translate service VpcId: !Ref VPC TranslateServiceSecurityGroupInboundRule: Condition: TranslateEnabled Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !GetAtt TranslateServiceSecurityGroup.GroupId IpProtocol: tcp FromPort: 3600 ToPort: 3600 CidrIp: 0.0.0.0/0 TranslateServiceSecurityGroupOutboundRule: Condition: TranslateEnabled Type: AWS::EC2::SecurityGroupEgress Properties: GroupId: !GetAtt TranslateServiceSecurityGroup.GroupId IpProtocol: -1 CidrIp: 0.0.0.0/0 ## Log groups StreamServiceLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Ref StreamServiceLogGroupName TranscribeServiceLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Ref TranscribeServiceLogGroupName TranslateServiceLogGroup: Condition: TranslateEnabled Type: AWS::Logs::LogGroup Properties: LogGroupName: !Ref TranslateServiceLogGroupName ## Cluster ECSCluster: Type: AWS::ECS::Cluster Properties: ClusterName: !Ref ECSClusterName ## Roles ECSRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: [ecs-tasks.amazonaws.com] Action: ['sts:AssumeRole'] Path: / Policies: - PolicyName: ecs-service PolicyDocument: Statement: - Effect: Allow Action: # Rules which allow ECS to attach network interfaces to instances # on your behalf in order for awsvpc networking mode to work right - 'ec2:AttachNetworkInterface' - 'ec2:CreateNetworkInterface' - 'ec2:CreateNetworkInterfacePermission' - 'ec2:DeleteNetworkInterface' - 'ec2:DeleteNetworkInterfacePermission' - 'ec2:Describe*' - 'ec2:DetachNetworkInterface' # Rules for DynamoDB - 'dynamodb:Scan' # Rules for Transcribe - 'transcribe:StartStreamTranscription' # Rules for Translate - 'translate:TranslateText' - 'translate:GetTerminology' - 'translate:ListTerminologies' - 'translate:ListTextTranslationJobs' - 'translate:DescribeTextTranslationJob' - 'translate:GetParallelData' - 'translate:ListParallelData' - 'comprehend:DetectDominantLanguage' # Rules for API Gateway - 'execute-api:ManageConnections' # Rules for IVS - 'ivs:PutMetadata' Resource: '*' ECSTaskExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: [ecs-tasks.amazonaws.com] Action: ['sts:AssumeRole'] Path: / Policies: - PolicyName: AmazonECSTaskExecutionRolePolicy PolicyDocument: Statement: - Effect: Allow Action: # Allow the ECS Tasks to download images from ECR - 'ecr:GetAuthorizationToken' - 'ecr:BatchCheckLayerAvailability' - 'ecr:GetDownloadUrlForLayer' - 'ecr:BatchGetImage' # Allow the ECS tasks to upload logs to CloudWatch - 'logs:CreateLogStream' - 'logs:PutLogEvents' Resource: '*' ## Stream service StreamTaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: !Ref StreamTaskDefinitionName ExecutionRoleArn: !Ref ECSTaskExecutionRole ContainerDefinitions: - Name: !Ref StreamContainerDefinitionName ReadonlyRootFilesystem: false # disabled Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECRStreamRepositoryName}:latest' LogConfiguration: LogDriver: awslogs Options: awslogs-region: !Sub '${AWS::Region}' awslogs-group: !Ref StreamServiceLogGroupName awslogs-stream-prefix: ecs PortMappings: - ContainerPort: 1935 HostPort: 1935 Protocol: "tcp" - ContainerPort: 19351 HostPort: 19351 Protocol: "tcp" Environment: - Name : IVS_INGEST_ENDPOINT Value: !Sub ${IVSChannel.IngestEndpoint}:443 - Name : IVS_KEY Value: !GetAtt IVSStreamKey.Value - Name : STREAM_KEY Value: !Sub streamkey-${AWS::StackName}- Cpu: 0 Memory: 4096 TaskRoleArn: !GetAtt ECSRole.Arn RequiresCompatibilities: - FARGATE NetworkMode: awsvpc Cpu: 2048 StreamServiceDiscovery: Type: AWS::ServiceDiscovery::Service Properties: Name: !Ref StreamServiceDiscoveryName DnsConfig: DnsRecords: - TTL: 60 Type: A NamespaceId: !Ref PrivateDnsNamespace StreamService: Type: AWS::ECS::Service Properties: LaunchType: FARGATE Cluster: !Ref ECSCluster ServiceName: !Ref StreamServiceName TaskDefinition: !Ref StreamTaskDefinition DesiredCount: 1 NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED Subnets: - !Ref Subnet SecurityGroups: - !Ref StreamServiceSecurityGroup # Service discovery ServiceRegistries: - RegistryArn: !GetAtt StreamServiceDiscovery.Arn # Transcribe service TranscribeTaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: !Ref TranscribeTaskDefinitionName ExecutionRoleArn: !Ref ECSTaskExecutionRole ContainerDefinitions: - Name: !Ref TranscribeContainerDefinitionName ReadonlyRootFilesystem: false # disabled Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECRTranscribeRepositoryName}:latest' LogConfiguration: LogDriver: awslogs Options: awslogs-region: !Sub '${AWS::Region}' awslogs-group: !Ref TranscribeServiceLogGroupName awslogs-stream-prefix: ecs Cpu: 0 Environment: - Name: AWS_REGION Value: !Sub '${AWS::Region}' - Name: AUDIO_LANGUAGE_TRANSCRIBE_CODE Value: !Ref AudioLanguageTranscribeCode - Name: AUDIO_LANGUAGE_CODE Value: !Ref AudioLanguageCode - Name: CUSTOM_VOCABULARY_NAME Value: !Ref TranscribeCustomVocabularyName - Name: VOCABULARY_FILTER Value: !Ref TranscribeVocabularyFilterName - Name: IVS_CHANNEL_ARN Value: !Ref IVSChannel - Name: WRITER_WEBSOCKET_API_URL Value: !Join [ "/", [ !GetAtt WriterWebSocket.ApiEndpoint, !Ref WriterWebSocketStage ] ] - Name: RTMP_INPUT Value: !Sub rtmp://${StreamServiceDiscovery.Name}.${PrivateDNSNamespaceName}/ivs/streamkey-${AWS::StackName}- - Name: KEYWORDS_TABLE_NAME Value: !Ref DynamoDBOverlaysTableName - Name: TRANSLATE_ENABLED Value: !Ref EnableTranslate - Name: TRANSLATE_WEBSOCKET_URL Value: !If [ TranslateEnabled, !Sub 'ws://${TranslateServiceDiscovery.Name}.${PrivateDNSNamespaceName}:3600', !Ref "AWS::NoValue"] Memory: 1024 TaskRoleArn: !GetAtt ECSRole.Arn RequiresCompatibilities: - FARGATE NetworkMode: awsvpc Cpu: 512 TranscribeService: Type: AWS::ECS::Service Properties: LaunchType: FARGATE Cluster: !Ref ECSCluster ServiceName: !Ref TranscribeServiceName TaskDefinition: !Ref TranscribeTaskDefinition DesiredCount: 1 NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED Subnets: - !Ref Subnet SecurityGroups: - !Ref TranscribeServiceSecurityGroup # Translate service TranslateTaskDefinition: Condition: TranslateEnabled Type: AWS::ECS::TaskDefinition Properties: Family: !Ref TranslateTaskDefinitionName ExecutionRoleArn: !Ref ECSTaskExecutionRole ContainerDefinitions: - Name: !Ref TranslateContainerDefinitionName ReadonlyRootFilesystem: false # disabled Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECRTranslateRepositoryName}:latest' LogConfiguration: LogDriver: awslogs Options: awslogs-region: !Sub '${AWS::Region}' awslogs-group: !Ref TranslateServiceLogGroupName awslogs-stream-prefix: ecs PortMappings: - ContainerPort: 3600 HostPort: 3600 Protocol: "tcp" Environment: - Name: AWS_REGION Value: !Sub '${AWS::Region}' - Name: AWS_GW_WS Value: !Join [ "/", [ !GetAtt WriterWebSocket.ApiEndpoint, !Ref WriterWebSocketStage ] ] - Name: AUDIO_LANGUAGE_CODE Value: !Ref AudioLanguageCode - Name: CAPTIONS_TRANSLATIONS_LANGUAGE_CODES Value: !Ref TranslateServiceTranslationsLanguageCodes Cpu: 0 Memory: 1024 TaskRoleArn: !GetAtt ECSRole.Arn RequiresCompatibilities: - FARGATE NetworkMode: awsvpc Cpu: 512 TranslateServiceDiscovery: Condition: TranslateEnabled Type: AWS::ServiceDiscovery::Service Properties: Name: !Ref TranslateServiceDiscoveryName DnsConfig: DnsRecords: - TTL: 60 Type: A NamespaceId: !Ref PrivateDnsNamespace TranslateService: Condition: TranslateEnabled Type: AWS::ECS::Service Properties: LaunchType: FARGATE Cluster: !Ref ECSCluster ServiceName: !Ref TranslateServiceName TaskDefinition: !Ref TranslateTaskDefinition DesiredCount: 1 NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED Subnets: - !Ref Subnet SecurityGroups: - !Ref TranslateServiceSecurityGroup # Service discovery ServiceRegistries: - RegistryArn: !GetAtt TranslateServiceDiscovery.Arn ################################## IVS resources IVSChannel: Type: AWS::IVS::Channel Properties: Name: !Ref IVSChannelName IVSStreamKey: Type: AWS::IVS::StreamKey Properties: ChannelArn: !Ref IVSChannel ################################## API Gateway resources # Api gateway role ApiGatewayRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Sid: '' Effect: 'Allow' Principal: Service: - 'apigateway.amazonaws.com' Action: - 'sts:AssumeRole' Path: '/' Policies: - PolicyName: LambdaAccess PolicyDocument: Version: '2012-10-17' Statement: - Effect: 'Allow' Action: 'lambda:InvokeFunction' Resource: '*' WriterWebSocket: Type: 'AWS::ApiGatewayV2::Api' Properties: Name: !Ref WriterWebSocketName ProtocolType: WEBSOCKET RouteSelectionExpression: $request.body.action ReaderWebSocket: Type: 'AWS::ApiGatewayV2::Api' Properties: Name: !Ref ReaderWebSocketName ProtocolType: WEBSOCKET RouteSelectionExpression: $request.body.action ## Reader WebSocket routes ### $connect ReaderWebSocketRouteConnect: Type: AWS::ApiGatewayV2::Route Properties: ApiId: !Ref ReaderWebSocket RouteKey: $connect AuthorizationType: NONE Target: !Join - / - - integrations - !Ref ReaderWebSocketRouteConnectIntegration ReaderWebSocketRouteConnectIntegration: Type: AWS::ApiGatewayV2::Integration Properties: ApiId: !Ref ReaderWebSocket IntegrationType: AWS_PROXY IntegrationUri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaOnConnect.Arn}/invocations CredentialsArn: !GetAtt ApiGatewayRole.Arn ### $disconnect ReaderWebSocketRouteDisconnect: Type: AWS::ApiGatewayV2::Route Properties: ApiId: !Ref ReaderWebSocket RouteKey: $disconnect AuthorizationType: NONE Target: !Join - / - - integrations - !Ref ReaderWebSocketRouteDisconnectIntegration ReaderWebSocketRouteDisconnectIntegration: Type: AWS::ApiGatewayV2::Integration Properties: ApiId: !Ref ReaderWebSocket IntegrationType: AWS_PROXY IntegrationUri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaOnDisconnect.Arn}/invocations CredentialsArn: !GetAtt ApiGatewayRole.Arn ## Writer WebSocket routes ### sendtrancription WriterWebSocketRouteSendTranscription: Type: AWS::ApiGatewayV2::Route Properties: ApiId: !Ref WriterWebSocket RouteKey: sendtranscription AuthorizationType: NONE Target: !Join - / - - integrations - !Ref WriterWebSocketRouteSendTranscriptionIntegration WriterWebSocketRouteSendTranscriptionIntegration: Type: AWS::ApiGatewayV2::Integration Properties: ApiId: !Ref WriterWebSocket IntegrationType: AWS_PROXY IntegrationUri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaSendTranscription.Arn}/invocations CredentialsArn: !GetAtt ApiGatewayRole.Arn ## Stages ReaderWebSocketStage: Type: AWS::ApiGatewayV2::Stage Properties: StageName: demo ApiId: !Ref ReaderWebSocket WriterWebSocketStage: Type: AWS::ApiGatewayV2::Stage Properties: StageName: demo ApiId: !Ref WriterWebSocket ## Deployments ReaderWebSocketDeployment: DependsOn: [ReaderWebSocketRouteConnect, ReaderWebSocketRouteDisconnect] Type: AWS::ApiGatewayV2::Deployment Properties: ApiId: !Ref ReaderWebSocket StageName: demo WriterWebSocketDeployment: DependsOn: [WriterWebSocketRouteSendTranscription] Type: AWS::ApiGatewayV2::Deployment Properties: ApiId: !Ref WriterWebSocket StageName: demo ################################## S3 resources TranscribeConfigurationBucket: Type: AWS::S3::Bucket Properties: BucketName: !Ref VocabularyConfigurationBucketName PlayerAppBucket: Type: AWS::S3::Bucket Properties: BucketName: !Ref PlayerAppBucketName PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true PlayerAppBucketPolicy: Type: 'AWS::S3::BucketPolicy' Properties: Bucket: !Ref PlayerAppBucket PolicyDocument: Version: "2012-10-17" Id: "PolicyForCloudFrontPrivateContent" Statement: - Effect: Allow Principal: AWS: !Sub "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${CloudFrontPlayerAppOriginAccessIdentity}" Action: s3:GetObject Resource: !Sub "arn:aws:s3:::${PlayerAppBucket}/*" ################################## DynamoDB resources DynamoDbOverlaysTable: Type: AWS::DynamoDB::Table Properties: TableName: !Ref DynamoDBOverlaysTableName AttributeDefinitions: - AttributeName: "keyword" AttributeType: "S" KeySchema: - AttributeName: "keyword" KeyType: "HASH" ProvisionedThroughput: ReadCapacityUnits: "5" WriteCapacityUnits: "5" DynamoDbConnectionsTable: Type: AWS::DynamoDB::Table Properties: TableName: !Ref DynamoDBConnectionsTableName AttributeDefinitions: - AttributeName: "connectionId" AttributeType: "S" - AttributeName: "lang" AttributeType: "S" KeySchema: - AttributeName: "connectionId" KeyType: "HASH" ProvisionedThroughput: ReadCapacityUnits: "5" WriteCapacityUnits: "5" GlobalSecondaryIndexes: - IndexName: lang-index KeySchema: - AttributeName: lang KeyType: HASH Projection: ProjectionType: ALL ProvisionedThroughput: ReadCapacityUnits: "5" WriteCapacityUnits: "5" CloudFrontPlayerAppOriginAccessIdentity: Type: AWS::CloudFront::CloudFrontOriginAccessIdentity Properties: CloudFrontOriginAccessIdentityConfig: Comment: !Sub "access-identity-${PlayerAppBucketName}.s3.amazonaws.com" CloudFrontPlayerAppDistribution: Type: AWS::CloudFront::Distribution DependsOn: ['PlayerAppBucket'] Properties: DistributionConfig: DefaultRootObject: 'index.html' Enabled: true Origins: - DomainName: !GetAtt PlayerAppBucket.RegionalDomainName ConnectionAttempts: 3 ConnectionTimeout: 10 Id: !Sub "S3-${PlayerAppBucketName}" S3OriginConfig: OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontPlayerAppOriginAccessIdentity}" PriceClass: PriceClass_100 ViewerCertificate: CloudFrontDefaultCertificate: 'true' DefaultCacheBehavior: ViewerProtocolPolicy: redirect-to-https AllowedMethods: - GET - HEAD TargetOriginId: !Sub "S3-${PlayerAppBucketName}" ForwardedValues: QueryString: false Outputs: AWSRegion: Value: !Ref AWS::Region ReaderWebSocketURL: Value: !Sub "wss://${ReaderWebSocket}.execute-api.${AWS::Region}.amazonaws.com/demo" StreamPlaybackURL: Value: !GetAtt IVSChannel.PlaybackUrl PlayerAppURL: Value: !GetAtt CloudFrontPlayerAppDistribution.DomainName ClusterName: Value: !Ref ECSClusterName StreamServiceName: Value: !Ref StreamServiceName WriterWebSocketApiId: Value: !Ref WriterWebSocket ReaderWebSocketApiId: Value: !Ref ReaderWebSocket EnableTranslate: Value: !Ref EnableTranslate CaptionsTranslationsLanguageCodes: Value: !Ref TranslateServiceTranslationsLanguageCodes StreamKey: Value: !Sub streamkey-${AWS::StackName}- AudioLanguageCode: Value: !Ref AudioLanguageCode