openvidu/openvidu-server/deployments/ce/aws/CF-OpenVidu.yaml.template

582 lines
19 KiB
Plaintext
Raw Normal View History

AWSTemplateFormatVersion: 2010-09-09
Description: OpenVidu Platform
Parameters:
# Domain and SSL certificate configuration
WhichCert:
Description: >
[selfsigned] Self signed certificate. Not recommended for production use.
[owncert] Valid certificate purchased in a Internet services company.
[letsencrypt] Generate a new certificate using Let's Encrypt.
Type: String
AllowedValues:
- selfsigned
- owncert
- letsencrypt
Default: selfsigned
PublicElasticIP:
Description: "Previously created AWS Elastic IP to associate it to the OpenVidu EC2 instance. If certificate type is 'selfsigned' this value is optional. If certificate type is 'owncert' or 'letsencrypt' this value is mandatory. Example 13.33.145.23."
Type: String
AllowedPattern: ^$|^([01]?\d{1,2}|2[0-4]\d|25[0-5])\.([01]?\d{1,2}|2[0-4]\d|25[0-5])\.([01]?\d{1,2}|2[0-4]\d|25[0-5])\.([01]?\d{1,2}|2[0-4]\d|25[0-5])$
ConstraintDescription: The public Elastic IP does not have a valid IPv4 format
MyDomainName:
Description: "Valid domain name pointing to previous IP. If certificate type is 'selfsigned' this value is optional. If certificate type is 'owncert' or 'letsencrypt' this value is mandatory. Example: openvidu.company.com"
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]$
ConstraintDescription: The domain name does not have a valid domain name format
OwnCertCRT:
Description: "If certificate type is 'owncert' this is the URL where CRT file will be downloaded"
Type: String
OwnCertKEY:
Description: "If certificate type is 'owncert' this is the URL where KEY file will be downloaded"
Type: String
LetsEncryptEmail:
Description: "If certificate type is 'letsencrypt', this email will be used for Let's Encrypt notifications"
Type: String
# OpenVidu configuration
OpenViduSecret:
2020-11-06 00:03:12 +01:00
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_-]+$
NoEcho: true
ConstraintDescription: "Cannot be empty and must contain only alphanumeric characters [a-zA-Z0-9], hypens ('-') and underscores ('_')"
# EC2 Instance configuration
InstanceType:
Description: "Specifies the EC2 instance type for your OpenVidu instance"
Type: String
Default: c5.xlarge
AllowedValues:
- 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"
KeyName:
Description: "Name of an existing EC2 KeyPair to enable SSH access to the instance. It is mandatory to perform some administrative tasks of OpenVidu."
Type: 'AWS::EC2::KeyPair::KeyName'
ConstraintDescription: "must be the name of an existing EC2 KeyPair"
# Other configuration
WantToDeployDemos:
Description: "Choose if you want to deploy OpenVidu Call application alongside OpenVidu platform."
Type: String
AllowedValues:
- true
- false
Default: true
WantToSendInfo:
Description: "Choose if you want to send to OpenVidu team the version deployed and AWS region."
Type: String
AllowedValues:
- true
- false
Default: true
#start_mappings
Mappings:
OVAMIMAP:
eu-west-1:
AMI: OV_AMI_ID
#end_mappings
Metadata:
'AWS::CloudFormation::Interface':
ParameterGroups:
- Label:
default: Domain and SSL certificate configuration
Parameters:
- WhichCert
- PublicElasticIP
- MyDomainName
- OwnCertCRT
- OwnCertKEY
- LetsEncryptEmail
- Label:
default: OpenVidu configuration
Parameters:
- OpenViduSecret
- Label:
default: EC2 Instance configuration
Parameters:
- InstanceType
- KeyName
- Label:
default: Other configuration
Parameters:
- WantToDeployDemos
- WantToSendInfo
ParameterLabels:
# SSL certificate configuration
WhichCert:
default: "Certificate Type"
PublicElasticIP:
default: "AWS Elastic IP (EIP)"
MyDomainName:
default: "Domain Name pointing to Elastic IP"
OwnCertCRT:
default: "URL to the CRT file (owncert)"
OwnCertKEY:
default: "URL to the key file (owncert)"
LetsEncryptEmail:
default: "Email for Let's Encrypt (letsencrypt)"
# OpenVidu configuration
OpenViduSecret:
default: "Openvidu Secret"
# EC2 Instance configuration
InstanceType:
default: "Instance type"
KeyName:
default: "SSH Key"
# Other configuration
WantToDeployDemos:
default: "Deploy OpenVidu Call application"
WantToSendInfo:
default: "Send deployment info to OpenVidu team"
Conditions:
WhichCertPresent: !Not [ !Equals [!Ref WhichCert, ""] ]
PublicElasticIPPresent: !Not [ !Equals [!Ref PublicElasticIP, ""] ]
Resources:
LaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: IMDSV2
LaunchTemplateData:
MetadataOptions:
HttpEndpoint: enabled
HttpPutResponseHopLimit: 1
HttpTokens: required
OpenviduServer:
Type: 'AWS::EC2::Instance'
Metadata:
Comment: 'Install and configure OpenVidu Server and Demos'
AWS::CloudFormation::Init:
config:
files:
'/usr/local/bin/ping.sh':
content: |
#!/bin/bash
INXDB_URL=193.147.51.51
INXDB_DB=ov_server
INXDB_MEASUREMENT=server
OV_VERSION=OPENVIDU_VERSION
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
EC2_AVAIL_ZONE=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/availability-zone)
EC2_REGION=$(echo "$EC2_AVAIL_ZONE" | sed 's/[a-z]$//')
curl -i -XPOST "http://$INXDB_URL:8086/write?db=$INXDB_DB" \
--data-binary "$INXDB_MEASUREMENT,region=$EC2_REGION ov_version=\"$OV_VERSION\" "
mode: "000755"
owner: "root"
group: "root"
'/usr/local/bin/check_app_ready.sh':
content: |
#!/bin/bash
while true; do
HTTP_STATUS=$(curl -Ik http://localhost:5443 | head -n1 | awk '{print $2}')
if [ $HTTP_STATUS == 200 ]; then
break
fi
sleep 5
done
mode: "000755"
owner: "root"
group: "root"
'/usr/local/bin/feedGroupVars.sh':
content: !Sub |
#!/bin/bash -x
WORKINGDIR=/opt/openvidu
# Replace secret
sed -i "s/OPENVIDU_SECRET=/OPENVIDU_SECRET=${OpenViduSecret}/" $WORKINGDIR/.env
# Replace domain name
if [[ "${MyDomainName}" != '' && "${PublicElasticIP}" != '' ]]; then
sed -i "s/DOMAIN_OR_PUBLIC_IP=/DOMAIN_OR_PUBLIC_IP=${MyDomainName}/" $WORKINGDIR/.env
elif [[ "${MyDomainName}" == '' && "${PublicElasticIP}" != '' ]]; then
sed -i "s/DOMAIN_OR_PUBLIC_IP=/DOMAIN_OR_PUBLIC_IP=${PublicElasticIP}/" $WORKINGDIR/.env
else
[ ! -d "/usr/share/openvidu" ] && mkdir -p /usr/share/openvidu
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
PublicHostname=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-hostname)
sed -i "s/DOMAIN_OR_PUBLIC_IP=/DOMAIN_OR_PUBLIC_IP=$PublicHostname/" $WORKINGDIR/.env
echo $PublicHostname > /usr/share/openvidu/old-host-name
fi
# Replace certificated type
sed -i "s/CERTIFICATE_TYPE=selfsigned/CERTIFICATE_TYPE=${WhichCert}/" $WORKINGDIR/.env
sed -i "s/LETSENCRYPT_EMAIL=user@example.com/LETSENCRYPT_EMAIL=${LetsEncryptEmail}/" $WORKINGDIR/.env
# Without Application
if [ "${WantToDeployDemos}" == "false" ]; then
sed -i "s/WITH_APP=true/WITH_APP=false/" $WORKINGDIR/docker-compose.yml
rm $WORKINGDIR/docker-compose.override.yml
fi
mode: "000755"
owner: "root"
group: "root"
'/usr/local/bin/buildCerts.sh':
content: !Sub |
#!/bin/bash -x
WORKINGDIR=/opt/openvidu
wget --no-check-certificate -O $WORKINGDIR/owncert/certificate.cert ${OwnCertCRT}
wget --no-check-certificate -O $WORKINGDIR/owncert/certificate.key ${OwnCertKEY}
mode: "000755"
owner: "root"
group: "root"
'/usr/local/bin/restartCE.sh':
content: !Sub |
#!/bin/bash -x
WORKINGDIR=/opt/openvidu
# Get new amazon URL
OldPublicHostname=$(cat /usr/share/openvidu/old-host-name)
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
PublicHostname=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-hostname)
sed -i "s/$OldPublicHostname/$PublicHostname/" $WORKINGDIR/.env
echo $PublicHostname > /usr/share/openvidu/old-host-name
# Restart all services
pushd "$WORKINGDIR"
./openvidu restart >/dev/null 2>&1 &
popd
mode: "000755"
owner: "root"
group: "root"
Properties:
ImageId: !GetAtt CloudformationLambdaInvoke.ImageId
LaunchTemplate:
LaunchTemplateName: IMDSV2
Version: 1
InstanceType: !Ref InstanceType
SecurityGroups:
- !Ref WebServerSecurityGroup
KeyName: !Ref KeyName
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
UserData:
Fn::Base64: !Sub |
#!/bin/bash -x
set -eu -o pipefail
cfn-init --region ${AWS::Region} --stack ${AWS::StackId} --resource OpenviduServer
export HOME="/root"
# Replace .env variables
/usr/local/bin/feedGroupVars.sh || { echo "[OpenVidu] Parameters incorrect/insufficient"; exit 1; }
# Launch on reboot
echo "@reboot /usr/local/bin/restartCE.sh" | crontab
# Download certs if "WichCert" mode
if [ "${WhichCert}" == "owncert" ]; then
/usr/local/bin/buildCerts.sh || { echo "[OpenVidu] error with the certificate files"; exit 1; }
fi
# Start openvidu application
pushd /opt/openvidu
./openvidu start >/dev/null 2>&1 &
popd
# Send info to openvidu
if [ "${WantToSendInfo}" == "true" ]; then
/usr/local/bin/ping.sh || true
fi
rm /usr/local/bin/ping.sh
# Wait for the app
/usr/local/bin/check_app_ready.sh
# sending the finish call
/usr/local/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource WaitCondition --region ${AWS::Region}
BlockDeviceMappings:
- DeviceName: /dev/sda1
Ebs:
VolumeType: gp3
DeleteOnTermination: true
VolumeSize: 200
MyEIP:
Type: 'AWS::EC2::EIPAssociation'
Condition: PublicElasticIPPresent
Properties:
InstanceId: !Ref OpenviduServer
EIP: !Ref PublicElasticIP
WaitCondition:
Type: 'AWS::CloudFormation::WaitCondition'
CreationPolicy:
ResourceSignal:
Timeout: PT30M
Count: '1'
WebServerSecurityGroup:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupDescription: SSH, Proxy and OpenVidu WebRTC Ports
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIpv6: ::/0
- 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
- IpProtocol: tcp
FromPort: 3478
ToPort: 3478
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 3478
ToPort: 3478
CidrIpv6: ::/0
- IpProtocol: udp
FromPort: 3478
ToPort: 3478
CidrIp: 0.0.0.0/0
- IpProtocol: udp
FromPort: 3478
ToPort: 3478
CidrIpv6: ::/0
- IpProtocol: udp
FromPort: 40000
ToPort: 57000
CidrIp: 0.0.0.0/0
- IpProtocol: udp
FromPort: 40000
ToPort: 57000
CidrIpv6: ::/0
- IpProtocol: tcp
FromPort: 40000
ToPort: 57000
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 40000
ToPort: 57000
CidrIpv6: ::/0
##########
# Lambda to Copy original AMI to the deployment region
##########
CloudformationLambdaRole:
Type: 'AWS::IAM::Role'
DeletionPolicy: Delete
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: /
Policies:
- PolicyName: !Join ['', [ !Ref AWS::StackName, '-cf-lambda-policy'] ]
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'ec2:DescribeImages'
- 'ec2:CopyImage'
Resource: '*'
RoleName: !Join ['', [ !Ref AWS::StackName, '-cf-lambda-role'] ]
CloudformationLambda:
Type: AWS::Lambda::Function
DeletionPolicy: Delete
Properties:
FunctionName: !Join ['', [ !Ref AWS::StackName, '-cf-lambda'] ]
Code:
ZipFile: |
import boto3
import cfnresponse
from botocore.config import Config
def handler(event, context):
try:
if (event['RequestType'] == 'Create'):
copy_ami(event, context)
return
else:
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
except Exception:
cfnresponse.send(event, context, cfnresponse.FAILED, {})
def copy_ami(event, context):
new_images=[]
cfn_output = {}
source_image_id = event['ResourceProperties']['AmiSourceId']
source_region = event['ResourceProperties']['AmiSourceRegion']
deployment_region = event['ResourceProperties']['DeploymentRegion']
# Clients init
ec2_client = boto3.client('ec2', config = Config(region_name=deployment_region))
ec2_client_ov = boto3.client('ec2', config = Config(region_name=source_region))
img_exists_waiter= ec2_client.get_waiter('image_exists')
img_avail_waiter = ec2_client.get_waiter('image_available')
# Get original ami name
public_ami_filter = [{ 'Name': 'image-id', 'Values': [ source_image_id ] }]
response = ec2_client_ov.describe_images(Filters=public_ami_filter)
new_ami_name= "[ OpenVidu CE AMI Copy ] - " + response['Images'][0]['Name']
own_ami_filter = [{ 'Name': 'name', 'Values': [new_ami_name] }]
response = ec2_client.describe_images(Filters=own_ami_filter)
if (len(response['Images']) == 1):
# If AMI exists, don't copy
new_images.append(response['Images'][0]['ImageId'])
cfn_output['ImageId'] = response['Images'][0]['ImageId']
else:
# If AMI does not exist, copy
response = ec2_client.copy_image(
SourceImageId=source_image_id,
SourceRegion=source_region,
Name=new_ami_name
)
new_images.append(response['ImageId'])
cfn_output['ImageId'] = response['ImageId']
# Wait images to be available
waiter_config = {'Delay': 15, 'MaxAttempts': 59
}
# Wait image to exist
response = img_exists_waiter.wait(ImageIds=new_images, WaiterConfig=waiter_config
)
# Wait image to be available
response = img_avail_waiter.wait(ImageIds=new_images, WaiterConfig=waiter_config)
# Return AMI
cfnresponse.send(event, context, cfnresponse.SUCCESS, cfn_output)
Handler: index.handler
Role:
!GetAtt CloudformationLambdaRole.Arn
Runtime: python3.11
Timeout: 900
CloudformationLambdaInvoke:
Type: AWS::CloudFormation::CustomResource
DeletionPolicy: Delete
Version: "1.0"
Properties:
ServiceToken: !GetAtt CloudformationLambda.Arn
AmiSourceRegion: 'eu-west-1'
AmiSourceId: !FindInMap [OVAMIMAP, 'eu-west-1', AMI]
DeploymentRegion: !Ref AWS::Region
Outputs:
OpenViduServerURL:
Description: Use this URL to connect OpenVidu Server
Value: !Join
- ''
- - 'https://'
- !GetAtt
- OpenviduServer
- PublicDnsName
OpenViduServerURLLE:
Description: Use this URL to connect OpenVidu Server
Value: !Join
- ''
- - 'https://'
- !Ref MyDomainName
Condition: WhichCertPresent
OpenViduCallURL:
Description: If you choose to deploy OpenVidu Call application, use this URL
Value: !Join
- ''
- - 'https://'
- !GetAtt
- OpenviduServer
- PublicDnsName
OpenViduCallURLLE:
Description: If you choose to deploy OpenVidu Call application, use this URL
Value: !Join
- ''
- - 'https://'
- !Ref MyDomainName
Condition: WhichCertPresent