openvidu/openvidu-deployment/community/singlenode/azure/cf-openvidu-singlenode.bicep

1133 lines
40 KiB
Bicep

@description('Stack name')
param stackName string
@description('''
[selfsigned] Not recommended for production use. If you don't have a FQDN, (DomainName parameter) you can use this option to generate a self-signed certificate.
[owncert] Valid for productions environments. If you have a FQDN, (DomainName parameter)
and an Elastic IP, you can use this option to use your own certificate.
[letsencrypt] Valid for production environments. If you have a FQDN, (DomainName parameter)
and an Elastic IP, you can use this option to generate a Let's Encrypt certificate.
''')
@allowed([
'selfsigned'
'owncert'
'letsencrypt'
])
param certificateType string = 'selfsigned'
@description('Previously created Public IP address for the OpenVidu Deployment. Blank will generate a public IP')
param publicIpAddress string = ''
@description('Name of the PublicIPAddress resource in your azure if you have a resource of publicIPAddress')
param publicIpAddressResourceName string = ''
@description('Domain name for the OpenVidu Deployment. Blank will generate default domain')
param domainName string = ''
@description('If certificate type is \'owncert\', this parameter will be used to specify the public certificate')
param ownPublicCertificate string = ''
@description('If certificate type is \'owncert\', this parameter will be used to specify the private certificate')
param ownPrivateCertificate string = ''
@description('If certificate type is \'letsencrypt\', this email will be used for Let\'s Encrypt notifications')
param letsEncryptEmail string = ''
@description('(Optional) Domain name for the TURN server with TLS. Only needed if your users are behind restrictive firewalls')
param turnDomainName string = ''
@description('(Optional) This setting is applicable if the certificate type is set to \'owncert\' and the TurnDomainName is specified.')
param turnOwnPublicCertificate string = ''
@description('(Optional) This setting is applicable if the certificate type is set to \'owncert\' and the TurnDomainName is specified.')
param turnOwnPrivateCertificate string = ''
// Azure instance config
@description('Specifies the azure vm size for your OpenVidu instance')
@allowed([
'Standard_B1s'
'Standard_B1ms'
'Standard_B2s'
'Standard_B2ms'
'Standard_B4ms'
'Standard_B8ms'
'Standard_D2_v3'
'Standard_D4_v3'
'Standard_D8_v3'
'Standard_D16_v3'
'Standard_D32_v3'
'Standard_D48_v3'
'Standard_D64_v3'
'Standard_D2_v4'
'Standard_D4_v4'
'Standard_D8_v4'
'Standard_D16_v4'
'Standard_D32_v4'
'Standard_D48_v4'
'Standard_D64_v4'
'Standard_D96_v4'
'Standard_D2_v5'
'Standard_D4_v5'
'Standard_D8_v5'
'Standard_D16_v5'
'Standard_D32_v5'
'Standard_D48_v5'
'Standard_D64_v5'
'Standard_D96_v5'
'Standard_F2'
'Standard_F4'
'Standard_F8'
'Standard_F16'
'Standard_F32'
'Standard_F64'
'Standard_F72'
'Standard_F2s_v2'
'Standard_F4s_v2'
'Standard_F8s_v2'
'Standard_F16s_v2'
'Standard_F32s_v2'
'Standard_F64s_v2'
'Standard_F72s_v2'
'Standard_E2_v3'
'Standard_E4_v3'
'Standard_E8_v3'
'Standard_E16_v3'
'Standard_E32_v3'
'Standard_E48_v3'
'Standard_E64_v3'
'Standard_E96_v3'
'Standard_E2_v4'
'Standard_E4_v4'
'Standard_E8_v4'
'Standard_E16_v4'
'Standard_E32_v4'
'Standard_E48_v4'
'Standard_E64_v4'
'Standard_E2_v5'
'Standard_E4_v5'
'Standard_E8_v5'
'Standard_E16_v5'
'Standard_E32_v5'
'Standard_E48_v5'
'Standard_E64_v5'
'Standard_E96_v5'
'Standard_M64'
'Standard_M128'
'Standard_M208ms_v2'
'Standard_M416ms_v2'
'Standard_L4s_v2'
'Standard_L8s_v2'
'Standard_L16s_v2'
'Standard_L32s_v2'
'Standard_L64s_v2'
'Standard_L80s_v2'
'Standard_NC6'
'Standard_NC12'
'Standard_NC24'
'Standard_NC24r'
'Standard_ND6s'
'Standard_ND12s'
'Standard_ND24s'
'Standard_ND24rs'
'Standard_NV6'
'Standard_NV12'
'Standard_NV24'
'Standard_H8'
'Standard_H16'
'Standard_H16r'
'Standard_H16mr'
'Standard_HB120rs_v2'
'Standard_HC44rs'
'Standard_DC2s'
'Standard_DC4s'
'Standard_DC2s_v2'
'Standard_DC4s_v2'
'Standard_DC8s_v2'
'Standard_DC16s_v2'
'Standard_DC32s_v2'
'Standard_A1_v2'
'Standard_A2_v2'
'Standard_A4_v2'
'Standard_A8_v2'
'Standard_A2m_v2'
'Standard_A4m_v2'
'Standard_A8m_v2'
])
param instanceType string = 'Standard_B2s' // Azure instance types.
@description('Username for the Virtual Machine.')
param adminUsername string
@description('SSH Key or password for the Virtual Machine.')
@secure()
param adminSshKey string
/*------------------------------------------- VARIABLES AND VALIDATIONS -------------------------------------------*/
//Condition for ipValid if is filled
var isEmptyIp = publicIpAddress == ''
var ipSegments = split(publicIpAddress, '.')
var isFourSegments = length(ipSegments) == 4
var seg1valid = isEmptyIp ? true : int(ipSegments[0]) >= 0 && int(ipSegments[0]) <= 255
var seg2valid = isEmptyIp ? true : int(ipSegments[1]) >= 0 && int(ipSegments[1]) <= 255
var seg3valid = isEmptyIp ? true : int(ipSegments[2]) >= 0 && int(ipSegments[2]) <= 255
var seg4valid = isEmptyIp ? true : int(ipSegments[3]) >= 0 && int(ipSegments[3]) <= 255
var isValidIP = !isEmptyIp && isFourSegments && seg1valid && seg2valid && seg3valid && seg4valid
//Condition for the domain name
var isEmptyDomain = domainName == ''
var domainParts = split(domainName, '.')
var validNumberParts = length(domainParts) >= 2
var allPartsValid = [
for part in domainParts: length(part) >= 1 && length(part) <= 63 && !empty(part) && part == toLower(part) && !contains(
part,
'--'
) && empty(replace(part, '[a-z0-9-]', ''))
]
var isDomainValid = !isEmptyDomain && validNumberParts && !contains(allPartsValid, false)
//Variables for deployment
var networkSettings = {
privateIPaddressNetInterface: '10.0.0.5'
vNetAddressPrefix: '10.0.0.0/16'
subnetAddressPrefix: '10.0.0.0/24'
netInterfaceName: '${stackName}-netInteface'
vNetName: '${stackName}-vnet'
subnetName: 'default'
}
var openviduVMSettings = {
vmName: '${stackName}-VM-CE'
osDiskType: 'StandardSSD_LRS'
ubuntuOSVersion: {
publisher: 'Canonical'
offer: '0001-com-ubuntu-server-jammy'
sku: '22_04-lts-gen2'
version: 'latest'
}
linuxConfiguration: {
disablePasswordAuthentication: true
ssh: {
publicKeys: [
{
path: '/home/${adminUsername}/.ssh/authorized_keys'
keyData: adminSshKey
}
]
}
}
}
var fqdn = isEmptyIp ? publicIP_OV.properties.dnsSettings.fqdn : domainName
//KeyVault for secrets
var keyVaultName = '${stackName}-keyvault'
var location = resourceGroup().location
var tenantId = subscription().tenantId
var deploymentUser = az.deployer().objectId
/*------------------------------------------- KEY VAULT -------------------------------------------*/
resource openviduSharedInfo 'Microsoft.KeyVault/vaults@2023-07-01' = {
name: keyVaultName
location: location
properties: {
enabledForDeployment: true
enabledForDiskEncryption: false
enabledForTemplateDeployment: true
tenantId: tenantId
enableSoftDelete: false
accessPolicies: [
{
//Rules for the master node when using key vault for secrets
objectId: openviduServer.identity.principalId
tenantId: tenantId
permissions: {
secrets: ['get', 'set', 'list']
}
}
{
//Rules for the user to check key vault for secrets
objectId: deploymentUser
tenantId: tenantId
permissions: {
secrets: ['get', 'list', 'set', 'delete', 'recover', 'backup', 'restore']
}
}
]
sku: {
name: 'standard'
family: 'A'
}
networkAcls: {
defaultAction: 'Allow'
bypass: 'AzureServices'
}
}
}
/*------------------------------------------- OPENVIDU NODE -------------------------------------------*/
//Parms for not string interpolation support for multiline
var stringInterpolationParams = {
domainName: domainName
fqdn: fqdn
turnDomainName: turnDomainName
certificateType: certificateType
letsEncryptEmail: letsEncryptEmail
ownPublicCertificate: ownPublicCertificate
ownPrivateCertificate: ownPrivateCertificate
turnOwnPublicCertificate: turnOwnPublicCertificate
turnOwnPrivateCertificate: turnOwnPrivateCertificate
keyVaultName: keyVaultName
}
var installScriptTemplate = '''
#!/bin/bash -x
OPENVIDU_VERSION=main
DOMAIN=
apt-get update && apt-get install -y \
curl \
unzip \
jq \
wget
# Configure Domain
if [[ "${domainName}" == '' ]]; then
[ ! -d "/usr/share/openvidu" ] && mkdir -p /usr/share/openvidu
DOMAIN=${fqdn}
echo ${fqdn} > /usr/share/openvidu/old-host-name
else
DOMAIN=${domainName}
fi
DOMAIN="$(/usr/local/bin/store_secret.sh save DOMAIN-NAME "$DOMAIN")"
REDIS_PASSWORD="$(/usr/local/bin/store_secret.sh generate REDIS-PASSWORD)"
MONGO_ADMIN_USERNAME="$(/usr/local/bin/store_secret.sh save MONGO-ADMIN-USERNAME "mongoadmin")"
MONGO_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh generate MONGO-ADMIN-PASSWORD)"
MONGO_REPLICA_SET_KEY="$(/usr/local/bin/store_secret.sh generate MONGO-REPLICA-SET-KEY)"
MINIO_ACCESS_KEY="$(/usr/local/bin/store_secret.sh save MINIO-ACCESS-KEY "minioadmin")"
MINIO_SECRET_KEY="$(/usr/local/bin/store_secret.sh generate MINIO-SECRET-KEY)"
DASHBOARD_ADMIN_USERNAME="$(/usr/local/bin/store_secret.sh save DASHBOARD-ADMIN-USERNAME "dashboardadmin")"
DASHBOARD_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh generate DASHBOARD-ADMIN-PASSWORD)"
GRAFANA_ADMIN_USERNAME="$(/usr/local/bin/store_secret.sh save GRAFANA-ADMIN-USERNAME "grafanaadmin")"
GRAFANA_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh generate GRAFANA-ADMIN-PASSWORD)"
DEFAULT_APP_USERNAME="$(/usr/local/bin/store_secret.sh save DEFAULT-APP-USERNAME "calluser")"
DEFAULT_APP_PASSWORD="$(/usr/local/bin/store_secret.sh generate DEFAULT-APP-PASSWORD)"
DEFAULT_APP_ADMIN_USERNAME="$(/usr/local/bin/store_secret.sh save DEFAULT-APP-ADMIN-USERNAME "calladmin")"
DEFAULT_APP_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh generate DEFAULT-APP-ADMIN-PASSWORD)"
LIVEKIT_API_KEY="$(/usr/local/bin/store_secret.sh generate LIVEKIT-API-KEY "API" 12)"
LIVEKIT_API_SECRET="$(/usr/local/bin/store_secret.sh generate LIVEKIT-API-SECRET)"
ENABLED_MODULES="$(/usr/local/bin/store_secret.sh save ENABLED-MODULES "observability,app")"
# Base command
INSTALL_COMMAND="sh <(curl -fsSL http://get.openvidu.io/community/singlenode/$OPENVIDU_VERSION/install.sh)"
# Common arguments
COMMON_ARGS=(
"--no-tty"
"--install"
"--environment=azure"
"--deployment-type=single_node"
"--domain-name=$DOMAIN"
"--enabled-modules='$ENABLED_MODULES'"
"--redis-password=$REDIS_PASSWORD"
"--mongo-admin-user=$MONGO_ADMIN_USERNAME"
"--mongo-admin-password=$MONGO_ADMIN_PASSWORD"
"--mongo-replica-set-key=$MONGO_REPLICA_SET_KEY"
"--minio-access-key=$MINIO_ACCESS_KEY"
"--minio-secret-key=$MINIO_SECRET_KEY"
"--dashboard-admin-user=$DASHBOARD_ADMIN_USERNAME"
"--dashboard-admin-password=$DASHBOARD_ADMIN_PASSWORD"
"--grafana-admin-user=$GRAFANA_ADMIN_USERNAME"
"--grafana-admin-password=$GRAFANA_ADMIN_PASSWORD"
"--default-app-user=$DEFAULT_APP_USERNAME"
"--default-app-password=$DEFAULT_APP_PASSWORD"
"--default-app-admin-user=$DEFAULT_APP_ADMIN_USERNAME"
"--default-app-admin-password=$DEFAULT_APP_ADMIN_PASSWORD"
"--livekit-api-key=$LIVEKIT_API_KEY"
"--livekit-api-secret=$LIVEKIT_API_SECRET"
)
# Turn with TLS
if [[ "${turnDomainName}" != '' ]]; then
LIVEKIT_TURN_DOMAIN_NAME=$(/usr/local/bin/store_secret.sh save LIVEKIT-TURN-DOMAIN-NAME "${turnDomainName}")
COMMON_ARGS+=(
"--turn-domain-name=$LIVEKIT_TURN_DOMAIN_NAME"
)
fi
# Certificate arguments
if [[ "${certificateType}" == "selfsigned" ]]; then
CERT_ARGS=(
"--certificate-type=selfsigned"
)
elif [[ "${certificateType}" == "letsencrypt" ]]; then
LETSENCRYPT_EMAIL=$(/usr/local/bin/store_secret.sh save LETSENCRYPT-EMAIL "${letsEncryptEmail}")
CERT_ARGS=(
"--certificate-type=letsencrypt"
"--letsencrypt-email=${letsEncryptEmail}"
)
else
# Download owncert files
mkdir -p /tmp/owncert
wget -O /tmp/owncert/fullchain.pem ${ownPublicCertificate}
wget -O /tmp/owncert/privkey.pem ${ownPrivateCertificate}
# Convert to base64
OWN_CERT_CRT=$(base64 -w 0 /tmp/owncert/fullchain.pem)
OWN_CERT_KEY=$(base64 -w 0 /tmp/owncert/privkey.pem)
CERT_ARGS=(
"--certificate-type=owncert"
"--owncert-public-key=$OWN_CERT_CRT"
"--owncert-private-key=$OWN_CERT_KEY"
)
# Turn with TLS and own certificate
if [[ "${turnDomainName}" != '' ]]; then
# Download owncert files
mkdir -p /tmp/owncert-turn
wget -O /tmp/owncert-turn/fullchain.pem ${turnOwnPublicCertificate}
wget -O /tmp/owncert-turn/privkey.pem ${turnOwnPrivateCertificate}
# Convert to base64
OWN_CERT_CRT_TURN=$(base64 -w 0 /tmp/owncert-turn/fullchain.pem)
OWN_CERT_KEY_TURN=$(base64 -w 0 /tmp/owncert-turn/privkey.pem)
CERT_ARGS+=(
"--turn-owncert-private-key=$OWN_CERT_KEY_TURN"
"--turn-owncert-public-key=$OWN_CERT_CRT_TURN"
)
fi
fi
# Construct the final command with all arguments
FINAL_COMMAND="$INSTALL_COMMAND $(printf "%s " "${COMMON_ARGS[@]}") $(printf "%s " "${CERT_ARGS[@]}")"
# Install OpenVidu
exec bash -c "$FINAL_COMMAND"
'''
//DONE
var after_installScriptTemplate = '''
#!/bin/bash
set -e
az login --identity --allow-no-subscriptions > /dev/null
# Generate URLs
DOMAIN=$(az keyvault secret show --vault-name ${keyVaultName} --name DOMAIN-NAME --query value -o tsv)
DASHBOARD_URL="https://${DOMAIN}/dashboard/"
GRAFANA_URL="https://${DOMAIN}/grafana/"
MINIO_URL="https://${DOMAIN}/minio-console/"
# Update shared secret
az keyvault secret set --vault-name ${keyVaultName} --name DOMAIN-NAME --value $DOMAIN
az keyvault secret set --vault-name ${keyVaultName} --name DASHBOARD-URL --value $DASHBOARD_URL
az keyvault secret set --vault-name ${keyVaultName} --name GRAFANA-URL --value $GRAFANA_URL
az keyvault secret set --vault-name ${keyVaultName} --name MINIO-URL --value $MINIO_URL
az keyvault secret show --vault-name ${keyVaultName} --name MINIO-URL
if [[ $? -ne 0 ]]; then
echo "Error updating keyvault"
fi
'''
//DONE
var update_config_from_secretScriptTemplate = '''
#!/bin/bash -x
set -e
az login --identity --allow-no-subscriptions > /dev/null
# Installation directory
INSTALL_DIR="/opt/openvidu"
CONFIG_DIR="${INSTALL_DIR}/config"
# Replace DOMAIN_NAME
export DOMAIN=$(az keyvault secret show --vault-name ${keyVaultName} --name DOMAIN-NAME --query value -o tsv)
if [[ -n "$DOMAIN" ]]; then
sed -i "s/DOMAIN_NAME=.*/DOMAIN_NAME=$DOMAIN/" "${CONFIG_DIR}/openvidu.env"
else
exit 1
fi
# Replace LIVEKIT_TURN_DOMAIN_NAME
export LIVEKIT_TURN_DOMAIN_NAME=$(az keyvault secret show --vault-name ${keyVaultName} --name LIVEKIT-TURN-DOMAIN-NAME --query value -o tsv)
if [[ -n "$LIVEKIT_TURN_DOMAIN_NAME" ]]; then
sed -i "s/LIVEKIT_TURN_DOMAIN_NAME=.*/LIVEKIT_TURN_DOMAIN_NAME=$LIVEKIT_TURN_DOMAIN_NAME/" "${CONFIG_DIR}/openvidu.env"
fi
if [[ ${certificateType} == "letsencrypt" ]]; then
export LETSENCRYPT_EMAIL=$(az keyvault secret show --vault-name ${keyVaultName} --name LETSENCRYPT-EMAIL --query value -o tsv)
sed -i "s/LETSENCRYPT_EMAIL=.*/LETSENCRYPT_EMAIL=$LETSENCRYPT_EMAIL/" "${CONFIG_DIR}/openvidu.env"
fi
# Get the rest of the values
export REDIS_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name REDIS-PASSWORD --query value -o tsv)
export MONGO_ADMIN_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name MONGO-ADMIN-USERNAME --query value -o tsv)
export MONGO_ADMIN_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name MONGO-ADMIN-PASSWORD --query value -o tsv)
export MONGO_REPLICA_SET_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name MONGO-REPLICA-SET-KEY --query value -o tsv)
export DASHBOARD_ADMIN_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name DASHBOARD-ADMIN-USERNAME --query value -o tsv)
export DASHBOARD_ADMIN_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name DASHBOARD-ADMIN-PASSWORD --query value -o tsv)
export MINIO_ACCESS_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name MINIO-ACCESS-KEY --query value -o tsv)
export MINIO_SECRET_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name MINIO-SECRET-KEY --query value -o tsv)
export GRAFANA_ADMIN_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name GRAFANA-ADMIN-USERNAME --query value -o tsv)
export GRAFANA_ADMIN_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name GRAFANA-ADMIN-PASSWORD --query value -o tsv)
export LIVEKIT_API_KEY=$(az keyvault secret show --vault-name ${keyVaultName} --name LIVEKIT-API-KEY --query value -o tsv)
export LIVEKIT_API_SECRET=$(az keyvault secret show --vault-name ${keyVaultName} --name LIVEKIT-API-SECRET --query value -o tsv)
export DEFAULT_APP_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name DEFAULT-APP-USERNAME --query value -o tsv)
export DEFAULT_APP_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name DEFAULT-APP-PASSWORD --query value -o tsv)
export DEFAULT_APP_ADMIN_USERNAME=$(az keyvault secret show --vault-name ${keyVaultName} --name DEFAULT-APP-ADMIN-USERNAME --query value -o tsv)
export DEFAULT_APP_ADMIN_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name DEFAULT-APP-ADMIN-PASSWORD --query value -o tsv)
export ENABLED_MODULES=$(az keyvault secret show --vault-name ${keyVaultName} --name ENABLED-MODULES --query value -o tsv)
# Replace rest of the values
sed -i "s/REDIS_PASSWORD=.*/REDIS_PASSWORD=$REDIS_PASSWORD/" "${CONFIG_DIR}/openvidu.env"
sed -i "s/MONGO_ADMIN_USERNAME=.*/MONGO_ADMIN_USERNAME=$MONGO_ADMIN_USERNAME/" "${CONFIG_DIR}/openvidu.env"
sed -i "s/MONGO_ADMIN_PASSWORD=.*/MONGO_ADMIN_PASSWORD=$MONGO_ADMIN_PASSWORD/" "${CONFIG_DIR}/openvidu.env"
sed -i "s/MONGO_REPLICA_SET_KEY=.*/MONGO_REPLICA_SET_KEY=$MONGO_REPLICA_SET_KEY/" "${CONFIG_DIR}/openvidu.env"
sed -i "s/DASHBOARD_ADMIN_USERNAME=.*/DASHBOARD_ADMIN_USERNAME=$DASHBOARD_ADMIN_USERNAME/" "${CONFIG_DIR}/openvidu.env"
sed -i "s/DASHBOARD_ADMIN_PASSWORD=.*/DASHBOARD_ADMIN_PASSWORD=$DASHBOARD_ADMIN_PASSWORD/" "${CONFIG_DIR}/openvidu.env"
sed -i "s/MINIO_ACCESS_KEY=.*/MINIO_ACCESS_KEY=$MINIO_ACCESS_KEY/" "${CONFIG_DIR}/openvidu.env"
sed -i "s/MINIO_SECRET_KEY=.*/MINIO_SECRET_KEY=$MINIO_SECRET_KEY/" "${CONFIG_DIR}/openvidu.env"
sed -i "s/GRAFANA_ADMIN_USERNAME=.*/GRAFANA_ADMIN_USERNAME=$GRAFANA_ADMIN_USERNAME/" "${CONFIG_DIR}/openvidu.env"
sed -i "s/GRAFANA_ADMIN_PASSWORD=.*/GRAFANA_ADMIN_PASSWORD=$GRAFANA_ADMIN_PASSWORD/" "${CONFIG_DIR}/openvidu.env"
sed -i "s/LIVEKIT_API_KEY=.*/LIVEKIT_API_KEY=$LIVEKIT_API_KEY/" "${CONFIG_DIR}/openvidu.env"
sed -i "s/LIVEKIT_API_SECRET=.*/LIVEKIT_API_SECRET=$LIVEKIT_API_SECRET/" "${CONFIG_DIR}/openvidu.env"
sed -i "s/CALL_USER=.*/CALL_USER=$DEFAULT_APP_USERNAME/" "${CONFIG_DIR}/app.env"
sed -i "s/CALL_SECRET=.*/CALL_SECRET=$DEFAULT_APP_PASSWORD/" "${CONFIG_DIR}/app.env"
sed -i "s/CALL_ADMIN_USER=.*/CALL_ADMIN_USER=$DEFAULT_APP_ADMIN_USERNAME/" "${CONFIG_DIR}/app.env"
sed -i "s/CALL_ADMIN_SECRET=.*/CALL_ADMIN_SECRET=$DEFAULT_APP_ADMIN_PASSWORD/" "${CONFIG_DIR}/app.env"
sed -i "s/ENABLED_MODULES=.*/ENABLED_MODULES=$ENABLED_MODULES/" "${CONFIG_DIR}/openvidu.env"
# Update URLs in secret
DASHBOARD_URL="https://${DOMAIN}/dashboard/"
GRAFANA_URL="https://${DOMAIN}/grafana/"
MINIO_URL="https://${DOMAIN}/minio-console/"
# Update shared secret
az keyvault secret set --vault-name ${keyVaultName} --name DOMAIN-NAME --value $DOMAIN
az keyvault secret set --vault-name ${keyVaultName} --name DASHBOARD-URL --value $DASHBOARD_URL
az keyvault secret set --vault-name ${keyVaultName} --name GRAFANA-URL --value $GRAFANA_URL
az keyvault secret set --vault-name ${keyVaultName} --name MINIO-URL --value $MINIO_URL
'''
//DONE
var update_secret_from_configScriptTemplate = '''
#!/bin/bash
set -e
az login --identity --allow-no-subscriptions > /dev/null
# Installation directory
INSTALL_DIR="/opt/openvidu"
CONFIG_DIR="${INSTALL_DIR}/config"
if [[ ${certificateType} == "letsencrypt" ]]; then
LETSENCRYPT_EMAIL="$(/usr/local/bin/get_value_from_config.sh LETSENCRYPT_EMAIL "${CONFIG_DIR}/openvidu.env")"
az keyvault secret set --vault-name ${keyVaultName} --name "LETSENCRYPT-EMAIL" --value $LETSENCRYPT_EMAIL
fi
# Get current values of the config
REDIS_PASSWORD="$(/usr/local/bin/get_value_from_config.sh REDIS_PASSWORD "${CONFIG_DIR}/openvidu.env")"
DOMAIN_NAME="$(/usr/local/bin/get_value_from_config.sh DOMAIN_NAME "${CONFIG_DIR}/openvidu.env")"
LIVEKIT_TURN_DOMAIN_NAME="$(/usr/local/bin/get_value_from_config.sh LIVEKIT_TURN_DOMAIN_NAME "${CONFIG_DIR}/openvidu.env")"
MONGO_ADMIN_USERNAME="$(/usr/local/bin/get_value_from_config.sh MONGO_ADMIN_USERNAME "${CONFIG_DIR}/openvidu.env")"
MONGO_ADMIN_PASSWORD="$(/usr/local/bin/get_value_from_config.sh MONGO_ADMIN_PASSWORD "${CONFIG_DIR}/openvidu.env")"
MONGO_REPLICA_SET_KEY="$(/usr/local/bin/get_value_from_config.sh MONGO_REPLICA_SET_KEY "${CONFIG_DIR}/openvidu.env")"
MINIO_ACCESS_KEY="$(/usr/local/bin/get_value_from_config.sh MINIO_ACCESS_KEY "${CONFIG_DIR}/openvidu.env")"
MINIO_SECRET_KEY="$(/usr/local/bin/get_value_from_config.sh MINIO_SECRET_KEY "${CONFIG_DIR}/openvidu.env")"
DASHBOARD_ADMIN_USERNAME="$(/usr/local/bin/get_value_from_config.sh DASHBOARD_ADMIN_USERNAME "${CONFIG_DIR}/openvidu.env")"
DASHBOARD_ADMIN_PASSWORD="$(/usr/local/bin/get_value_from_config.sh DASHBOARD_ADMIN_PASSWORD "${CONFIG_DIR}/openvidu.env")"
GRAFANA_ADMIN_USERNAME="$(/usr/local/bin/get_value_from_config.sh GRAFANA_ADMIN_USERNAME "${CONFIG_DIR}/openvidu.env")"
GRAFANA_ADMIN_PASSWORD="$(/usr/local/bin/get_value_from_config.sh GRAFANA_ADMIN_PASSWORD "${CONFIG_DIR}/openvidu.env")"
LIVEKIT_API_KEY="$(/usr/local/bin/get_value_from_config.sh LIVEKIT_API_KEY "${CONFIG_DIR}/openvidu.env")"
LIVEKIT_API_SECRET="$(/usr/local/bin/get_value_from_config.sh LIVEKIT_API_SECRET "${CONFIG_DIR}/openvidu.env")"
DEFAULT_APP_USERNAME="$(/usr/local/bin/get_value_from_config.sh CALL_USER "${CONFIG_DIR}/app.env")"
DEFAULT_APP_PASSWORD="$(/usr/local/bin/get_value_from_config.sh CALL_SECRET "${CONFIG_DIR}/app.env")"
DEFAULT_APP_ADMIN_USERNAME="$(/usr/local/bin/get_value_from_config.sh CALL_ADMIN_USER "${CONFIG_DIR}/app.env")"
DEFAULT_APP_ADMIN_PASSWORD="$(/usr/local/bin/get_value_from_config.sh CALL_ADMIN_SECRET "${CONFIG_DIR}/app.env")"
ENABLED_MODULES="$(/usr/local/bin/get_value_from_config.sh ENABLED_MODULES "${CONFIG_DIR}/openvidu.env")"
# Update shared secret
az keyvault secret set --vault-name ${keyVaultName} --name REDIS-PASSWORD --value $REDIS_PASSWORD
az keyvault secret set --vault-name ${keyVaultName} --name DOMAIN-NAME --value $DOMAIN_NAME
az keyvault secret set --vault-name ${keyVaultName} --name LIVEKIT-TURN-DOMAIN-NAME --value $LIVEKIT_TURN_DOMAIN_NAME
az keyvault secret set --vault-name ${keyVaultName} --name MONGO-ADMIN-USERNAME --value $MONGO_ADMIN_USERNAME
az keyvault secret set --vault-name ${keyVaultName} --name MONGO-ADMIN-PASSWORD --value $MONGO_ADMIN_PASSWORD
az keyvault secret set --vault-name ${keyVaultName} --name MONGO-REPLICA-SET-KEY --value $MONGO_REPLICA_SET_KEY
az keyvault secret set --vault-name ${keyVaultName} --name MINIO-ACCESS-KEY --value $MINIO_ACCESS_KEY
az keyvault secret set --vault-name ${keyVaultName} --name MINIO-SECRET-KEY --value $MINIO_SECRET_KEY
az keyvault secret set --vault-name ${keyVaultName} --name DASHBOARD-ADMIN-USERNAME --value $DASHBOARD_ADMIN_USERNAME
az keyvault secret set --vault-name ${keyVaultName} --name DASHBOARD-ADMIN-PASSWORD --value $DASHBOARD_ADMIN_PASSWORD
az keyvault secret set --vault-name ${keyVaultName} --name GRAFANA-ADMIN-USERNAME --value $GRAFANA_ADMIN_USERNAME
az keyvault secret set --vault-name ${keyVaultName} --name GRAFANA-ADMIN-PASSWORD --value $GRAFANA_ADMIN_PASSWORD
az keyvault secret set --vault-name ${keyVaultName} --name LIVEKIT-API-KEY --value $LIVEKIT_API_KEY
az keyvault secret set --vault-name ${keyVaultName} --name LIVEKIT-API-SECRET --value $LIVEKIT_API_SECRET
az keyvault secret set --vault-name ${keyVaultName} --name DEFAULT-APP-USERNAME --value $DEFAULT_APP_USERNAME
az keyvault secret set --vault-name ${keyVaultName} --name DEFAULT-APP-PASSWORD --value $DEFAULT_APP_PASSWORD
az keyvault secret set --vault-name ${keyVaultName} --name DEFAULT-APP-ADMIN-USERNAME --value $DEFAULT_APP_ADMIN_USERNAME
az keyvault secret set --vault-name ${keyVaultName} --name DEFAULT-APP-ADMIN-PASSWORD --value $DEFAULT_APP_ADMIN_PASSWORD
az keyvault secret set --vault-name ${keyVaultName} --name ENABLED-MODULES --value $ENABLED_MODULES
'''
//DONE
var get_value_from_configScript = '''
#!/bin/bash -x
set -e
# Function to get the value of a given key from the environment file
get_value() {
local key="$1"
local file_path="$2"
# Use grep to find the line with the key, ignoring lines starting with #
# Use awk to split on '=' and print the second field, which is the value
local value=$(grep -E "^\s*$key\s*=" "$file_path" | awk -F= '{print $2}' | sed 's/#.*//; s/^\s*//; s/\s*$//')
# If the value is empty, return "none"
if [ -z "$value" ]; then
echo "none"
else
echo "$value"
fi
}
# Check if the correct number of arguments are supplied
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <key> <file_path>"
exit 1
fi
# Get the key and file path from the arguments
key="$1"
file_path="$2"
# Get and print the value
get_value "$key" "$file_path"
'''
//DONE
var store_secretScriptTemplate = '''
#!/bin/bash
set -e
az login --identity --allow-no-subscriptions > /dev/null
# Modes: save, generate
# save mode: save the secret in the secret manager
# generate mode: generate a random password and save it in the secret manager
MODE="$1"
if [[ "$MODE" == "generate" ]]; then
SECRET_KEY_NAME="$2"
PREFIX="${3:-}"
LENGTH="${4:-44}"
RANDOM_PASSWORD="$(openssl rand -base64 64 | tr -d '+/=\n' | cut -c -${LENGTH})"
RANDOM_PASSWORD="${PREFIX}${RANDOM_PASSWORD}"
az keyvault secret set --vault-name ${keyVaultName} --name $SECRET_KEY_NAME --value $RANDOM_PASSWORD > /dev/null
if [[ $? -ne 0 ]]; then
echo "Error generating secret"
fi
echo "$RANDOM_PASSWORD"
elif [[ "$MODE" == "save" ]]; then
SECRET_KEY_NAME="$2"
SECRET_VALUE="$3"
az keyvault secret set --vault-name ${keyVaultName} --name $SECRET_KEY_NAME --value $SECRET_VALUE > /dev/null
if [[ $? -ne 0 ]]; then
echo "Error generating secret"
fi
echo "$SECRET_VALUE"
else
exit 1
fi
'''
var check_app_ready = '''
#!/bin/bash
while true; do
HTTP_STATUS=$(curl -Ik http://localhost:7880 | head -n1 | awk '{print $2}')
if [ $HTTP_STATUS == 200 ]; then
break
fi
sleep 5
done
'''
var restart = '''
#!/bin/bash -x
set -e
# Stop all services
systemctl stop openvidu
# Update config from secret
/usr/local/bin/update_config_from_secret.sh
# Start all services
systemctl start openvidu
'''
var config_blobStorageTemplate = '''
#!/bin/bash
set -e
# Install dir and config dir
INSTALL_DIR="/opt/openvidu"
CONFIG_DIR="${INSTALL_DIR}/config"
az login --identity
# Config azure blob storage
EXTERNAL_S3_ACCOUNT_NAME="${storageAccountName}"
EXTERNAL_S3_ACCOUNT_KEY=$(az storage account keys list --account-name ${storageAccountName} --query '[0].value' -o tsv)
EXTERNAL_S3_CONTAINER_NAME="${storageAccountContainerName}"
sed -i "s|EXTERNAL_S3_ACCOUNT_NAME=.*|EXTERNAL_S3_ACCOUNT_NAME=$EXTERNAL_S3_ACCOUNT_NAME|" "${CONFIG_DIR}/openvidu.env"
sed -i "s|EXTERNAL_S3_ACCOUNT_KEY=.*|EXTERNAL_S3_ACCOUNT_KEY=$EXTERNAL_S3_ACCOUNT_KEY|" "${CONFIG_DIR}/openvidu.env"
sed -i "s|EXTERNAL_S3_CONTAINER_NAME=.*|EXTERNAL_S3_CONTAINER_NAME=$EXTERNAL_S3_CONTAINER_NAME|" "${CONFIG_DIR}/openvidu.env"
'''
var formattedTemplateInstallScript = reduce(
items(stringInterpolationParams),
{ value: installScriptTemplate },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var after_installScriptMaster = reduce(
items(stringInterpolationParams),
{ value: after_installScriptTemplate },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var update_config_from_secretScript = reduce(
items(stringInterpolationParams),
{ value: update_config_from_secretScriptTemplate },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var update_secret_from_configScript = reduce(
items(stringInterpolationParams),
{ value: update_secret_from_configScriptTemplate },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var store_secretScript = reduce(
items(stringInterpolationParams),
{ value: store_secretScriptTemplate },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var blobStorageParams = {
storageAccountName: storageAccount.name
storageAccountKey: listKeys(storageAccount.id, '2021-04-01').keys[0].value
storageAccountContainerName: isEmptyContainerName ? 'openvidu-appdata' : '${containerName}'
}
var config_blobStorageScript = reduce(
items(blobStorageParams),
{ value: config_blobStorageTemplate },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
var base64install = base64(formattedTemplateInstallScript)
var base64after_install = base64(after_installScriptMaster)
var base64update_config_from_secret = base64(update_config_from_secretScript)
var base64update_secret_from_config = base64(update_secret_from_configScript)
var base64get_value_from_config = base64(get_value_from_configScript)
var base64store_secret = base64(store_secretScript)
var base64check_app_ready = base64(check_app_ready)
var base64restart = base64(restart)
var base64config_blobStorage = base64(config_blobStorageScript)
var userDataParams = {
base64install: base64install
base64after_install: base64after_install
base64update_config_from_secret: base64update_config_from_secret
base64update_secret_from_config: base64update_secret_from_config
base64get_value_from_config: base64get_value_from_config
base64store_secret: base64store_secret
base64check_app_ready: base64check_app_ready
base64restart: base64restart
base64config_blobStorage: base64config_blobStorage
}
var userDataTemplate = '''
#!/bin/bash -x
set -eu -o pipefail
echo ${base64install} | base64 -d > /usr/local/bin/install.sh
chmod +x /usr/local/bin/install.sh
# after_install.sh
echo ${base64after_install} | base64 -d > /usr/local/bin/after_install.sh
chmod +x /usr/local/bin/after_install.sh
# update_config_from_secret.sh
echo ${base64update_config_from_secret} | base64 -d > /usr/local/bin/update_config_from_secret.sh
chmod +x /usr/local/bin/update_config_from_secret.sh
# update_secret_from_config.sh
echo ${base64update_secret_from_config} | base64 -d > /usr/local/bin/update_secret_from_config.sh
chmod +x /usr/local/bin/update_secret_from_config.sh
# get_value_from_config.sh
echo ${base64get_value_from_config} | base64 -d > /usr/local/bin/get_value_from_config.sh
chmod +x /usr/local/bin/get_value_from_config.sh
# store_secret.sh
echo ${base64store_secret} | base64 -d > /usr/local/bin/store_secret.sh
chmod +x /usr/local/bin/store_secret.sh
echo ${base64check_app_ready} | base64 -d > /usr/local/bin/check_app_ready.sh
chmod +x /usr/local/bin/check_app_ready.sh
echo ${base64restart} | base64 -d > /usr/local/bin/restart.sh
chmod +x /usr/local/bin/restart.sh
echo ${base64config_blobStorage} | base64 -d > /usr/local/bin/config_blobStorage.sh
chmod +x /usr/local/bin/config_blobStorage.sh
# Install azure cli
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
az login --identity --allow-no-subscriptions
apt-get update && apt-get install -y
export HOME="/root"
# Install OpenVidu
/usr/local/bin/install.sh || { echo "[OpenVidu] error installing OpenVidu"; exit 1; }
#Config blob storage
/usr/local/bin/config_blobStorage.sh || { echo "[OpenVidu] error configuring Blob Storage"; exit 1; }
# Start OpenVidu
systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; exit 1; }
# Update shared secret
/usr/local/bin/after_install.sh || { echo "[OpenVidu] error updating shared secret"; exit 1; }
# Launch on reboot
echo "@reboot /usr/local/bin/restart.sh >> /var/log/openvidu-restart.log" 2>&1 | crontab
# Wait for the app
/usr/local/bin/check_app_ready.sh
'''
var userData = reduce(
items(userDataParams),
{ value: userDataTemplate },
(curr, next) => { value: replace(curr.value, '\${${next.key}}', next.value) }
).value
resource openviduServer 'Microsoft.Compute/virtualMachines@2023-09-01' = {
name: openviduVMSettings.vmName
location: location
identity: { type: 'SystemAssigned' }
properties: {
hardwareProfile: {
vmSize: instanceType
}
storageProfile: {
osDisk: {
createOption: 'FromImage'
managedDisk: {
storageAccountType: openviduVMSettings.osDiskType
}
diskSizeGB: 100
}
imageReference: openviduVMSettings.ubuntuOSVersion
}
networkProfile: {
networkInterfaces: [
{
id: netInterface_OV.id
}
]
}
osProfile: {
computerName: openviduVMSettings.vmName
adminUsername: adminUsername
adminPassword: adminSshKey
linuxConfiguration: openviduVMSettings.linuxConfiguration
}
userData: base64(userData)
}
}
/*------------------------------------------- NETWORK -------------------------------------------*/
//Create publicIPAddress if convinient
resource publicIP_OV 'Microsoft.Network/publicIPAddresses@2023-11-01' = if (isEmptyIp == true) {
name: '${stackName}-publicIP'
location: location
sku: {
name: 'Standard'
tier: 'Regional'
}
properties: {
publicIPAddressVersion: 'IPv4'
publicIPAllocationMethod: 'Static'
dnsSettings: {
domainNameLabel: isEmptyDomain ? toLower('${stackName}') : null
fqdn: isEmptyDomain ? null : domainName
}
}
}
resource publicIP_OV_ifNotEmpty 'Microsoft.Network/publicIPAddresses@2023-11-01' existing = if (!isEmptyIp == true) {
name: publicIpAddressResourceName
}
// Create the virtual network
resource vnet_OV 'Microsoft.Network/virtualNetworks@2023-11-01' = {
name: networkSettings.vNetName
location: location
properties: {
addressSpace: {
addressPrefixes: [
networkSettings.vNetAddressPrefix
]
}
subnets: [
{
name: networkSettings.subnetName
properties: {
addressPrefix: networkSettings.subnetAddressPrefix
privateEndpointNetworkPolicies: 'Disabled'
privateLinkServiceNetworkPolicies: 'Enabled'
networkSecurityGroup: {
id: webServerSecurityGroup.id
}
}
}
]
}
}
resource netInterface_OV 'Microsoft.Network/networkInterfaces@2023-11-01' = {
name: networkSettings.netInterfaceName
location: location
properties: {
ipConfigurations: [
{
name: 'ipconfig1'
properties: {
privateIPAllocationMethod: 'Dynamic'
subnet: {
id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet_OV.name, networkSettings.subnetName)
}
publicIPAddress: {
id: isEmptyIp ? publicIP_OV.id : publicIP_OV_ifNotEmpty.id
}
}
}
]
networkSecurityGroup: {
id: webServerSecurityGroup.id
}
}
}
// SecurityGroup for OpenviduSN
resource webServerSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-11-01' = {
name: '${stackName}-nsg'
location: location
properties: {
securityRules: [
{
name: 'SSH'
properties: {
protocol: 'Tcp'
sourceAddressPrefix: '*'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '22'
access: 'Allow'
priority: 100
direction: 'Inbound'
}
}
{
name: 'HTTP'
properties: {
protocol: 'Tcp'
sourceAddressPrefix: '*'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '80'
access: 'Allow'
priority: 110
direction: 'Inbound'
}
}
{
name: 'HTTPS'
properties: {
protocol: 'Tcp'
sourceAddressPrefix: '*'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '443'
access: 'Allow'
priority: 120
direction: 'Inbound'
}
}
{
name: 'TURN'
properties: {
protocol: 'Udp'
sourceAddressPrefix: '*'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '443'
access: 'Allow'
priority: 130
direction: 'Inbound'
}
}
{
name: 'RTMP'
properties: {
protocol: 'Tcp'
sourceAddressPrefix: '*'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '1935'
access: 'Allow'
priority: 140
direction: 'Inbound'
}
}
{
name: 'WebRTC_over_TCP'
properties: {
protocol: 'Tcp'
sourceAddressPrefix: '*'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '7881'
access: 'Allow'
priority: 150
direction: 'Inbound'
}
}
{
name: 'WebRTC_using_WHIP'
properties: {
protocol: 'Udp'
sourceAddressPrefix: '*'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '7885'
access: 'Allow'
priority: 160
direction: 'Inbound'
}
}
{
name: 'MinIO'
properties: {
protocol: 'Tcp'
sourceAddressPrefix: '*'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '9000'
access: 'Allow'
priority: 170
direction: 'Inbound'
}
}
{
name: 'WebRTC_traffic_UDP'
properties: {
protocol: 'Udp'
sourceAddressPrefix: '*'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRanges: [
'50000'
'60000'
]
access: 'Allow'
priority: 180
direction: 'Inbound'
}
}
{
name: 'WebRTC_traffic_TCP'
properties: {
protocol: 'Tcp'
sourceAddressPrefix: '*'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRanges: [
'50000'
'60000'
]
access: 'Allow'
priority: 190
direction: 'Inbound'
}
}
]
}
}
/*------------------------------------------- STORAGE ACCOUNT ----------------------------------------*/
@description('Name of the bucket where OpenVidu will store the recordings. If not specified, a default bucket will be created.')
param containerName string = ''
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: uniqueString(resourceGroup().id)
location: resourceGroup().location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
accessTier: 'Cool'
supportsHttpsTrafficOnly: true
}
}
var isEmptyContainerName = containerName == ''
resource blobContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = {
name: isEmptyContainerName
? '${storageAccount.name}/default/openvidu-appdata'
: '${storageAccount.name}/default/${containerName}'
properties: {
publicAccess: 'None'
}
}
/*------------------------------------------- OUTPUTS -------------------------------------------*/
output ipValidationStatus string = isValidIP ? 'IP address is valid' : 'IP address not valid'
output domainValidationStatus string = isDomainValid ? 'Domain is valid' : 'Domain is not valid'
//Condition if owncert is selected
output ownCertValidationStatus string = (certificateType == 'owncert' && ownPrivateCertificate != '' && ownPublicCertificate != '')
? 'owncert selected and valid'
: 'You need to fill \'Own Public Certificate\' and \'Own Private Certificate\''
//Condition if letsEncrypt is selected
output letsEncryptValidationStatus string = (certificateType == 'letsencrypt' && letsEncryptEmail != '')
? 'letsEncrypt selected and valid'
: 'You need to fill \'Lets Encrypt Email\''