# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 AWSTemplateFormatVersion: 2010-09-09 Transform: 'AWS::Serverless-2016-10-31' Parameters: ECSTaskCpu: Type: Number Default: 4096 ECSTaskMemory: Type: Number Default: 8192 ECSContainerName: Type: String Default: 'recording-demo-container' ECSContainerCpu: Type: Number Default: 4096 ECSContainerMemory: Type: Number Default: 8192 ECSContainerMemoryReservation: Type: Number Default: 8192 EcsClusterName: Type: String Description: 'Specifies the ECS Cluster Name with which the resources would be associated' Default: 'RecordingDemoEC2Cluster' ECRDockerImageArn: Type: String Description: 'ARN of the docker image stored in ECR along with the tag' EcsAsgMinSize: Type: Number Default: 1 EcsAsgMaxSize: Type: Number Default: 5 DesiredCapacity: Type: Number Default: 2 Description: Number of instances to launch in your ECS cluster. ImageId: Type: AWS::SSM::Parameter::Value Description: Use an Image from SSM Parameter Store Default: /aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id InstanceType: Description: EC2 instance type Type: String Default: t3.xlarge AllowedValues: [mt2.large, t2.xlarge, t2.2xlarge, t3.large, t3.xlarge, t3.2xlarge, m4.large, m4.xlarge, m4.2xlarge, m4.4xlarge, m5.large, m5.xlarge, m5.2xlarge, m5.4xlarge, m5.8xlarge, c4.xlarge, c4.2xlarge, c4.4xlarge, c5.large, c5.xlarge, c5.2xlarge, c5.4xlarge] ConstraintDescription: Please choose a valid instance type. RecordingDemoLogGroupName: Type: String Default: RecordingDemoLogGroup EnvironmentName: Description: An environment name that is prefixed to resource names Type: String Default: recording-demo-environment VpcCIDR: Description: Please enter the IP range (CIDR notation) for this VPC Type: String Default: 10.192.0.0/16 PublicSubnet1CIDR: Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone Type: String Default: 10.192.10.0/24 PublicSubnet2CIDR: Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone Type: String Default: 10.192.11.0/24 Resources: RecordingArtifactsUploadBucket: Type: AWS::S3::Bucket Properties: AccessControl: BucketOwnerFullControl BucketName: Fn::Join: ['', ['chime-meeting-sdk-', {Ref: 'AWS::AccountId'}, '-', {Ref: 'AWS::Region'}, '-recordings']] RecordingDemoLambdaExecutionRole: Type: AWS::IAM::Role Properties: ManagedPolicyArns: - 'arn:aws:iam::aws:policy/CloudWatchLogsFullAccess' - 'arn:aws:iam::aws:policy/AmazonECS_FullAccess' AssumeRolePolicyDocument: Statement: - Action: ['sts:AssumeRole'] Effect: Allow Principal: Service: [lambda.amazonaws.com] Version: '2012-10-17' RecordingDemoBuildDeployGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: Ref: RecordingDemoLogGroupName RetentionInDays: 365 RecordingDemoLambdaFunction: Type: 'AWS::Serverless::Function' Properties: FunctionName: RecordingDemoLambda Description: Lambda to interact with ECS for starting and stopping recording. Handler: index.handler Role: Fn::GetAtt: [RecordingDemoLambdaExecutionRole, Arn] Runtime: nodejs12.x Timeout: 300 MemorySize: 3008 Environment: Variables: ecsClusterArn: Fn::GetAtt: [ECSCluster, Arn] ecsContainerName: Ref: ECSContainerName ecsTaskDefinationArn: Ref: ECSRecordingDemoTaskDefinition recordingArtifactsBucket: Ref: RecordingArtifactsUploadBucket CodeUri: ../src/ Events: Api1: Type: Api Properties: Path: /recording Method: POST ECSRecordingDemoTaskDefinition: Type: 'AWS::ECS::TaskDefinition' Properties: Cpu: Ref: ECSTaskCpu Memory: Ref: ECSTaskMemory RequiresCompatibilities: - EC2 Volumes: - Name: 'dbus' Host: SourcePath: '/run/dbus/system_bus_socket:/run/dbus/system_bus_socket' ContainerDefinitions: - Name: Ref: ECSContainerName Cpu: Ref: ECSContainerCpu Memory: Ref: ECSContainerMemory MemoryReservation: Ref: ECSContainerMemoryReservation Essential: true Image: Ref: ECRDockerImageArn LogConfiguration: LogDriver: awslogs Options: awslogs-group: Ref: RecordingDemoBuildDeployGroup awslogs-region: Ref: AWS::Region awslogs-stream-prefix: Ref: ECSContainerName LinuxParameters: SharedMemorySize: 2048 ECSCluster: Type: 'AWS::ECS::Cluster' Properties: ClusterName: Ref: EcsClusterName # Refer: https://docs.aws.amazon.com/codebuild/latest/userguide/cloudformation-vpc-template.html VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCIDR EnableDnsSupport: true EnableDnsHostnames: true InstanceTenancy: default Tags: - Key: Name Value: !Ref EnvironmentName InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Ref EnvironmentName InternetGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref VPC PublicSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 0, !GetAZs '' ] CidrBlock: !Ref PublicSubnet1CIDR MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${EnvironmentName} Public Subnet (AZ1) PublicSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 1, !GetAZs '' ] CidrBlock: !Ref PublicSubnet2CIDR MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${EnvironmentName} Public Subnet PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName} Public Routes DefaultPublicRoute: Type: AWS::EC2::Route DependsOn: InternetGatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnet1 PublicSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnet2 EcsSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: ECS Security Group VpcId: !Ref VPC EcsSecurityGroupHTTPinbound: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref EcsSecurityGroup IpProtocol: tcp FromPort: '80' ToPort: '80' CidrIp: 0.0.0.0/0 EcsSecurityGroupSSHinbound: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref EcsSecurityGroup IpProtocol: tcp FromPort: '22' ToPort: '22' CidrIp: 0.0.0.0/0 EcsSecurityGroupALBports: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref EcsSecurityGroup IpProtocol: tcp FromPort: '31000' ToPort: '61000' SourceSecurityGroupId: !Ref EcsSecurityGroup CloudwatchLogsGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Join ['-', [ECSLogGroup, !Ref AWS::StackName]] RetentionInDays: 14 ECSAutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: VPCZoneIdentifier: - !Ref PublicSubnet1 - !Ref PublicSubnet2 LaunchConfigurationName: !Ref ContainerInstances MinSize: '1' MaxSize: !Ref EcsAsgMaxSize DesiredCapacity: !Ref DesiredCapacity CreationPolicy: ResourceSignal: Timeout: PT15M UpdatePolicy: AutoScalingReplacingUpdate: WillReplace: 'true' ContainerInstances: Type: AWS::AutoScaling::LaunchConfiguration Properties: ImageId: !Ref ImageId SecurityGroups: [!Ref EcsSecurityGroup] InstanceType: !Ref InstanceType IamInstanceProfile: !Ref EC2InstanceProfile UserData: Fn::Base64: !Sub | #!/bin/bash -xe echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config echo ECS_IMAGE_PULL_BEHAVIOR=prefer-cached >> /etc/ecs/ecs.config yum install -y aws-cfn-bootstrap /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ECSAutoScalingGroup --region ${AWS::Region} EC2InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Path: / Roles: [!Ref EC2Role] EC2Role: Type: AWS::IAM::Role Properties: ManagedPolicyArns: - 'arn:aws:iam::aws:policy/CloudWatchLogsFullAccess' - 'arn:aws:iam::aws:policy/AmazonECS_FullAccess' - 'arn:aws:iam::aws:policy/AmazonS3FullAccess' AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: [ec2.amazonaws.com] Action: ['sts:AssumeRole'] Path: / Policies: - PolicyName: ecs-service PolicyDocument: Statement: - Effect: Allow Action: ['ecs:CreateCluster', 'ecs:DeregisterContainerInstance', 'ecs:DiscoverPollEndpoint', 'ecs:Poll', 'ecs:RegisterContainerInstance', 'ecs:StartTelemetrySession', 'ecs:Submit*', 'logs:CreateLogStream', 'logs:PutLogEvents', 'ecr:GetAuthorizationToken', 'ecr:BatchCheckLayerAvailability', 'ecr:BatchGetImage', 'ecr:GetDownloadUrlForLayer'] Resource: '*' Outputs: ApiURL: Description: "API endpoint URL for Prod environment" Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/recording" AutoScalingGroupName: Description: "Name of the AWS AutoScalingGroup created as part of this deployment" Value: !Ref ECSAutoScalingGroup ECSClusterName: Description: "Name of the AWS ECS cluster created as part of this deployment" Value: !Ref ECSCluster