@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' } } } /*------------------------------------------- MASTER 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 " 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 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 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 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 } 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 # 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; } # 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' } } ] } } /*------------------------------------------- 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\''