From c9c4fd1fe355c07bdf8837839caf449321f03e1a Mon Sep 17 00:00:00 2001 From: Murat Ugur Eminoglu Date: Sun, 22 Oct 2023 21:47:02 +0300 Subject: [PATCH] Add AWS Wizar Page files with updated templates --- cloudformation/aws-streaming-wizard/index.php | 253 ++++++ .../template-custom-cert.yaml | 732 ++++++++++++++++++ .../aws-streaming-wizard/template.yaml | 679 ++++++++++++++++ 3 files changed, 1664 insertions(+) create mode 100644 cloudformation/aws-streaming-wizard/index.php create mode 100644 cloudformation/aws-streaming-wizard/template-custom-cert.yaml create mode 100644 cloudformation/aws-streaming-wizard/template.yaml diff --git a/cloudformation/aws-streaming-wizard/index.php b/cloudformation/aws-streaming-wizard/index.php new file mode 100644 index 00000000..7a8843ab --- /dev/null +++ b/cloudformation/aws-streaming-wizard/index.php @@ -0,0 +1,253 @@ + 'latest', + 'region' => $region, + 'credentials' => $credentials +]); + +$ip = $_SERVER['REMOTE_ADDR']; +$logfile = "ip_log.txt"; +$blockThreshold = 10; + +$ipLogs = file($logfile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + +$ipCount = 0; +foreach ($ipLogs as $ipLog) { + list($loggedIP, $timestamp) = explode("|", $ipLog); + if ($loggedIP == $ip && (time() - $timestamp) < 60 * 5) { + $ipCount++; + } +} + +#if ($ipCount >= $blockThreshold) { +# echo "Too many requests from your IP. Please try again later."; +# exit; +#} + +file_put_contents($logfile, "$ip|" . time() . "\n", FILE_APPEND); + + +// Handle form submission +if ($_SERVER["REQUEST_METHOD"] === "POST") { + $viewerCount = $_POST["viewerCount"]; + $publisherCount = $_POST["publisherCount"]; + + $C5_XLARGE_EDGE_LIMIT = 150; + $C5_4XLARGE_EDGE_LIMIT = $C5_XLARGE_EDGE_LIMIT*4; + $C5_9XLARGE_EDGE_LIMIT = $C5_XLARGE_EDGE_LIMIT*7; + + $C5_XLARGE_ORIGIN_LIMIT = 40; + $C5_4XLARGE_ORIGIN_LIMIT = $C5_XLARGE_ORIGIN_LIMIT*4; + $C5_9XLARGE_ORIGIN_LIMIT = $C5_XLARGE_ORIGIN_LIMIT*9; + + if (is_numeric($viewerCount)) { + if ($viewerCount >= 1 && $viewerCount <= $C5_XLARGE_EDGE_LIMIT*10) { + $edgeCount = ceil($viewerCount/$C5_XLARGE_EDGE_LIMIT); + $edgeType = "c5.xlarge"; + } + elseif ($viewerCount >= $C5_XLARGE_EDGE_LIMIT*10 + 1 && $viewerCount <= $C5_4XLARGE_EDGE_LIMIT * 10) { + $edgeCount = ceil($viewerCount/$C5_4XLARGE_EDGE_LIMIT); + $edgeType = "c5.4xlarge"; + } + elseif ($viewerCount >= $C5_4XLARGE_EDGE_LIMIT * 10 + 1) { + $edgeCount = ceil($viewerCount/$C5_9XLARGE_EDGE_LIMIT); + $edgeType = "c5.9xlarge"; + } + + } else { + echo "Please enter a numeric value"; + } + + if (is_numeric($publisherCount)) { + if ($publisherCount >= 1 && $publisherCount <= $C5_XLARGE_ORIGIN_LIMIT*3) { + $originCount = ceil($publisherCount/$C5_XLARGE_ORIGIN_LIMIT); + $originType = "c5.xlarge"; + } + elseif ($publisherCount >= $C5_XLARGE_ORIGIN_LIMIT*3 + 1 && $publisherCount <= $C5_4XLARGE_ORIGIN_LIMIT*3) { + $originCount = ceil($publisherCount/$C5_4XLARGE_ORIGIN_LIMIT); + $originType = "c5.4xlarge"; + } + elseif ($publisherCount >= $C5_4XLARGE_ORIGIN_LIMIT*3 + 1) { + $originCount = ceil($publisherCount/$C5_9XLARGE_ORIGIN_LIMIT); + $originType = "c5.9xlarge"; + } + } else { + echo "Please enter a numeric value"; + } + + // Verify reCAPTCHA v3 response + $recaptchaSecretKey = '6LfQKM8nAAAAAGCf0Yxilz97mn7WhmOZ12D3-S5X'; // Replace with your reCAPTCHA v3 secret key + $recaptchaResponse = $_POST['g-recaptcha-response']; + + // Make a POST request to Google reCAPTCHA verification endpoint + $recaptchaVerificationUrl = 'https://www.google.com/recaptcha/api/siteverify'; + $recaptchaVerificationData = [ + 'secret' => $recaptchaSecretKey, + 'response' => $recaptchaResponse + ]; + + $recaptchaVerificationOptions = [ + 'http' => [ + 'method' => 'POST', + 'header' => 'Content-Type: application/x-www-form-urlencoded', + 'content' => http_build_query($recaptchaVerificationData) + ] + ]; + + $recaptchaVerificationContext = stream_context_create($recaptchaVerificationOptions); + $recaptchaVerificationResult = file_get_contents($recaptchaVerificationUrl, false, $recaptchaVerificationContext); + + $recaptchaVerificationData = json_decode($recaptchaVerificationResult); + + if (!$recaptchaVerificationData->success) { + // reCAPTCHA v3 verification failed + echo "reCAPTCHA verification failed."; + exit; // Stop processing further + } + + +$errorMessages = array(); // Initialize an array to store error messages + +$minValue = 1000; // Minimum value (4-digit number) +$maxValue = 9999; // Maximum value (4-digit number) +$randomNumber = rand($minValue, $maxValue); +$randomDomainName = "ams-cf-".$randomNumber . ".antmedia.cloud"; + +if ($_SERVER["REQUEST_METHOD"] === "POST") { + if (isset($_POST["checkbox"])) { + // Code to run when the checkbox is checked + $output = []; + $returnCode = 0; + + // Adjust the actual command based on your requirements and paths +# sleep(10); + $command = "certbot certonly --dns-route53 --agree-tos --register-unsafely-without-email -d $randomDomainName --config-dir ./certificates --work-dir ./ --logs-dir ./logs 2>&1 >/dev/null"; +# $command = 'echo "test"'; + + // Execute Certbot command and capture output + exec($command, $output, $returnCode); + + + // Output the results (including errors) + if ($returnCode !== 0) { + $errorMessage = "Error creating certificates. Please check the error output below:"; + $errorMessages = $output; // Store error messages for display + } else { + $successMessage = "Certificates have been successfully created.\n Domain Name: $randomDomainName"; + } + + } +} + + +if (isset($_POST["checkbox"])) { + // Specify the path to the existing CloudFormation template file + $templateFile = './template-custom-cert.yaml'; + $certificateFile = "./certificates/live/$randomDomainName/cert.pem"; + $privateKeyFile = "./certificates/live/$randomDomainName/privkey.pem"; + $chainFile = "./certificates/live/$randomDomainName/chain.pem"; + + // Read the contents of the existing template file + $templateContent = file_get_contents($templateFile); + + // Replace the desired values in the template content + $updatedTemplateContent = str_replace('c5.4xlarge', $edgeType, $templateContent); + $updatedTemplateContent = str_replace('c5.2xlarge', $originType, $updatedTemplateContent); + $updatedTemplateContent = str_replace('MinSizeEdge', $edgeCount, $updatedTemplateContent); + $updatedTemplateContent = str_replace('MinSizeOrigin', $originCount, $updatedTemplateContent); + + $certificateContent = file_get_contents($certificateFile); + $privateKeyContent = file_get_contents($privateKeyFile); + $chainContent = file_get_contents($chainFile); + + // Add 8 spaces to the beginning of each line + $lines = explode("\n", $certificateContent); + $formattedCertificateContent = ''; + foreach ($lines as $line) { + $formattedCertificateContent .= str_repeat(' ', 8) . $line . "\n"; + } + + $lines = explode("\n", $privateKeyContent); + $formattedPrivateKeyContent = ''; + foreach ($lines as $line) { + $formattedPrivateKeyContent .= str_repeat(' ', 8) . $line . "\n"; + } + + $lines = explode("\n", $chainContent); + $formattedChainContent = ''; + foreach ($lines as $line) { + $formattedChainContent .= str_repeat(' ', 8) . $line . "\n"; + } + + $updatedTemplateContent = str_replace('---CertificateBody---', $formattedCertificateContent, $updatedTemplateContent); + $updatedTemplateContent = str_replace('---PrivateKey---', $formattedPrivateKeyContent, $updatedTemplateContent); + $updatedTemplateContent = str_replace('---CertificaChain---', $formattedChainContent, $updatedTemplateContent); + +// Now you can use or save the updated template content + + } +else { +// Specify the path to the existing CloudFormation template file + $templateFile = './template.yaml'; // Replace with your existing template file path + + // Read the contents of the existing template file + $templateContent = file_get_contents($templateFile); + + // Replace the desired values in the template content + $updatedTemplateContent = str_replace('c5.4xlarge', $edgeType, $templateContent); + $updatedTemplateContent = str_replace('c5.2xlarge', $originType, $updatedTemplateContent); + $updatedTemplateContent = str_replace('MinSizeEdge', $edgeCount, $updatedTemplateContent); + $updatedTemplateContent = str_replace('MinSizeOrigin', $originCount, $updatedTemplateContent); +} + +// Generate a unique filename for the modified template +$filename = 'antmedia-aws-autoscale-' . uniqid() . '.yaml'; + +// Upload the modified template file to S3 +$bucketName = 'antmedia-cf-wizard'; // Replace with your S3 bucket name +$s3Client->putObject([ + 'Bucket' => $bucketName, + 'Key' => $filename, + 'Body' => $updatedTemplateContent, +]); + +$bucketPolicy = [ + 'Version' => '2012-10-17', + 'Statement' => [ + [ + 'Sid' => 'PublicRead', + 'Effect' => 'Allow', + 'Principal' => '*', + 'Action' => 's3:GetObject', + 'Resource' => "arn:aws:s3:::{$bucketName}/*" + ] + ] +]; + +$s3Client->putBucketPolicy([ + 'Bucket' => $bucketName, + 'Policy' => json_encode($bucketPolicy) +]); + +$publicUrl = "https://{$bucketName}.s3.amazonaws.com/{$filename}"; + +// Generate a download link for the modified CloudFormation template file +$downloadLink = $s3Client->getObjectUrl($bucketName, $filename); + +// Display a download link to the user +// echo 'Download Modified CloudFormation Template'; +// echo "$publicUrl"; +} +?> diff --git a/cloudformation/aws-streaming-wizard/template-custom-cert.yaml b/cloudformation/aws-streaming-wizard/template-custom-cert.yaml new file mode 100644 index 00000000..49d68c83 --- /dev/null +++ b/cloudformation/aws-streaming-wizard/template-custom-cert.yaml @@ -0,0 +1,732 @@ +AWSTemplateFormatVersion: 2010-09-09 +Description: >- + Ant Media Server AutoScaling CloudFormation Templates. + If you have any questions, please just drop a line to contact (at) antmedia.io +Parameters: + KeyName: + Description: Name of an existing EC2 KeyPair to enable SSH access to the instances. If there is no value here, you must create an ssh key (EC2 > Key Pairs). + Type: 'AWS::EC2::KeyPair::KeyName' + MinLength: '1' + MaxLength: '255' + AllowedPattern: '[\x20-\x7E]*' + ConstraintDescription: can contain only ASCII characters. + +Resources: + DescribeImagesRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: lambda.amazonaws.com + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole + Policies: + - PolicyName: DescribeImages + PolicyDocument: + Version: '2012-10-17' + Statement: + - Action: ec2:DescribeImages + Effect: Allow + Resource: "*" + AMSGetLatestAMI: + Type: AWS::Lambda::Function + Properties: + Runtime: python3.8 + Handler: index.handler + Role: !Sub ${DescribeImagesRole.Arn} + Timeout: 60 + Code: + ZipFile: | + import boto3 + import cfnresponse + import json + import traceback + + def handler(event, context): + try: + response = boto3.client('ec2').describe_images( + Filters=[ + {'Name': 'product-code', 'Values': [event['ResourceProperties']['ProductId']]}, + {'Name': 'name', 'Values': [event['ResourceProperties']['Name']]}, + {'Name': 'architecture', 'Values': [event['ResourceProperties']['Architecture']]}, + {'Name': 'root-device-type', 'Values': ['ebs']}, + ], + ) + + amis = sorted(response['Images'], + key=lambda x: x['CreationDate'], + reverse=True) + id = amis[0]['ImageId'] + + cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, id) + except: + traceback.print_last() + cfnresponse.send(event, context, cfnresponse.FAIL, {}, "ok") + UbuntuGetLatestAMI: + Type: AWS::Lambda::Function + Properties: + Runtime: python3.11 + Handler: index.handler + Role: !Sub ${DescribeImagesRole.Arn} + Timeout: 60 + Code: + ZipFile: | + import boto3 + import cfnresponse + import json + import traceback + + def handler(event, context): + try: + response = boto3.client('ec2').describe_images( + Owners=[event['ResourceProperties']['Owner']], + Filters=[ + {'Name': 'name', 'Values': [event['ResourceProperties']['Name']]}, + {'Name': 'architecture', 'Values': [event['ResourceProperties']['Architecture']]}, + {'Name': 'root-device-type', 'Values': ['ebs']}, + ], + ) + + amis = sorted(response['Images'], + key=lambda x: x['CreationDate'], + reverse=True) + id = amis[0]['ImageId'] + + cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, id) + except: + traceback.print_last() + cfnresponse.send(event, context, cfnresponse.FAIL, {}, "ok") + ACMCertificateImportFunction: + Type: AWS::Lambda::Function + Properties: + Code: + ZipFile: | + import boto3 + import cfnresponse + + def lambda_handler(event, context): + try: + acm_client = boto3.client('acm') + response = acm_client.import_certificate( + Certificate=event['ResourceProperties']['CertificateBody'], + PrivateKey=event['ResourceProperties']['PrivateKey'], + CertificateChain=event['ResourceProperties']['CertificateChain'] + ) + certificate_arn = response['CertificateArn'] + cfnresponse.send(event, context, cfnresponse.SUCCESS, {'CertificateArn': certificate_arn}) + except Exception as e: + print("Error:", e) + cfnresponse.send(event, context, cfnresponse.FAILED, {}) + + Handler: index.lambda_handler + Role: !Sub '${AcmCertificateImportLambdaExecutionRole.Arn}' + Runtime: python3.11 + AcmCertificateImportLambdaExecutionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: ['sts:AssumeRole'] + ManagedPolicyArns: [!Sub 'arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'] + Policies: + - PolicyName: main + PolicyDocument: + Version: '2012-10-17' + Statement: + - Sid: Acm + Effect: Allow + Action: + - 'acm:AddTagsToCertificate' + - 'acm:ImportCertificate' + Resource: '*' + + CertificateImportCustomResource: + Type: Custom::ACMCertificateImport + Properties: + ServiceToken: !GetAtt ACMCertificateImportFunction.Arn + CertificateBody: | +---CertificateBody--- + PrivateKey: | +---PrivateKey--- + CertificateChain: | +---CertificaChain--- + AntMediaAmi: + Type: Custom::FindAMI + Properties: + ServiceToken: !Sub ${AMSGetLatestAMI.Arn} + ProductId: "4wh7rhpic3wfwamyp5905tsbt" + Name: "AntMedia-AWS-Marketplace-EE-*" + Architecture: "x86_64" + + UbuntuAmi: + Type: Custom::FindAMI + Properties: + ServiceToken: !Sub ${UbuntuGetLatestAMI.Arn} + Owner: "099720109477" + Name: "ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*" + Architecture: "x86_64" + + AntMediaVPC: + Type: AWS::EC2::VPC + Properties: + CidrBlock: 10.0.0.0/16 + EnableDnsHostnames: true + EnableDnsSupport: true + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-AntMedia-VPC + + OriginZone: + Type: AWS::EC2::Subnet + DependsOn: AntMediaVPC + Properties: + VpcId: !Ref AntMediaVPC + CidrBlock: 10.0.1.0/24 + MapPublicIpOnLaunch: true + AvailabilityZone: + Fn::Select: + - 0 + - Fn::GetAZs: "" + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-AntMedia-Origin-Subnet + + EdgeZone: + Type: AWS::EC2::Subnet + DependsOn: AntMediaVPC + Properties: + VpcId: !Ref AntMediaVPC + CidrBlock: 10.0.2.0/24 + MapPublicIpOnLaunch: true + AvailabilityZone: + Fn::Select: + - 1 + - Fn::GetAZs: "" + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-AntMedia-Edge-Subnet + + DefaultGateway: + Type: AWS::EC2::InternetGateway + + InternetGatewayAttachment: + Type: AWS::EC2::VPCGatewayAttachment + Properties: + InternetGatewayId: !Ref DefaultGateway + VpcId: !Ref AntMediaVPC + + RouteTable: + Type: AWS::EC2::RouteTable + Properties: + VpcId: !Ref AntMediaVPC + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-AntMedia-Route-Table + + DefaultRoute: + Type: AWS::EC2::Route + DependsOn: InternetGatewayAttachment + Properties: + RouteTableId: !Ref RouteTable + GatewayId: !Ref DefaultGateway + DestinationCidrBlock: 0.0.0.0/0 + + SubnetRouteTableAssociationOrigin: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref RouteTable + SubnetId: !Ref OriginZone + + SubnetRouteTableAssociationEdge: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref RouteTable + SubnetId: !Ref EdgeZone + + RTMPLoadBalancer: + Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer' + Properties: + Subnets: + - !Ref OriginZone + Type: 'network' + RTMPListener: + Type: 'AWS::ElasticLoadBalancingV2::Listener' + Properties: + DefaultActions: + - Type: forward + TargetGroupArn: !Ref RTMPTargetGroup + LoadBalancerArn: !Ref RTMPLoadBalancer + Port: '1935' + Protocol: TCP + RTMPTargetGroup: + Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' + Properties: + HealthCheckIntervalSeconds: 30 + HealthyThresholdCount: 3 + Port: 1935 + Protocol: TCP + UnhealthyThresholdCount: 3 + VpcId: !Ref AntMediaVPC + RTMPSecurityGroup: + Type: 'AWS::EC2::SecurityGroup' + Properties: + GroupDescription: 'Ant Media Server RTMP Load Balancer Security Group' + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: '1935' + ToPort: '1935' + CidrIp: '0.0.0.0/0' + SecurityGroupEgress: + - IpProtocol: tcp + FromPort: 0 + ToPort: 65535 + CidrIp: '0.0.0.0/0' + VpcId: !Ref AntMediaVPC + + OriginGroup: + Type: 'AWS::AutoScaling::AutoScalingGroup' + DependsOn: + - LaunchTemplateOrigin + Properties: + VPCZoneIdentifier: + - !Ref OriginZone + LaunchTemplate: + LaunchTemplateName: !Sub ${AWS::StackName}-AntMedia-LaunchTemplateOrigin + Version: !GetAtt 'LaunchTemplateOrigin.LatestVersionNumber' + MinSize: MinSizeOrigin + MaxSize: 100 + DesiredCapacity: MinSizeOrigin + TargetGroupARNs: + - !Ref ALBTargetGroupOrigin + - !Ref RTMPTargetGroup + Tags: + - Key: Name + Value: Antmedia-Origin + PropagateAtLaunch: 'true' + CreationPolicy: + ResourceSignal: + Timeout: PT15M + Count: MinSizeOrigin + UpdatePolicy: + AutoScalingRollingUpdate: + MinInstancesInService: '1' + MaxBatchSize: '1' + PauseTime: PT15M + WaitOnResourceSignals: 'true' + NotificationConfiguration: + TopicARN: !Ref NotificationTopic + NotificationTypes: + - 'autoscaling:EC2_INSTANCE_LAUNCH' + - 'autoscaling:EC2_INSTANCE_LAUNCH_ERROR' + - 'autoscaling:EC2_INSTANCE_TERMINATE' + - 'autoscaling:EC2_INSTANCE_TERMINATE_ERROR' + + LaunchTemplateOrigin: + Type: 'AWS::EC2::LaunchTemplate' + Properties: + LaunchTemplateName: !Sub ${AWS::StackName}-AntMedia-LaunchTemplateOrigin + LaunchTemplateData: + InstanceType: c5.2xlarge + KeyName: !Ref KeyName + ImageId: !Ref AntMediaAmi + SecurityGroupIds: + - !GetAtt "InstanceSecurityGroup.GroupId" + BlockDeviceMappings: + - DeviceName: /dev/sda1 + Ebs: + VolumeSize: 10 + VolumeType: gp2 + DeleteOnTermination: true + UserData: + Fn::Base64: !Sub | + #!/bin/bash + touch /usr/local/antmedia/conf/initialized + bash /usr/local/antmedia/change_server_mode.sh cluster ${DBInstance.PrivateIp} + apt-get update + apt-get install -y python3-pip + apt-get install -y python3-setuptools + mkdir -p /opt/aws/bin + wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz + python3 -m easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-py3-latest.tar.gz + /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource OriginGroup --region ${AWS::Region} + TagSpecifications: + - ResourceType: instance + Tags: + - Key: Name + Value: OriginInstance + TagSpecifications: + - ResourceType: launch-template + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-AntMedia-LaunchTemplateOrigin + + EdgeGroup: + Type: 'AWS::AutoScaling::AutoScalingGroup' + DependsOn: + - LaunchTemplateEdge + Properties: + VPCZoneIdentifier: + - !Ref EdgeZone + LaunchTemplate: + LaunchTemplateName: !Sub ${AWS::StackName}-AntMedia-LaunchTemplateEdge + Version: !GetAtt 'LaunchTemplateEdge.LatestVersionNumber' + MinSize: MinSizeEdge + MaxSize: 100 + DesiredCapacity: MinSizeEdge + TargetGroupARNs: + - !Ref ALBTargetGroupEdge + Tags: + - Key: Name + Value: Antmedia-Edge + PropagateAtLaunch: 'true' + CreationPolicy: + ResourceSignal: + Timeout: PT15M + Count: MinSizeEdge + UpdatePolicy: + AutoScalingRollingUpdate: + MinInstancesInService: '1' + MaxBatchSize: '1' + PauseTime: PT15M + WaitOnResourceSignals: 'true' + NotificationConfiguration: + TopicARN: !Ref NotificationTopic + NotificationTypes: + - 'autoscaling:EC2_INSTANCE_LAUNCH' + - 'autoscaling:EC2_INSTANCE_LAUNCH_ERROR' + - 'autoscaling:EC2_INSTANCE_TERMINATE' + - 'autoscaling:EC2_INSTANCE_TERMINATE_ERROR' + + LaunchTemplateEdge: + Type: 'AWS::EC2::LaunchTemplate' + Properties: + LaunchTemplateName: !Sub ${AWS::StackName}-AntMedia-LaunchTemplateEdge + LaunchTemplateData: + InstanceType: c5.4xlarge + KeyName: !Ref KeyName + ImageId: !Ref AntMediaAmi + SecurityGroupIds: + - !GetAtt "InstanceSecurityGroup.GroupId" + BlockDeviceMappings: + - DeviceName: /dev/sda1 + Ebs: + VolumeSize: !Ref DiskSize + VolumeType: gp2 + DeleteOnTermination: true + UserData: + Fn::Base64: !Sub | + #!/bin/bash + touch /usr/local/antmedia/conf/initialized + bash /usr/local/antmedia/change_server_mode.sh cluster ${DBInstance.PrivateIp} + apt-get update + apt-get install -y python3-pip + apt-get install -y python3-setuptools + mkdir -p /opt/aws/bin + wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz + python3 -m easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-py3-latest.tar.gz + /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource EdgeGroup --region ${AWS::Region} + TagSpecifications: + - ResourceType: instance + Tags: + - Key: Name + Value: EdgeInstance + TagSpecifications: + - ResourceType: launch-template + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-AntMedia-LaunchTemplateEdge + + ELBSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Allows access + VpcId: !Ref AntMediaVPC + SecurityGroupIngress: + - CidrIp: 0.0.0.0/0 + IpProtocol: tcp + FromPort: 80 + ToPort: 80 + Description: Allow 80. Port for Origin Instances + - CidrIp: 0.0.0.0/0 + IpProtocol: tcp + FromPort: 443 + ToPort: 443 + Description: Allow 443. Port for Origin Instances + - CidrIp: 0.0.0.0/0 + IpProtocol: tcp + FromPort: 5080 + ToPort: 5080 + Description: Allow 5080. Port for Edge Instances + - CidrIp: 0.0.0.0/0 + IpProtocol: tcp + FromPort: 5443 + ToPort: 5443 + Description: Allow 5443. Port for Edge Instances + + ApplicationLoadBalancer: + Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer' + DependsOn: + - DBInstance + Properties: + Subnets: + - !Ref OriginZone + - !Ref EdgeZone + SecurityGroups: + - !GetAtt [ ELBSecurityGroup, GroupId ] + ALBListener443: + Type: 'AWS::ElasticLoadBalancingV2::Listener' + Properties: + Certificates: + - CertificateArn: !GetAtt CertificateImportCustomResource.CertificateArn + DefaultActions: + - Type: forward + TargetGroupArn: !Ref ALBTargetGroupOrigin + LoadBalancerArn: !Ref ApplicationLoadBalancer + Port: '443' + Protocol: HTTPS + ALBListener5443: + Type: 'AWS::ElasticLoadBalancingV2::Listener' + Properties: + Certificates: + - CertificateArn: !GetAtt CertificateImportCustomResource.CertificateArn + DefaultActions: + - Type: forward + TargetGroupArn: !Ref ALBTargetGroupEdge + LoadBalancerArn: !Ref ApplicationLoadBalancer + Port: '5443' + Protocol: HTTPS + ALBListener5080: + Type: 'AWS::ElasticLoadBalancingV2::Listener' + Properties: + DefaultActions: + - Type: forward + TargetGroupArn: !Ref ALBTargetGroupEdge + LoadBalancerArn: !Ref ApplicationLoadBalancer + Port: '5080' + Protocol: HTTP + ALBListener80: + Type: 'AWS::ElasticLoadBalancingV2::Listener' + Properties: + DefaultActions: + - Type: forward + TargetGroupArn: !Ref ALBTargetGroupOrigin + LoadBalancerArn: !Ref ApplicationLoadBalancer + Port: '80' + Protocol: HTTP + ALBTargetGroupOrigin: + Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' + DependsOn: + - DBInstance + Properties: + HealthCheckIntervalSeconds: 30 + HealthCheckTimeoutSeconds: 5 + HealthyThresholdCount: 3 + Port: 5080 + Protocol: HTTP + UnhealthyThresholdCount: 5 + VpcId: !Ref AntMediaVPC + TargetGroupAttributes: + - Key: stickiness.enabled + Value: 'true' + - Key: stickiness.type + Value: lb_cookie + - Key: stickiness.lb_cookie.duration_seconds + Value: '30' + - Key: load_balancing.algorithm.type + Value: least_outstanding_requests + ALBTargetGroupEdge: + Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' + DependsOn: + - DBInstance + Properties: + HealthCheckIntervalSeconds: 30 + HealthCheckTimeoutSeconds: 5 + HealthyThresholdCount: 3 + Port: 5080 + Protocol: HTTP + UnhealthyThresholdCount: 5 + VpcId: !Ref AntMediaVPC + TargetGroupAttributes: + - Key: stickiness.enabled + Value: 'true' + - Key: stickiness.type + Value: lb_cookie + - Key: stickiness.lb_cookie.duration_seconds + Value: '30' + - Key: load_balancing.algorithm.type + Value: least_outstanding_requests + OriginRule: + Type: 'AWS::ElasticLoadBalancingV2::ListenerRule' + Properties: + Actions: + - Type: forward + TargetGroupArn: !Ref ALBTargetGroupOrigin + Conditions: + - Field: query-string + QueryStringConfig: + Values: + - Key: target + Value: origin + ListenerArn: !Ref ALBListener443 + Priority: 1 + EdgeRule: + Type: 'AWS::ElasticLoadBalancingV2::ListenerRule' + Properties: + Actions: + - Type: forward + TargetGroupArn: !Ref ALBTargetGroupEdge + Conditions: + - Field: query-string + QueryStringConfig: + Values: + - Key: target + Value: edge + ListenerArn: !Ref ALBListener443 + Priority: 2 + InstanceSecurityGroup: + Type: 'AWS::EC2::SecurityGroup' + Properties: + GroupDescription: Enable SSH access and HTTP access on the configured port + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: '22' + ToPort: '22' + CidrIp: 0.0.0.0/0 + - IpProtocol: tcp + FromPort: '5080' + ToPort: '5080' + CidrIp: 10.0.0.0/16 + - IpProtocol: tcp + FromPort: '1935' + ToPort: '1935' + CidrIp: 0.0.0.0/0 + - IpProtocol: udp + FromPort: '50000' + ToPort: '60000' + CidrIp: 0.0.0.0/0 + - IpProtocol: tcp + FromPort: '5000' + ToPort: '5000' + CidrIp: 10.0.0.0/16 + VpcId: !Ref AntMediaVPC + + OriginCPUPolicy: + Type: AWS::AutoScaling::ScalingPolicy + Properties: + AutoScalingGroupName: !Ref OriginGroup + PolicyType: TargetTrackingScaling + TargetTrackingConfiguration: + PredefinedMetricSpecification: + PredefinedMetricType: ASGAverageCPUUtilization + TargetValue: 60.0 + + EdgeCPUPolicy: + Type: AWS::AutoScaling::ScalingPolicy + Properties: + AutoScalingGroupName: !Ref EdgeGroup + PolicyType: TargetTrackingScaling + TargetTrackingConfiguration: + PredefinedMetricSpecification: + PredefinedMetricType: ASGAverageCPUUtilization + TargetValue: 60.0 + + DBEC2SecurityGroup: + Type: 'AWS::EC2::SecurityGroup' + Properties: + VpcId: !Ref AntMediaVPC + GroupDescription: MongoDB SecurityGroup + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: '27017' + ToPort: '27017' + CidrIp: 10.0.0.0/16 + - IpProtocol: tcp + FromPort: '22' + ToPort: '22' + CidrIp: 0.0.0.0/0 + DBInstance: + Type: 'AWS::EC2::Instance' + DependsOn: + - AMSGetLatestAMI + - UbuntuAmi + - DescribeImagesRole + Properties: + KeyName: !Ref KeyName + ImageId: !Ref UbuntuAmi + InstanceType: c5.xlarge + SubnetId: !Ref OriginZone + SecurityGroupIds: + - !GetAtt "DBEC2SecurityGroup.GroupId" + Tags: + - Key: Name + Value: Antmedia-MongoDB + UserData: + Fn::Base64: + !Sub | + #!/bin/bash -xe + wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add - + echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list + sudo apt-get update + sudo apt-get install -y mongodb-org python3-pip python3-setuptools + sed -i 's/127.0.0.1/0.0.0.0/g' /etc/mongod.conf + systemctl enable mongod + systemctl restart mongod + +Outputs: + + OriginHTTPS: + Description: HTTPS URL of the Ant Media Origin Servers + Value: !Join + - '' + - - 'https://' + - !GetAtt + - ApplicationLoadBalancer + - DNSName + + EdgeHTTPS: + Description: HTTPS URL of the Ant Media Edge Servers + Value: !Join + - '' + - - 'https://' + - !GetAtt + - ApplicationLoadBalancer + - DNSName + - ':5443' + + OriginHTTP: + Description: HTTP URL of the Ant Media Origin Servers + Value: !Join + - '' + - - 'http://' + - !GetAtt + - ApplicationLoadBalancer + - DNSName + + EdgeHTTP: + Description: HTTP URL of the Ant Media Edge Servers + Value: !Join + - '' + - - 'http://' + - !GetAtt + - ApplicationLoadBalancer + - DNSName + - ':5080' + + RTMP: + Description: RTMP URL of the Ant Media Server + Value: !Join + - '' + - - 'rtmp://' + - !GetAtt + - RTMPLoadBalancer + - DNSName + + diff --git a/cloudformation/aws-streaming-wizard/template.yaml b/cloudformation/aws-streaming-wizard/template.yaml new file mode 100644 index 00000000..59e397a0 --- /dev/null +++ b/cloudformation/aws-streaming-wizard/template.yaml @@ -0,0 +1,679 @@ +AWSTemplateFormatVersion: 2010-09-09 +Description: >- + Ant Media Server AutoScaling CloudFormation Templates. + If you have any questions, please just drop a line to contact (at) antmedia.io +Parameters: + KeyName: + Description: Name of an existing EC2 KeyPair to enable SSH access to the instances. If there is no value here, you must create an ssh key (EC2 > Key Pairs). + Type: 'AWS::EC2::KeyPair::KeyName' + MinLength: '1' + MaxLength: '255' + AllowedPattern: '[\x20-\x7E]*' + ConstraintDescription: can contain only ASCII characters. + LoadBalancerCertificateArn: + Description: 'Amazon Resource Name (ARN) of the certificate to associate with the load balancer. If you do not have the SSL certificate, please check this guide: https://antmedia.io/ant-media-server-cloudformation-installation/ ' + Type: String + Default: '' + +Resources: + DescribeImagesRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: lambda.amazonaws.com + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole + Policies: + - PolicyName: DescribeImages + PolicyDocument: + Version: '2012-10-17' + Statement: + - Action: ec2:DescribeImages + Effect: Allow + Resource: "*" + AMSGetLatestAMI: + Type: AWS::Lambda::Function + Properties: + Runtime: python3.11 + Handler: index.handler + Role: !Sub ${DescribeImagesRole.Arn} + Timeout: 60 + Code: + ZipFile: | + import boto3 + import cfnresponse + import json + import traceback + + def handler(event, context): + try: + response = boto3.client('ec2').describe_images( + Filters=[ + {'Name': 'product-code', 'Values': [event['ResourceProperties']['ProductId']]}, + {'Name': 'name', 'Values': [event['ResourceProperties']['Name']]}, + {'Name': 'architecture', 'Values': [event['ResourceProperties']['Architecture']]}, + {'Name': 'root-device-type', 'Values': ['ebs']}, + ], + ) + + amis = sorted(response['Images'], + key=lambda x: x['CreationDate'], + reverse=True) + id = amis[0]['ImageId'] + + cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, id) + except: + traceback.print_last() + cfnresponse.send(event, context, cfnresponse.FAIL, {}, "ok") + UbuntuGetLatestAMI: + Type: AWS::Lambda::Function + Properties: + Runtime: python3.11 + Handler: index.handler + Role: !Sub ${DescribeImagesRole.Arn} + Timeout: 60 + Code: + ZipFile: | + import boto3 + import cfnresponse + import json + import traceback + + def handler(event, context): + try: + response = boto3.client('ec2').describe_images( + Owners=[event['ResourceProperties']['Owner']], + Filters=[ + {'Name': 'name', 'Values': [event['ResourceProperties']['Name']]}, + {'Name': 'architecture', 'Values': [event['ResourceProperties']['Architecture']]}, + {'Name': 'root-device-type', 'Values': ['ebs']}, + ], + ) + + amis = sorted(response['Images'], + key=lambda x: x['CreationDate'], + reverse=True) + id = amis[0]['ImageId'] + + cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, id) + except: + traceback.print_last() + cfnresponse.send(event, context, cfnresponse.FAIL, {}, "ok") + + AntMediaAmi: + Type: Custom::FindAMI + Properties: + ServiceToken: !Sub ${AMSGetLatestAMI.Arn} + ProductId: "4wh7rhpic3wfwamyp5905tsbt" + Name: "AntMedia-AWS-Marketplace-EE-*" + Architecture: "x86_64" + + UbuntuAmi: + Type: Custom::FindAMI + Properties: + ServiceToken: !Sub ${UbuntuGetLatestAMI.Arn} + Owner: "099720109477" + Name: "ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*" + Architecture: "x86_64" + + AntMediaVPC: + Type: AWS::EC2::VPC + Properties: + CidrBlock: 10.0.0.0/16 + EnableDnsHostnames: true + EnableDnsSupport: true + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-AntMedia-VPC + + OriginZone: + Type: AWS::EC2::Subnet + DependsOn: AntMediaVPC + Properties: + VpcId: !Ref AntMediaVPC + CidrBlock: 10.0.1.0/24 + MapPublicIpOnLaunch: true + AvailabilityZone: + Fn::Select: + - 0 + - Fn::GetAZs: "" + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-AntMedia-Origin-Subnet + + EdgeZone: + Type: AWS::EC2::Subnet + DependsOn: AntMediaVPC + Properties: + VpcId: !Ref AntMediaVPC + CidrBlock: 10.0.2.0/24 + MapPublicIpOnLaunch: true + AvailabilityZone: + Fn::Select: + - 1 + - Fn::GetAZs: "" + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-AntMedia-Edge-Subnet + + DefaultGateway: + Type: AWS::EC2::InternetGateway + + InternetGatewayAttachment: + Type: AWS::EC2::VPCGatewayAttachment + Properties: + InternetGatewayId: !Ref DefaultGateway + VpcId: !Ref AntMediaVPC + + RouteTable: + Type: AWS::EC2::RouteTable + Properties: + VpcId: !Ref AntMediaVPC + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-AntMedia-Route-Table + + DefaultRoute: + Type: AWS::EC2::Route + DependsOn: InternetGatewayAttachment + Properties: + RouteTableId: !Ref RouteTable + GatewayId: !Ref DefaultGateway + DestinationCidrBlock: 0.0.0.0/0 + + SubnetRouteTableAssociationOrigin: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref RouteTable + SubnetId: !Ref OriginZone + + SubnetRouteTableAssociationEdge: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref RouteTable + SubnetId: !Ref EdgeZone + + RTMPLoadBalancer: + Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer' + Properties: + Subnets: + - !Ref OriginZone + Type: 'network' + RTMPListener: + Type: 'AWS::ElasticLoadBalancingV2::Listener' + Properties: + DefaultActions: + - Type: forward + TargetGroupArn: !Ref RTMPTargetGroup + LoadBalancerArn: !Ref RTMPLoadBalancer + Port: '1935' + Protocol: TCP + RTMPTargetGroup: + Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' + Properties: + HealthCheckIntervalSeconds: 30 + HealthyThresholdCount: 3 + Port: 1935 + Protocol: TCP + UnhealthyThresholdCount: 3 + VpcId: !Ref AntMediaVPC + RTMPSecurityGroup: + Type: 'AWS::EC2::SecurityGroup' + Properties: + GroupDescription: 'Ant Media Server RTMP Load Balancer Security Group' + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: '1935' + ToPort: '1935' + CidrIp: '0.0.0.0/0' + SecurityGroupEgress: + - IpProtocol: tcp + FromPort: 0 + ToPort: 65535 + CidrIp: '0.0.0.0/0' + VpcId: !Ref AntMediaVPC + + OriginGroup: + Type: 'AWS::AutoScaling::AutoScalingGroup' + DependsOn: + - LaunchTemplateOrigin + Properties: + VPCZoneIdentifier: + - !Ref OriginZone + LaunchTemplate: + LaunchTemplateName: !Sub ${AWS::StackName}-AntMedia-LaunchTemplateOrigin + Version: !GetAtt 'LaunchTemplateOrigin.LatestVersionNumber' + MinSize: MinSizeOrigin + MaxSize: 100 + DesiredCapacity: MinSizeOrigin + TargetGroupARNs: + - !Ref ALBTargetGroupOrigin + - !Ref RTMPTargetGroup + Tags: + - Key: Name + Value: Antmedia-Origin + PropagateAtLaunch: 'true' + CreationPolicy: + ResourceSignal: + Timeout: PT15M + Count: MinSizeOrigin + UpdatePolicy: + AutoScalingRollingUpdate: + MinInstancesInService: '1' + MaxBatchSize: '1' + PauseTime: PT15M + WaitOnResourceSignals: 'true' + NotificationConfiguration: + TopicARN: !Ref NotificationTopic + NotificationTypes: + - 'autoscaling:EC2_INSTANCE_LAUNCH' + - 'autoscaling:EC2_INSTANCE_LAUNCH_ERROR' + - 'autoscaling:EC2_INSTANCE_TERMINATE' + - 'autoscaling:EC2_INSTANCE_TERMINATE_ERROR' + + LaunchTemplateOrigin: + Type: 'AWS::EC2::LaunchTemplate' + Properties: + LaunchTemplateName: !Sub ${AWS::StackName}-AntMedia-LaunchTemplateOrigin + LaunchTemplateData: + InstanceType: c5.2xlarge + KeyName: !Ref KeyName + ImageId: !Ref AntMediaAmi + SecurityGroupIds: + - !GetAtt "InstanceSecurityGroup.GroupId" + BlockDeviceMappings: + - DeviceName: /dev/sda1 + Ebs: + VolumeSize: 10 + VolumeType: gp2 + DeleteOnTermination: true + UserData: + Fn::Base64: !Sub | + #!/bin/bash + touch /usr/local/antmedia/conf/initialized + bash /usr/local/antmedia/change_server_mode.sh cluster ${DBInstance.PrivateIp} + apt-get update + apt-get install -y python3-pip + apt-get install -y python3-setuptools + mkdir -p /opt/aws/bin + wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz + python3 -m easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-py3-latest.tar.gz + /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource OriginGroup --region ${AWS::Region} + TagSpecifications: + - ResourceType: instance + Tags: + - Key: Name + Value: OriginInstance + TagSpecifications: + - ResourceType: launch-template + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-AntMedia-LaunchTemplateOrigin + + EdgeGroup: + Type: 'AWS::AutoScaling::AutoScalingGroup' + DependsOn: + - LaunchTemplateEdge + Properties: + VPCZoneIdentifier: + - !Ref EdgeZone + LaunchTemplate: + LaunchTemplateName: !Sub ${AWS::StackName}-AntMedia-LaunchTemplateEdge + Version: !GetAtt 'LaunchTemplateEdge.LatestVersionNumber' + MinSize: MinSizeEdge + MaxSize: 100 + DesiredCapacity: MinSizeEdge + TargetGroupARNs: + - !Ref ALBTargetGroupEdge + Tags: + - Key: Name + Value: Antmedia-Edge + PropagateAtLaunch: 'true' + CreationPolicy: + ResourceSignal: + Timeout: PT15M + Count: MinSizeEdge + UpdatePolicy: + AutoScalingRollingUpdate: + MinInstancesInService: '1' + MaxBatchSize: '1' + PauseTime: PT15M + WaitOnResourceSignals: 'true' + NotificationConfiguration: + TopicARN: !Ref NotificationTopic + NotificationTypes: + - 'autoscaling:EC2_INSTANCE_LAUNCH' + - 'autoscaling:EC2_INSTANCE_LAUNCH_ERROR' + - 'autoscaling:EC2_INSTANCE_TERMINATE' + - 'autoscaling:EC2_INSTANCE_TERMINATE_ERROR' + + LaunchTemplateEdge: + Type: 'AWS::EC2::LaunchTemplate' + Properties: + LaunchTemplateName: !Sub ${AWS::StackName}-AntMedia-LaunchTemplateEdge + LaunchTemplateData: + InstanceType: c5.4xlarge + KeyName: !Ref KeyName + ImageId: !Ref AntMediaAmi + SecurityGroupIds: + - !GetAtt "InstanceSecurityGroup.GroupId" + BlockDeviceMappings: + - DeviceName: /dev/sda1 + Ebs: + VolumeSize: !Ref DiskSize + VolumeType: gp2 + DeleteOnTermination: true + UserData: + Fn::Base64: !Sub | + #!/bin/bash + touch /usr/local/antmedia/conf/initialized + bash /usr/local/antmedia/change_server_mode.sh cluster ${DBInstance.PrivateIp} + apt-get update + apt-get install -y python3-pip + apt-get install -y python3-setuptools + mkdir -p /opt/aws/bin + wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz + python3 -m easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-py3-latest.tar.gz + /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource EdgeGroup --region ${AWS::Region} + TagSpecifications: + - ResourceType: instance + Tags: + - Key: Name + Value: EdgeInstance + TagSpecifications: + - ResourceType: launch-template + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-AntMedia-LaunchTemplateEdge + + ELBSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Allows access + VpcId: !Ref AntMediaVPC + SecurityGroupIngress: + - CidrIp: 0.0.0.0/0 + IpProtocol: tcp + FromPort: 80 + ToPort: 80 + Description: Allow 80. Port for Origin Instances + - CidrIp: 0.0.0.0/0 + IpProtocol: tcp + FromPort: 443 + ToPort: 443 + Description: Allow 443. Port for Origin Instances + - CidrIp: 0.0.0.0/0 + IpProtocol: tcp + FromPort: 5080 + ToPort: 5080 + Description: Allow 5080. Port for Edge Instances + - CidrIp: 0.0.0.0/0 + IpProtocol: tcp + FromPort: 5443 + ToPort: 5443 + Description: Allow 5443. Port for Edge Instances + + ApplicationLoadBalancer: + Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer' + DependsOn: + - DBInstance + Properties: + Subnets: + - !Ref OriginZone + - !Ref EdgeZone + SecurityGroups: + - !GetAtt [ ELBSecurityGroup, GroupId ] + ALBListener443: + Type: 'AWS::ElasticLoadBalancingV2::Listener' + Properties: + Certificates: + - CertificateArn: !Ref LoadBalancerCertificateArn + DefaultActions: + - Type: forward + TargetGroupArn: !Ref ALBTargetGroupOrigin + LoadBalancerArn: !Ref ApplicationLoadBalancer + Port: '443' + Protocol: HTTPS + ALBListener5443: + Type: 'AWS::ElasticLoadBalancingV2::Listener' + Properties: + Certificates: + - CertificateArn: !Ref LoadBalancerCertificateArn + DefaultActions: + - Type: forward + TargetGroupArn: !Ref ALBTargetGroupEdge + LoadBalancerArn: !Ref ApplicationLoadBalancer + Port: '5443' + Protocol: HTTPS + ALBListener5080: + Type: 'AWS::ElasticLoadBalancingV2::Listener' + Properties: + DefaultActions: + - Type: forward + TargetGroupArn: !Ref ALBTargetGroupEdge + LoadBalancerArn: !Ref ApplicationLoadBalancer + Port: '5080' + Protocol: HTTP + ALBListener80: + Type: 'AWS::ElasticLoadBalancingV2::Listener' + Properties: + DefaultActions: + - Type: forward + TargetGroupArn: !Ref ALBTargetGroupOrigin + LoadBalancerArn: !Ref ApplicationLoadBalancer + Port: '80' + Protocol: HTTP + ALBTargetGroupOrigin: + Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' + DependsOn: + - DBInstance + Properties: + HealthCheckIntervalSeconds: 30 + HealthCheckTimeoutSeconds: 5 + HealthyThresholdCount: 3 + Port: 5080 + Protocol: HTTP + UnhealthyThresholdCount: 5 + VpcId: !Ref AntMediaVPC + TargetGroupAttributes: + - Key: stickiness.enabled + Value: 'true' + - Key: stickiness.type + Value: lb_cookie + - Key: stickiness.lb_cookie.duration_seconds + Value: '30' + - Key: load_balancing.algorithm.type + Value: least_outstanding_requests + ALBTargetGroupEdge: + Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' + DependsOn: + - DBInstance + Properties: + HealthCheckIntervalSeconds: 30 + HealthCheckTimeoutSeconds: 5 + HealthyThresholdCount: 3 + Port: 5080 + Protocol: HTTP + UnhealthyThresholdCount: 5 + VpcId: !Ref AntMediaVPC + TargetGroupAttributes: + - Key: stickiness.enabled + Value: 'true' + - Key: stickiness.type + Value: lb_cookie + - Key: stickiness.lb_cookie.duration_seconds + Value: '30' + - Key: load_balancing.algorithm.type + Value: least_outstanding_requests + OriginRule: + Type: 'AWS::ElasticLoadBalancingV2::ListenerRule' + Properties: + Actions: + - Type: forward + TargetGroupArn: !Ref ALBTargetGroupOrigin + Conditions: + - Field: query-string + QueryStringConfig: + Values: + - Key: target + Value: origin + ListenerArn: !Ref ALBListener443 + Priority: 1 + EdgeRule: + Type: 'AWS::ElasticLoadBalancingV2::ListenerRule' + Properties: + Actions: + - Type: forward + TargetGroupArn: !Ref ALBTargetGroupEdge + Conditions: + - Field: query-string + QueryStringConfig: + Values: + - Key: target + Value: edge + ListenerArn: !Ref ALBListener443 + Priority: 2 + InstanceSecurityGroup: + Type: 'AWS::EC2::SecurityGroup' + Properties: + GroupDescription: Enable SSH access and HTTP access on the configured port + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: '22' + ToPort: '22' + CidrIp: 0.0.0.0/0 + - IpProtocol: tcp + FromPort: '5080' + ToPort: '5080' + CidrIp: 10.0.0.0/16 + - IpProtocol: tcp + FromPort: '1935' + ToPort: '1935' + CidrIp: 0.0.0.0/0 + - IpProtocol: udp + FromPort: '50000' + ToPort: '60000' + CidrIp: 0.0.0.0/0 + - IpProtocol: tcp + FromPort: '5000' + ToPort: '5000' + CidrIp: 10.0.0.0/16 + VpcId: !Ref AntMediaVPC + + OriginCPUPolicy: + Type: AWS::AutoScaling::ScalingPolicy + Properties: + AutoScalingGroupName: !Ref OriginGroup + PolicyType: TargetTrackingScaling + TargetTrackingConfiguration: + PredefinedMetricSpecification: + PredefinedMetricType: ASGAverageCPUUtilization + TargetValue: 60.0 + + EdgeCPUPolicy: + Type: AWS::AutoScaling::ScalingPolicy + Properties: + AutoScalingGroupName: !Ref EdgeGroup + PolicyType: TargetTrackingScaling + TargetTrackingConfiguration: + PredefinedMetricSpecification: + PredefinedMetricType: ASGAverageCPUUtilization + TargetValue: 60.0 + + DBEC2SecurityGroup: + Type: 'AWS::EC2::SecurityGroup' + Properties: + VpcId: !Ref AntMediaVPC + GroupDescription: MongoDB SecurityGroup + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: '27017' + ToPort: '27017' + CidrIp: 10.0.0.0/16 + - IpProtocol: tcp + FromPort: '22' + ToPort: '22' + CidrIp: 0.0.0.0/0 + DBInstance: + Type: 'AWS::EC2::Instance' + DependsOn: + - AMSGetLatestAMI + - UbuntuAmi + - DescribeImagesRole + Properties: + KeyName: !Ref KeyName + ImageId: !Ref UbuntuAmi + InstanceType: c5.xlarge + SubnetId: !Ref OriginZone + SecurityGroupIds: + - !GetAtt "DBEC2SecurityGroup.GroupId" + Tags: + - Key: Name + Value: Antmedia-MongoDB + UserData: + Fn::Base64: + !Sub | + #!/bin/bash -xe + wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add - + echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list + sudo apt-get update + sudo apt-get install -y mongodb-org python3-pip python3-setuptools + sed -i 's/127.0.0.1/0.0.0.0/g' /etc/mongod.conf + systemctl enable mongod + systemctl restart mongod + +Outputs: + + OriginHTTPS: + Description: HTTPS URL of the Ant Media Origin Servers + Value: !Join + - '' + - - 'https://' + - !GetAtt + - ApplicationLoadBalancer + - DNSName + + EdgeHTTPS: + Description: HTTPS URL of the Ant Media Edge Servers + Value: !Join + - '' + - - 'https://' + - !GetAtt + - ApplicationLoadBalancer + - DNSName + - ':5443' + + OriginHTTP: + Description: HTTP URL of the Ant Media Origin Servers + Value: !Join + - '' + - - 'http://' + - !GetAtt + - ApplicationLoadBalancer + - DNSName + + EdgeHTTP: + Description: HTTP URL of the Ant Media Edge Servers + Value: !Join + - '' + - - 'http://' + - !GetAtt + - ApplicationLoadBalancer + - DNSName + - ':5080' + + RTMP: + Description: RTMP URL of the Ant Media Server + Value: !Join + - '' + - - 'rtmp://' + - !GetAtt + - RTMPLoadBalancer + - DNSName + +