{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "metadata": { "description": "Deploys a Linux VM running a Zato environment from a git repository in a Docker container." }, "parameters": { "vmName": { "type": "string", "defaultValue": "zato", "metadata": { "description": "Name of the virtual machine." } }, "vmSize": { "type": "string", "defaultValue": "Standard_D2lds_v6", "metadata": { "description": "Size of the virtual machine. Sizes with a local NVMe disk give the best Docker performance." } }, "adminUsername": { "type": "string", "defaultValue": "azureuser", "metadata": { "description": "Administrator user name for SSH access to the host." } }, "authenticationType": { "type": "string", "defaultValue": "sshPublicKey", "allowedValues": [ "sshPublicKey", "password" ], "metadata": { "description": "How the administrator authenticates over SSH to the host." } }, "adminPasswordOrKey": { "type": "securestring", "metadata": { "description": "SSH public key or password for the administrator account." } }, "zatoPassword": { "type": "securestring", "metadata": { "description": "Password for the Zato Dashboard user." } }, "installUpdates": { "type": "string", "defaultValue": "True", "allowedValues": [ "True", "False" ], "metadata": { "description": "Whether to pull the latest Zato image on each boot." } }, "envRepoUrl": { "type": "string", "defaultValue": "", "metadata": { "description": "SSH address of the git repository with the environment, such as git@github.com:owner/name.git. Leave it empty to run the public Zato blueprint, which you can switch to your own repository from the Dashboard later." } }, "envRepoBranch": { "type": "string", "defaultValue": "main", "metadata": { "description": "Branch of the environment repository." } }, "envRepoDeployKey": { "type": "securestring", "defaultValue": "", "metadata": { "description": "Private SSH key with read access to the environment repository. Leave it empty if the repository is public or not given." } }, "envSecrets": { "type": "securestring", "defaultValue": "", "metadata": { "description": "Secrets for the environment, one key=value per line, which enmasse reads from env.ini. Secrets of the same name in the Key Vault take precedence." } }, "useKeyVault": { "type": "string", "defaultValue": "False", "allowedValues": [ "True", "False" ], "metadata": { "description": "Whether to create a Key Vault that the virtual machine reads the secrets of the environment from on each start. A secret named My-API-Password in the vault becomes My_API_Password in env.ini." } }, "allowedSourceAddresses": { "type": "array", "defaultValue": [ "0.0.0.0/0" ], "metadata": { "description": "Source IP addresses or CIDR ranges allowed to reach the VM, given as a list. Use your own addresses rather than the default of 0.0.0.0/0, which is the whole internet." } }, "extraPorts": { "type": "array", "defaultValue": [], "metadata": { "description": "Ports to open in addition to SSH, the Dashboard and the load balancer. Add 11553 for HL7 over MLLP, 22022 for SSH into the container." } }, "osDiskSizeGB": { "type": "int", "defaultValue": 64, "minValue": 30, "maxValue": 1023, "metadata": { "description": "Size of the OS disk in GB. Larger disks are given more IOPS by Azure." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Region to deploy into." } }, "dnsSuffix": { "type": "string", "defaultValue": "[newGuid()]", "metadata": { "description": "Random part of the DNS name of the VM, drawn once when the deployment form opens. Leave it as it is." } } }, "variables": { "vnetName": "[concat(parameters('vmName'), '-vnet')]", "subnetName": "default", "nsgName": "[concat(parameters('vmName'), '-nsg')]", "nicName": "[concat(parameters('vmName'), '-nic')]", "publicIpName": "[concat(parameters('vmName'), '-ip')]", "dnsLabel": "[concat(parameters('vmName'), '-', substring(replace(parameters('dnsSuffix'), '-', ''), 0, 8))]", "fqdn": "[concat(variables('dnsLabel'), '.', toLower(replace(parameters('location'), ' ', '')), '.cloudapp.azure.com')]", "subnetRef": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('vnetName'), variables('subnetName'))]", "basePorts": [ "22", "8184", "11224" ], "openPorts": "[union(variables('basePorts'), parameters('extraPorts'))]", "linuxConfiguration": { "disablePasswordAuthentication": true, "ssh": { "publicKeys": [ { "path": "[concat('/home/', parameters('adminUsername'), '/.ssh/authorized_keys')]", "keyData": "[parameters('adminPasswordOrKey')]" } ] } }, "image": "zatosource/zato-4.1", "servingMarker": "/run/zato-deploy/serving", "deployFilesUrl": "https://raw.githubusercontent.com/zatosource/zato/refs/heads/main/cloud/deploy", "bootstrapPath": "/usr/local/bin/zato-deploy-bootstrap.sh", "useKeyVault": "[equals(parameters('useKeyVault'), 'True')]", "keyVaultName": "[concat('zato-', substring(replace(parameters('dnsSuffix'), '-', ''), 0, 16))]", "keyVaultSecretsUserRole": "4633458b-17de-408a-b874-0445c86b69e6", "keyVaultSecretsOfficerRole": "b86a8fe4-44ce-4948-aee5-eccb2c155cd7", "azureFilesUrl": "https://raw.githubusercontent.com/zatosource/zato/refs/heads/main/cloud/azure", "keyVaultScriptPath": "/usr/local/lib/zato-azure/key_vault_secrets.py", "cloudInitSecretsCommand": "[if(variables('useKeyVault'), concat(' - path: /etc/zato-deploy/secrets-command\n permissions: \"0700\"\n content: |\n #!/bin/sh\n exec /usr/bin/python3 ', variables('keyVaultScriptPath'), ' ', variables('keyVaultName'), '\n'), '')]", "cloudInitKeyVaultScript": "[if(variables('useKeyVault'), concat(' - curl -fsSL --retry 10 --retry-all-errors --create-dirs -o ', variables('keyVaultScriptPath'), ' ', variables('azureFilesUrl'), '/key_vault_secrets.py\n'), '')]", "cloudInitDeployEnv": "[concat(' - path: /etc/zato-deploy/deploy.env\n permissions: \"0600\"\n content: |\n fqdn=', variables('fqdn'), '\n admin_username=', parameters('adminUsername'), '\n image=', variables('image'), '\n')]", "cloudInitContainerEnv": "[concat(' - path: /etc/zato-deploy/container.env\n permissions: \"0600\"\n content: |\n Zato_Password=', parameters('zatoPassword'), '\n Zato_Use_Lets_Encrypt=True\n Zato_Install_Updates=', parameters('installUpdates'), '\n Zato_SSL_Subject_Alt_Name=subjectAltName=DNS:', variables('fqdn'), '\n Zato_Dashboard_CSRF_Trusted_Origins=https://', variables('fqdn'), ':8184\n')]", "cloudInitEnvRepo": "[concat(' - path: /etc/zato-deploy/env-repo.env\n permissions: \"0600\"\n content: |\n env_repo_url=', parameters('envRepoUrl'), '\n env_repo_branch=', parameters('envRepoBranch'), '\n')]", "cloudInitEnvSecrets": "[concat(' - path: /etc/zato-deploy/env-secrets.env\n permissions: \"0600\"\n encoding: b64\n content: ', base64(concat(parameters('envSecrets'), '\n')), '\n')]", "cloudInitEnvRepoKey": "[if(empty(parameters('envRepoDeployKey')), '', concat(' - path: /etc/zato-deploy/env-repo-key\n permissions: \"0600\"\n encoding: b64\n content: ', base64(concat(parameters('envRepoDeployKey'), '\n')), '\n'))]", "cloudInitRuncmd": "[concat('runcmd:\n - echo \"Zato - downloading the deployment program\" > /dev/ttyS0\n', variables('cloudInitKeyVaultScript'), ' - curl -fsSL --retry 10 --retry-all-errors -o ', variables('bootstrapPath'), ' ', variables('deployFilesUrl'), '/bootstrap.sh\n - chmod 0755 ', variables('bootstrapPath'), '\n - ', variables('bootstrapPath'), ' ', variables('deployFilesUrl'), '\n')]", "cloudInit": "[concat('#cloud-config\nwrite_files:\n', variables('cloudInitDeployEnv'), variables('cloudInitContainerEnv'), variables('cloudInitEnvRepo'), variables('cloudInitEnvSecrets'), variables('cloudInitSecretsCommand'), variables('cloudInitEnvRepoKey'), variables('cloudInitRuncmd'))]" }, "resources": [ { "type": "Microsoft.Network/networkSecurityGroups", "apiVersion": "2023-11-01", "name": "[variables('nsgName')]", "location": "[parameters('location')]", "properties": { "securityRules": [ { "name": "zato-inbound", "properties": { "priority": 300, "direction": "Inbound", "access": "Allow", "protocol": "Tcp", "sourceAddressPrefixes": "[parameters('allowedSourceAddresses')]", "sourcePortRange": "*", "destinationAddressPrefix": "*", "destinationPortRanges": "[variables('openPorts')]" } }, { "name": "lets-encrypt-inbound", "properties": { "priority": 310, "direction": "Inbound", "access": "Allow", "protocol": "Tcp", "sourceAddressPrefix": "Internet", "sourcePortRange": "*", "destinationAddressPrefix": "*", "destinationPortRange": "443" } } ] } }, { "type": "Microsoft.Network/virtualNetworks", "apiVersion": "2023-11-01", "name": "[variables('vnetName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('nsgName'))]" ], "properties": { "addressSpace": { "addressPrefixes": [ "10.0.0.0/16" ] }, "subnets": [ { "name": "[variables('subnetName')]", "properties": { "addressPrefix": "10.0.0.0/24", "networkSecurityGroup": { "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('nsgName'))]" } } } ] } }, { "type": "Microsoft.Network/publicIPAddresses", "apiVersion": "2023-11-01", "name": "[variables('publicIpName')]", "location": "[parameters('location')]", "sku": { "name": "Standard" }, "properties": { "publicIPAllocationMethod": "Static", "dnsSettings": { "domainNameLabel": "[variables('dnsLabel')]" } } }, { "type": "Microsoft.Network/networkInterfaces", "apiVersion": "2023-11-01", "name": "[variables('nicName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/virtualNetworks', variables('vnetName'))]", "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIpName'))]" ], "properties": { "ipConfigurations": [ { "name": "ipconfig1", "properties": { "privateIPAllocationMethod": "Dynamic", "subnet": { "id": "[variables('subnetRef')]" }, "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIpName'))]" } } } ] } }, { "type": "Microsoft.Compute/virtualMachines", "apiVersion": "2024-07-01", "name": "[parameters('vmName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" ], "identity": { "type": "SystemAssigned" }, "properties": { "hardwareProfile": { "vmSize": "[parameters('vmSize')]" }, "storageProfile": { "imageReference": { "publisher": "Canonical", "offer": "ubuntu-24_04-lts", "sku": "server", "version": "latest" }, "osDisk": { "createOption": "FromImage", "diskSizeGB": "[parameters('osDiskSizeGB')]", "managedDisk": { "storageAccountType": "Premium_LRS" } } }, "diagnosticsProfile": { "bootDiagnostics": { "enabled": true } }, "osProfile": { "computerName": "[parameters('vmName')]", "adminUsername": "[parameters('adminUsername')]", "adminPassword": "[parameters('adminPasswordOrKey')]", "linuxConfiguration": "[if(equals(parameters('authenticationType'), 'password'), null(), variables('linuxConfiguration'))]", "customData": "[base64(variables('cloudInit'))]" }, "networkProfile": { "networkInterfaces": [ { "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" } ] } } }, { "type": "Microsoft.Compute/virtualMachines/extensions", "apiVersion": "2024-07-01", "name": "[concat(parameters('vmName'), '/zato-deploy-page')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Compute/virtualMachines', parameters('vmName'))]" ], "properties": { "publisher": "Microsoft.Azure.Extensions", "type": "CustomScript", "typeHandlerVersion": "2.1", "autoUpgradeMinorVersion": true, "settings": { "commandToExecute": "[concat('timeout 900 sh -c ''until [ -e ', variables('servingMarker'), ' ]; do sleep 1; done''')]" } } }, { "condition": "[variables('useKeyVault')]", "type": "Microsoft.KeyVault/vaults", "apiVersion": "2023-07-01", "name": "[variables('keyVaultName')]", "location": "[parameters('location')]", "properties": { "tenantId": "[subscription().tenantId]", "sku": { "family": "A", "name": "standard" }, "enableRbacAuthorization": true } }, { "condition": "[variables('useKeyVault')]", "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "scope": "[format('Microsoft.KeyVault/vaults/{0}', variables('keyVaultName'))]", "name": "[guid(resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName')), parameters('vmName'), variables('keyVaultSecretsUserRole'))]", "dependsOn": [ "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]", "[resourceId('Microsoft.Compute/virtualMachines', parameters('vmName'))]" ], "properties": { "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('keyVaultSecretsUserRole'))]", "principalId": "[reference(resourceId('Microsoft.Compute/virtualMachines', parameters('vmName')), '2024-07-01', 'Full').identity.principalId]", "principalType": "ServicePrincipal" } }, { "condition": "[variables('useKeyVault')]", "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "scope": "[format('Microsoft.KeyVault/vaults/{0}', variables('keyVaultName'))]", "name": "[guid(resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName')), deployer().objectId, variables('keyVaultSecretsOfficerRole'))]", "dependsOn": [ "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]" ], "properties": { "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('keyVaultSecretsOfficerRole'))]", "principalId": "[deployer().objectId]" } } ], "outputs": { "dashboardUrl": { "type": "string", "value": "[concat('https://', reference(resourceId('Microsoft.Network/publicIPAddresses', variables('publicIpName'))).dnsSettings.fqdn, ':8184/')]" }, "sshCommand": { "type": "string", "value": "[concat('ssh ', parameters('adminUsername'), '@', reference(resourceId('Microsoft.Network/publicIPAddresses', variables('publicIpName'))).dnsSettings.fqdn)]" }, "publicIpAddress": { "type": "string", "value": "[reference(resourceId('Microsoft.Network/publicIPAddresses', variables('publicIpName'))).ipAddress]" }, "keyVaultName": { "condition": "[variables('useKeyVault')]", "type": "string", "value": "[variables('keyVaultName')]" } } }