--- AWSTemplateFormatVersion: 2010-09-09 Description: Openvidu Pro With Master Replication Parameters: DomainName: Description: 'Domain name which will be used to access OpenVidu Pro. This domain name should point to the Load Balancer URL after the stack is deployed.' Type: 'String' AllowedPattern: ^$|^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$ MinLength: 1 ConstraintDescription: The domain name does not have a valid domain name format KeyName: Description: 'Name of an existing EC2 KeyPair to enable SSH access to the instance. It is mandatory to perform some administrative tasks on instances.' Type: 'AWS::EC2::KeyPair::KeyName' AllowedPattern : '.+' ConstraintDescription: 'Must be defined and to be an existing EC2 KeyPair' OpenViduLicense: Description: 'Visit https://openvidu.io/account' Type: String AllowedPattern: ^(?!\s*$).+$ MinLength: 1 NoEcho: true ConstraintDescription: OpenVidu Pro License is mandatory OpenViduSecret: Description: 'Secret to connect to this OpenVidu Platform. Cannot be empty and must contain only alphanumeric characters [a-zA-Z0-9], hypens ("-") and underscores ("_")' Type: String AllowedPattern: ^[a-zA-Z0-9_-]+$ MinLength: 1 NoEcho: true ConstraintDescription: 'Cannot be empty and must contain only alphanumeric characters [a-zA-Z0-9], hypens ("-") and underscores ("_")' MediaServer: Description: 'Media Server to be deployed in Media Nodes' Type: String Default: mediasoup AllowedValues: - mediasoup - kurento ConstraintDescription: 'Must be a valid EC2 instance type' OpenViduProClusterId: Description: 'Unique identifier for the OpenVidu Pro cluster' Type: String MinLength: 1 AllowedPattern: ^[a-z0-9_-]+$ ConstraintDescription: 'Cannot be empty and must contain only lowercase characters [a-z0-9], hypens ("-") and underscores ("_")' OpenViduS3BucketName: Description: "Bucket to save configuration and recordings. If not defined, a default one will be created" Type: String Default: '' OpenViduS3ConfigAutoRestart: Description: "If true, changes at in .env file in S3 bucket will restart automatically all master nodes." Type: String AllowedValues: - true - false Default: true OpenViduRecording: Description: "If 'true', recordings will be saved in an s3 bucket created by this cloudformation, or the defined one at OpenViduS3Bucket" Type: String AllowedValues: - true - false Default: true CoturnInMediaNodes: Description: "If true, Coturn will be deployed on media nodes. Otherwise it will be deployed in master nodes." Type: String AllowedValues: - true - false Default: false # Enable Elasticsearch and Kibana ElasticsearchEnabled: Description: "Choose if you want OpenVidu to use Elasticsearch." Type: String AllowedValues: - true - false Default: true # Elasticsearch configuration ElasticsearchUser: Description: "Username for Elasticsearch and Kibana. ('ElasticSearch Enabled' must be true)" Type: String AllowedPattern: ^$|^[^" ]+$ ConstraintDescription: Elasticsearch user is mandatory (no whitespaces or quotations allowed) Default: elasticadmin ElasticsearchPassword: Description: "Password for Elasticsearch and Kibana ('ElasticSearch Enabled' must be true)" Type: String AllowedPattern: ^$|^[^" ]+$ NoEcho: true ConstraintDescription: Elasticsearch password is mandatory and it should have at least 6 characters (no whitespaces or quotations allowed) # Elasticsearch configuration ElasticsearchUrl: Description: "If you have an external Elasticsearch service running, put here the url to the service. If empty, an Elasticsearch service will be deployed next to OpenVidu. ('ElasticSearch Enabled' must be true)" Type: String AllowedPattern: (^(https?:\/\/)?([^:\/]+)(:([0-9]+))?(\/.*)?$|^$) ConstraintDescription: "It is very important to specify the Elasticsearch URL with the port used by this service. For example: https://es-example" KibanaUrl: Description: "If you have an external Kibana service running, put here the url to the service. If empty, a Kibana service will be deployed next to OpenVidu. ('ElasticSearch Enabled' must be true)" Type: String AllowedPattern: (^(https?:\/\/)?([^:\/]+)(:([0-9]+))?(\/.*)?$|^$) ConstraintDescription: "It is very important to specify the url with port used by this service. For example: https://kibana-example" LoadBalancerCertificateARN: Description: 'Amazon certificate arn resource to load into the LoadBalancer' Type: String AllowedPattern: '.+' ConstraintDescription: The Load Balancer domain name must be defined AwsInstanceTypeOV: Description: 'Specifies the EC2 instance type for your OpenVidu Server Pro Node' Type: String Default: c5.xlarge AllowedValues: - t2.medium - t2.large - t2.xlarge - t2.2xlarge - t3.large - t3.xlarge - t3.2xlarge - m4.large - m4.xlarge - m4.2xlarge - m4.4xlarge - m4.10xlarge - m4.16xlarge - m5.large - m5.xlarge - m5.2xlarge - m5.4xlarge - m5.8xlarge - m5.12xlarge - m5.16xlarge - m5.24xlarge - c4.large - c4.xlarge - c4.2xlarge - c4.4xlarge - c4.8xlarge - c5.large - c5.xlarge - c5.2xlarge - c5.4xlarge - c5.9xlarge - c5.12xlarge - c5.18xlarge - c5.24xlarge - c6a.large - c6a.xlarge - c6a.2xlarge - c6a.4xlarge - c6a.8xlarge - c6a.12xlarge - c6a.16xlarge - c6a.24xlarge - c6a.32xlarge - c6a.48xlarge - c6a.metal ConstraintDescription: 'Must be a valid EC2 instance type' AwsInstanceTypeKMS: Description: 'Specifies the EC2 instance type for your Media Nodes' Type: String Default: c5.xlarge AllowedValues: - t2.medium - t2.large - t2.xlarge - t2.2xlarge - t3.large - t3.xlarge - t3.2xlarge - m4.large - m4.xlarge - m4.2xlarge - m4.4xlarge - m4.10xlarge - m4.16xlarge - m5.large - m5.xlarge - m5.2xlarge - m5.4xlarge - m5.8xlarge - m5.12xlarge - m5.16xlarge - m5.24xlarge - c4.large - c4.xlarge - c4.2xlarge - c4.4xlarge - c4.8xlarge - c5.large - c5.xlarge - c5.2xlarge - c5.4xlarge - c5.9xlarge - c5.12xlarge - c5.18xlarge - c5.24xlarge - c6a.large - c6a.xlarge - c6a.2xlarge - c6a.4xlarge - c6a.8xlarge - c6a.12xlarge - c6a.16xlarge - c6a.24xlarge - c6a.32xlarge - c6a.48xlarge - c6a.metal ConstraintDescription: 'Must be a valid EC2 instance type' MinMasterNodes: Description: 'Minimun number of Master Nodes' Type: Number Default: 1 MinValue: 1 ConstraintDescription: 'A Minimun number of Master Nodes is mandatory' MaxMasterNodes: Description: 'Maximum number of Master Nodes' Type: Number Default: 4 MinValue: 1 ConstraintDescription: 'A Maximum number of Master Nodes is mandatory' DesiredMasterNodes: Description: 'Desired number of Master Nodes' Type: Number Default: 1 MinValue: 1 ConstraintDescription: 'A desired number of Master Nodes is mandatory' MinMediaNodes: Description: 'Minimun number of Media Nodes' Type: Number Default: 1 MinValue: 1 ConstraintDescription: 'A Minimun number of Master Nodes is mandatory' MaxMediaNodes: Description: 'Maximum number of Media Nodes' Type: Number Default: 4 MinValue: 1 ConstraintDescription: 'A Maximum number of Master Nodes is mandatory' ScaleUpMediaNodesAvgCpu: Description: 'Scale up media nodes when avg cpu is greater the specified value' Type: Number Default: 70 MinValue: 0 ConstraintDescription: 'A desired number of Master Nodes is mandatory' ScaleDownMediaNodesAvgCpu: Description: 'Scale down media nodes when avg cpu is below the specified value' Type: Number Default: 30 MinValue: 1 ConstraintDescription: 'A desired number of Master Nodes is mandatory' DesiredMediaNodes: Description: 'Desired number of Media Nodes' Type: Number Default: 1 MinValue: 1 ConstraintDescription: 'A desired number of Master Nodes is mandatory' OpenViduVPC: Description: 'Dedicated VPC for OpenVidu cluster' Type: AWS::EC2::VPC::Id AllowedPattern: ^.+$ ConstraintDescription: You must specify a VPC ID OpenViduSubnets: Description: 'Subnet for OpenVidu cluster' Type: List AllowedPattern: ^.+$ ConstraintDescription: You must specify a subnet ID #start_mappings Mappings: OVAMIMAP: eu-west-1: AMI: OV_MASTER_REPLICATION_AMI_ID KMSAMIMAP: eu-west-1: AMI: KMS_AMI_ID #end_mappings Metadata: 'AWS::CloudFormation::Interface': ParameterGroups: - Label: default: OpenVidu configuration Parameters: - DomainName - OpenViduProClusterId - OpenViduLicense - OpenViduSecret - MediaServer - OpenViduS3BucketName - OpenViduS3ConfigAutoRestart - OpenViduRecording - CoturnInMediaNodes - Label: default: Elasticsearch and Kibana configuration Parameters: - ElasticsearchEnabled - ElasticsearchUrl - KibanaUrl - ElasticsearchUser - ElasticsearchPassword - Label: default: EC2 and Autoscaling configuration Parameters: - AwsInstanceTypeOV - AwsInstanceTypeKMS - KeyName - MinMasterNodes - MaxMasterNodes - DesiredMasterNodes - MinMediaNodes - MaxMediaNodes - DesiredMediaNodes - ScaleUpMediaNodesAvgCpu - ScaleDownMediaNodesAvgCpu - Label: default: Load Balancer Certificate Configuration Parameters: - LoadBalancerCertificateARN - Label: default: Networking configuration Parameters: - OpenViduVPC - OpenViduSubnets ParameterLabels: # OpenVidu General Configuration DomainName: default: 'Domain Name' OpenViduProClusterId: default: 'OpenVidu Pro Cluster Id' OpenViduLicense: default: 'OpenVidu Pro License' OpenViduSecret: default: 'OpenVidu Secret' MediaServer: default: 'Media Server' OpenViduS3BucketName: default: 'S3 Bucket where recordings and OpenVidu configuration will be stored' OpenViduS3ConfigAutoRestart: default: 'Auto Restart OpenVidu on S3 bucket .env changes' OpenViduRecording: default: 'Enable OpenVidu Recording' CoturnInMediaNodes: default: 'Deploy Coturn in Media Nodes. (Experimental)' # Elasticsearch and Kibana Configuration ElasticsearchEnabled: default: "Enable Elasticsearch and Kibana" ElasticsearchUrl: default: 'Elasticsearch URL' KibanaUrl: default: 'Kibana URL' ElasticsearchUser: default: 'Elasticsearch and Kibana username' ElasticsearchPassword: default: 'Elasticsearch and Kibana password' # SSL Certificate Configuration LoadBalancerCertificateARN: default: 'ARN of the AWS Certificate. This certificate must be valid for "Domain Name"' # EC2 And Autoscaling Configuration AwsInstanceTypeOV: default: "Master Nodes instance type" AwsInstanceTypeKMS: default: 'Media Nodes instance type' KeyName: default: 'SSH Key Name' MinMasterNodes: default: 'Minimum Master Nodes' MaxMasterNodes: default: 'Maximum Master Nodes' DesiredMasterNodes: default: 'Desired Master Nodes' DesiredMediaNodes: default: 'Desired Media Nodes' MinMediaNodes: default: 'Minimum Media Nodes' MaxMediaNodes: default: 'Maximum Media Nodes' ScaleUpMediaNodesAvgCpu: default: 'Scale Up Media Nodes on Average CPU' ScaleDownMediaNodesAvgCpu: default: 'Scale Down Media Nodes on Average CPU' # Networking Configuration OpenViduVPC: default: 'OpenVidu Pro VPC' OpenViduSubnets: default: 'OpenVIdu Pro Subnets' Conditions: CreateS3Bucket: !Equals [ !Ref OpenViduS3BucketName, ''] Rules: # Check when Elasticsearch is enabled that all the parameters are present ElasticsearchValidation: RuleCondition: !Equals [ !Ref ElasticsearchEnabled, 'true' ] Assertions: - AssertDescription: Paramter 'Elasticsearch and Kibana username' (ElasticsearchUser) is needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'true'. Assert: !Not [ !Equals [!Ref ElasticsearchUser, ''] ] - AssertDescription: Parameter 'Elasticsearch and Kibana password' (ElasticsearchPassword) is needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'true'. Assert: !Not [ !Equals [!Ref ElasticsearchPassword, ''] ] # Check when Elasticsearch is disabled that any parameter of elasticsearch is not present ElasticsearchDisabledValidation: RuleCondition: !Equals [ !Ref ElasticsearchEnabled, 'false' ] Assertions: - AssertDescription: Parameter 'Elasticsearch URL' (ElasticsearchUrl) is not needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'false'. Assert: !Equals [ !Ref ElasticsearchUrl, "" ] - AssertDescription: Parameter 'Kibana URL' (KibanaUrl) is not needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'false'. Assert: !Equals [ !Ref KibanaUrl, "" ] - AssertDescription: Parameter 'Elasticsearch and Kibana username' (ElasticsearchUser) is not needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'false'. Assert: !Equals [ !Ref ElasticsearchUser, "" ] - AssertDescription: Parameter 'Elasticsearch and Kibana password' (ElasticsearchPassword) is not needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'false'. Assert: !Equals [ !Ref ElasticsearchPassword, "" ] Resources: ##### # S3 bucket ##### S3OpenViduBucket: Type: 'AWS::S3::Bucket' DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: ### Unique bucket name using Stack ID BucketName: !Join [ "-", [ !Ref OpenViduProClusterId, !Select [0, !Split ["-", !Select [2, !Split [/, !Ref AWS::StackId ]]]] ] ] AccessControl: Private PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls : true RestrictPublicBuckets: true Condition: CreateS3Bucket ##### # Security groups ##### # Security group with all open ports necessary for OpenVidu Pro to work # Only the Load Balancer has access to replication-manager port 4443 which proxies to OpenVidu Pro OpenViduSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: SSH and OpenVidu WebRTC Ports GroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'OpenViduSecurityGroup'] ] VpcId: !Ref OpenViduVPC Tags: - Key: Name Value: !Join [ "-", [ !Ref 'AWS::StackName', 'OpenViduSecurityGroup'] ] SecurityGroupIngress: - IpProtocol: udp FromPort: 3478 ToPort: 3478 CidrIp: 0.0.0.0/0 - IpProtocol: udp FromPort: 3478 ToPort: 3478 CidrIpv6: ::/0 - IpProtocol: tcp FromPort: 3478 ToPort: 3478 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 3478 ToPort: 3478 CidrIpv6: ::/0 - IpProtocol: tcp FromPort: 4443 ToPort: 4443 SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup - IpProtocol: udp FromPort: 40000 ToPort: 65535 CidrIp: 0.0.0.0/0 - IpProtocol: udp FromPort: 40000 ToPort: 65535 CidrIpv6: ::/0 - IpProtocol: tcp FromPort: 40000 ToPort: 65535 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 40000 ToPort: 65535 CidrIpv6: ::/0 SecurityGroupEgress: - IpProtocol: tcp FromPort: 1 ToPort: 65535 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 1 ToPort: 65535 CidrIpv6: ::/0 - IpProtocol: udp FromPort: 1 ToPort: 65535 CidrIp: 0.0.0.0/0 - IpProtocol: udp FromPort: 1 ToPort: 65535 CidrIpv6: ::/0 # This security groups Ingress rule is for OpenVidu Pro Master instances which only need access # to other OpenVidu Pro instances at port 5443 and 4443 to proxy requests from replication-manager OpenViduSecurityGroupIngressServer: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref OpenViduSecurityGroup IpProtocol: tcp FromPort: 5443 ToPort: 5443 SourceSecurityGroupId: !Ref OpenViduSecurityGroup OpenViduSecurityGroupIngressReplicationManager: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref OpenViduSecurityGroup IpProtocol: tcp FromPort: 4443 ToPort: 4443 SourceSecurityGroupId: !Ref OpenViduSecurityGroup LoadBalancerSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: VpcId: !Ref OpenViduVPC GroupDescription: Load Balancer Security group GroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'LoadBalancerSecurityGroup'] ] Tags: - Key: Name Value: !Join [ "-", [ !Ref 'AWS::StackName', 'LoadBalancerSecurityGroup'] ] SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIpv6: ::/0 - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIpv6: ::/0 SecurityGroupEgress: - IpProtocol: tcp FromPort: 1 ToPort: 65535 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 1 ToPort: 65535 CidrIpv6: ::/0 - IpProtocol: udp FromPort: 1 ToPort: 65535 CidrIp: 0.0.0.0/0 - IpProtocol: udp FromPort: 1 ToPort: 65535 CidrIpv6: ::/0 # Redis Security group. # Let access only to instances with OpenVidu Pro security group attached RedisSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: VpcId: !Ref OpenViduVPC GroupDescription: Security Group for OpenVidu Pro Redis GroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'RedisSecurityGroup'] ] Tags: - Key: Name Value: !Join [ "-", [ !Ref 'AWS::StackName', 'RedisSecurityGroup'] ] SecurityGroupIngress: - IpProtocol: tcp FromPort: 6379 ToPort: 6379 SourceSecurityGroupId: !Ref OpenViduSecurityGroup SecurityGroupEgress: - IpProtocol: tcp FromPort: 1 ToPort: 65535 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 1 ToPort: 65535 CidrIpv6: ::/0 # Media Nodes Security group. Let access only to # instances with OpenVidu Pro security group attached # to ports 3000, 4000, and 8888 MediaNodeSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: VpcId: !Ref OpenViduVPC GroupDescription: SSH, Media Node controller and KMS WebRTC Ports GroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'KMSSecurityGroup'] ] Tags: - Key: Name Value: !Join [ "-", [ !Ref 'AWS::StackName', 'KMSSecurityGroup'] ] SecurityGroupIngress: - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIpv6: ::/0 - IpProtocol: udp FromPort: 443 ToPort: 443 CidrIp: 0.0.0.0/0 - IpProtocol: udp FromPort: 443 ToPort: 443 CidrIpv6: ::/0 - IpProtocol: tcp FromPort: 3000 ToPort: 3000 SourceSecurityGroupId: !Ref OpenViduSecurityGroup - IpProtocol: tcp FromPort: 4000 ToPort: 4000 SourceSecurityGroupId: !Ref OpenViduSecurityGroup - IpProtocol: tcp FromPort: 8888 ToPort: 8888 SourceSecurityGroupId: !Ref OpenViduSecurityGroup - IpProtocol: udp FromPort: 40000 ToPort: 65535 CidrIp: 0.0.0.0/0 - IpProtocol: udp FromPort: 40000 ToPort: 65535 CidrIpv6: ::/0 - IpProtocol: tcp FromPort: 40000 ToPort: 65535 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 40000 ToPort: 65535 CidrIpv6: ::/0 SecurityGroupEgress: - IpProtocol: tcp FromPort: 1 ToPort: 65535 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 1 ToPort: 65535 CidrIpv6: ::/0 - IpProtocol: udp FromPort: 1 ToPort: 65535 CidrIp: 0.0.0.0/0 - IpProtocol: udp FromPort: 1 ToPort: 65535 CidrIpv6: ::/0 ##### # Redis Cluster ##### RedisClusterSubnetGroup: Type: AWS::ElastiCache::SubnetGroup Properties: CacheSubnetGroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'RedisSubnetGroup'] ] Description: Subnet where to deploy Redis SubnetIds: !Ref OpenViduSubnets RedisCluster: Type: AWS::ElastiCache::CacheCluster Properties: ClusterName: !Join [ "-", [ !Ref 'AWS::StackName', 'Redis'] ] CacheNodeType: cache.t3.medium Engine: redis EngineVersion: 6.x NumCacheNodes: 1 CacheParameterGroupName: default.redis6.x CacheSubnetGroupName: !Ref RedisClusterSubnetGroup VpcSecurityGroupIds: - !Ref RedisSecurityGroup Tags: - Key: Name Value: !Join [ "-", [ !Ref 'AWS::StackName', 'Redis'] ] ##### # Media Node Autoscaling Group ##### MediaNodeLaunchTemplateConfiguration: Type: AWS::EC2::LaunchTemplate Properties: LaunchTemplateName: !Join [ "-", [ !Ref 'AWS::StackName', 'ASGMediaNodeLaunchTemplate'] ] LaunchTemplateData: MetadataOptions: HttpEndpoint: enabled HttpPutResponseHopLimit: 1 HttpTokens: required SecurityGroupIds: - !GetAtt MediaNodeSecurityGroup.GroupId ImageId: !GetAtt LambdaOnCreateInvoke.MediaNodeImageId KeyName: !Ref KeyName InstanceType: !Ref AwsInstanceTypeKMS BlockDeviceMappings: - DeviceName: /dev/sda1 Ebs: VolumeType: gp3 DeleteOnTermination: true VolumeSize: 50 MediaNodeAutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: AutoScalingGroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'ASGMediaNode'] ] LaunchTemplate: LaunchTemplateId: !Ref MediaNodeLaunchTemplateConfiguration Version: !GetAtt MediaNodeLaunchTemplateConfiguration.LatestVersionNumber MinSize: !Ref MinMediaNodes MaxSize: !Ref MaxMediaNodes DesiredCapacity: !Ref DesiredMediaNodes VPCZoneIdentifier: !Ref OpenViduSubnets NewInstancesProtectedFromScaleIn: true Tags: - Key: Name Value: !Join [ "-", [ !Ref 'AWS::StackName', 'Media Node'] ] PropagateAtLaunch: true - Key: ov-cluster-member Value: kms PropagateAtLaunch: true - Key: ov-medianode-status Value: running PropagateAtLaunch: true ##### # SQS Queue ##### SQSPolicy: Type: AWS::SQS::QueuePolicy Properties: Queues: - !Ref SQSQueue PolicyDocument: Statement: - Effect: Allow Action: - 'sqs:SendMessage' Principal: Service: - events.amazonaws.com Resource: - !GetAtt SQSQueue.Arn SQSQueue: Type: AWS::SQS::Queue Properties: QueueName: !Join ['-', [ !Ref 'AWS::StackName', 'SQS.fifo'] ] FifoQueue: true MessageRetentionPeriod: 60 VisibilityTimeout: 50 ContentBasedDeduplication: true Tags: - Key: Name Value: !Join ['-', [ !Ref 'AWS::StackName', 'SQS'] ] ##### # Load Balancer ##### LoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: !Join ['-', [ !Ref 'AWS::StackName', 'lb'] ] Subnets: !Ref OpenViduSubnets SecurityGroups: - !Ref LoadBalancerSecurityGroup Tags: - Key: Name Value: !Join ['-', [ !Ref 'AWS::StackName', 'lb'] ] HttpLoadBalancerListener: Type: "AWS::ElasticLoadBalancingV2::Listener" Properties: DefaultActions: - Type: "redirect" RedirectConfig: Protocol: "HTTPS" Port: '443' Host: "#{host}" Path: "/#{path}" Query: "#{query}" StatusCode: "HTTP_301" LoadBalancerArn: !Ref LoadBalancer Port: 80 Protocol: "HTTP" LoadBalancerListener: Type: 'AWS::ElasticLoadBalancingV2::Listener' Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref TargetGroup LoadBalancerArn: !Ref LoadBalancer Port: 443 Protocol: HTTPS Certificates: - CertificateArn: !Ref LoadBalancerCertificateARN RootListenerRule: Type: 'AWS::ElasticLoadBalancingV2::ListenerRule' Properties: ListenerArn: !Ref LoadBalancerListener Priority: 1 Conditions: - Field: path-pattern Values: - / Actions: - Type: "fixed-response" FixedResponseConfig: StatusCode: "401" InspectorListenerRule: Type: 'AWS::ElasticLoadBalancingV2::ListenerRule' Properties: ListenerArn: !Ref LoadBalancerListener Priority: 2 Conditions: - Field: path-pattern Values: - /inspector Actions: - Type: "redirect" RedirectConfig: Protocol: "HTTPS" Port: '443' Host: "#{host}" Path: "/inspector/" Query: "#{query}" StatusCode: "HTTP_301" ListenerRule: Type: 'AWS::ElasticLoadBalancingV2::ListenerRule' Properties: ListenerArn: !Ref LoadBalancerListener Priority: 3 Conditions: - Field: path-pattern Values: - /openvidu* Actions: - TargetGroupArn: !Ref TargetGroup Type: forward TargetGroup: Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' Properties: Name: !Ref 'AWS::StackName' VpcId: !Ref OpenViduVPC Port: 4443 Protocol: HTTP Matcher: HttpCode: '200' HealthCheckIntervalSeconds: 10 HealthCheckPath: /openvidu/health HealthCheckProtocol: HTTP HealthCheckPort: '4443' HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 3 UnhealthyThresholdCount: 4 Tags: - Key: Name Value: !Join [ "-", [ !Ref 'AWS::StackName', 'TargetGroup'] ] ##### # OpenVidu Pro Master Role ##### OpenViduProMasterRole: Type: 'AWS::IAM::Role' Properties: Tags: - Key: Name Value: !Join [ "-", [ !Ref 'AWS::StackName', 'MasterNodeRole'] ] AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - 'sts:AssumeRole' Path: / Policies: - PolicyName: !Join ['-', [ !Ref 'AWS::StackName', 'MasterNodePolicy'] ] PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - 'ec2:Describe*' - 'ec2:CreateTags' - 'ec2:DescribeTags' Resource: '*' - Effect: Allow Action: - 'sqs:*' Resource: !GetAtt SQSQueue.Arn - Effect: Allow Action: - 'autoscaling:SetInstanceHealth' - 'autoscaling:DescribeAutoScalingInstances' - 'autoscaling:DescribeAutoScalingGroups' - 'autoscaling:SetInstanceProtection' Resource: '*' - Effect: Allow Action: - 's3:DeleteObject' - 's3:GetObject' - 's3:PutObject' Resource: - Fn::If: - CreateS3Bucket # If bucket is created, get ARN - !Join [ "", [ !GetAtt S3OpenViduBucket.Arn, "/*" ] ] # If bucket name is defined, use bucket name - !Join [ "", [ 'arn:aws:s3:::', !Ref OpenViduS3BucketName, '/*'] ] - Effect: Allow Action: - 's3:ListBucket' - 's3:GetBucketLocation' Resource: - Fn::If: - CreateS3Bucket # If bucket is created, get ARN - !Join [ "", [ !GetAtt S3OpenViduBucket.Arn ] ] # If bucket name is defined, use bucket name - !Join [ "", [ 'arn:aws:s3:::', !Ref OpenViduS3BucketName ]] RoleName: !Join ['-', [ !Ref 'AWS::StackName', 'MasterNodeRole'] ] OpenViduProMasterInstanceProfile: Type: 'AWS::IAM::InstanceProfile' Properties: Path: / Roles: - !Ref OpenViduProMasterRole ##### # OpenVidu Pro Master AutoScaling Group ##### OpenViduProMasterNodeAutoScalingLaunchTemplate: Type: AWS::EC2::LaunchTemplate Properties: LaunchTemplateName: !Join [ "-", [ !Ref 'AWS::StackName', 'ASGMasterNodeLaunchConfiguration'] ] LaunchTemplateData: MetadataOptions: HttpEndpoint: enabled HttpPutResponseHopLimit: 1 HttpTokens: required SecurityGroupIds: - !GetAtt OpenViduSecurityGroup.GroupId IamInstanceProfile: Arn: !GetAtt OpenViduProMasterInstanceProfile.Arn ImageId: !GetAtt LambdaOnCreateInvoke.MasterNodeImageId KeyName: !Ref KeyName InstanceType: !Ref AwsInstanceTypeOV BlockDeviceMappings: - DeviceName: /dev/sda1 Ebs: VolumeType: gp3 DeleteOnTermination: true VolumeSize: 100 UserData: Fn::Base64: Fn::Sub: - | DOMAIN_OR_PUBLIC_IP=${DomainNameVar} | \ OPENVIDU_ENTERPRISE_MEDIA_SERVER=${MediaServer} | \ OPENVIDU_PRO_LICENSE=${OpenViduLicense} | \ OPENVIDU_SECRET=${OpenViduSecret} | \ OPENVIDU_PRO_CLUSTER_ID=${OpenViduProClusterId} | \ OPENVIDU_PRO_ELASTICSEARCH_HOST=${ElasticsearchUrl} | \ OPENVIDU_PRO_KIBANA_HOST=${KibanaUrl} | \ ELASTICSEARCH_USERNAME=${ElasticsearchUser} | \ ELASTICSEARCH_PASSWORD=${ElasticsearchPassword} | \ RM_REDIS_IP=${RedisHostName} | \ RM_REDIS_PORT=${RedisPort} | \ RM_SQS_QUEUE=${SqsQueueName} | \ RM_CLOUDFORMATION_ARN=${AWS::StackId} | \ OPENVIDU_PRO_CONFIG_S3_BUCKET=${OpenViduS3BucketParam} | \ RM_MEDIA_NODES_AUTOSCALING_GROUP_NAME=${MediaNodesAutoscalingGroupName} | \ RM_MASTER_NODES_AUTOSCALING_GROUP_NAME=${MasterNodesAutoscalingGroupName} | \ OPENVIDU_RECORDING=${OpenViduRecording} | \ OPENVIDU_PRO_COTURN_IN_MEDIA_NODES=${CoturnInMediaNodes} | \ OPENVIDU_ENTERPRISE_S3_CONFIG_AUTORESTART=${OpenViduS3ConfigAutoRestart} | \ OPENVIDU_PRO_ELASTICSEARCH=${ElasticsearchEnabled} - DomainNameVar: !Ref DomainName RedisHostName: !GetAtt RedisCluster.RedisEndpoint.Address RedisPort: !GetAtt RedisCluster.RedisEndpoint.Port SqsQueueName: !GetAtt SQSQueue.QueueName MediaNodesAutoscalingGroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'ASGMediaNode'] ] MasterNodesAutoscalingGroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'ASGOpenViduProMasterNode'] ] OpenViduS3BucketParam: !If [ CreateS3Bucket, !Ref S3OpenViduBucket, !Ref OpenViduS3BucketName ] OpenViduProMasterNodeAutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: AutoScalingGroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'ASGOpenViduProMasterNode'] ] LaunchTemplate: LaunchTemplateId: !Ref OpenViduProMasterNodeAutoScalingLaunchTemplate Version: !GetAtt OpenViduProMasterNodeAutoScalingLaunchTemplate.LatestVersionNumber TargetGroupARNs: - !Ref TargetGroup MinSize: !Ref MinMasterNodes MaxSize: !Ref MaxMasterNodes DesiredCapacity: !Ref DesiredMasterNodes VPCZoneIdentifier: !Ref OpenViduSubnets HealthCheckType: ELB HealthCheckGracePeriod: 180 Tags: - Key: Name Value: !Join [ "-", [ !Ref 'AWS::StackName', 'Master Node'] ] PropagateAtLaunch: true - Key: ov-cluster-member Value: server PropagateAtLaunch: true ##### # Media Node Autoscaling Lifecycle hooks ##### LaunchMediaNodeLifeCycleHook: Type: AWS::AutoScaling::LifecycleHook Properties: LifecycleHookName: !Join [ "-", [ !Ref 'AWS::StackName', 'LaunchMediaNodeLifeCycleHook'] ] AutoScalingGroupName: !Ref MediaNodeAutoScalingGroup LifecycleTransition: autoscaling:EC2_INSTANCE_LAUNCHING DefaultResult: CONTINUE HeartbeatTimeout: 30 TerminateMediaNodeLifeCycleHook: Type: AWS::AutoScaling::LifecycleHook Properties: LifecycleHookName: !Join [ "-", [ !Ref 'AWS::StackName', 'TerminateMediaNodeLifeCycleHook'] ] AutoScalingGroupName: !Ref MediaNodeAutoScalingGroup LifecycleTransition: autoscaling:EC2_INSTANCE_TERMINATING DefaultResult: ABANDON HeartbeatTimeout: 30 ########## # AWS Events ########## # Send event with launched and terminated autoscaling group instances LifeCycleMediaNodesRule: Type: AWS::Events::Rule Properties: Name: !Join ['', [ !Ref AWS::StackName, '-asg-lifecycle-rule'] ] State: 'ENABLED' EventPattern: !Sub | { "source": [ "aws.autoscaling" ], "detail": { "LifecycleTransition": ["autoscaling:EC2_INSTANCE_LAUNCHING", "autoscaling:EC2_INSTANCE_TERMINATING"], "AutoScalingGroupName": [ "${MediaNodeAutoScalingGroup}" ] } } Targets: - Arn: !GetAtt SQSQueue.Arn Id: AsgLifecycleMediaNodes SqsParameters: MessageGroupId: sqs-notification InputTransformer: InputPathsMap: source: $.source lifecycle-transition: $.detail.LifecycleTransition ec2-instance: $.detail.EC2InstanceId autoscaling-groupname: $.detail.AutoScalingGroupName InputTemplate: >- { "source": , "detail": { "LifecycleTransition": , "AutoScalingGroupName": , "EC2InstanceId": }, "role": "MediaNode" } # Send event to update cluster state on autoscaling actions from AWS AutoscalingScheduleRule: Type: AWS::Events::Rule Properties: Description: 'Executes periodically lambda which sends information about the OpenVidu Pro Cluster' Name: !Join ['', [ !Ref AWS::StackName, '-asg-rule'] ] ScheduleExpression: 'rate(1 minute)' State: 'ENABLED' Targets: - Arn: !GetAtt SQSQueue.Arn Id: AsgSchedule SqsParameters: MessageGroupId: sqs-notification InputTransformer: InputPathsMap: time: $.time InputTemplate: >- { "source": "custom.autoscaling_schedule", "detail": { "time":