I need to create via ARM template storage account --> File share --> Container with mounted fileshare.
The dependency is:
file share depends on storage account
container depends on file share
How to get ReferenceId of Fileshare?
I have the following code:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountType": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS"
],
"metadata": {
"description": "Storage account type (SKU)"
}
},
"fileShareName": {
"type": "string",
"minLength": 3,
"maxLength": 63,
"defaultValue": "sftp",
"metadata": {
"description": "Name of the File Share to be created. "
}
}
},
"variables": {
"deploymentLocation": "[resourceGroup().location]",
"storageAccountName": "[concat('sftpstr', uniqueString(resourceGroup().id))]"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageAccountName')]",
"apiVersion": "2019-06-01",
"location": "[variables('deploymentLocation')]",
"sku": {
"name": "[parameters('storageAccountType')]"
},
"kind": "StorageV2",
"properties": {
"accessTier": "Hot"
}
},
{
"type": "Microsoft.Storage/storageAccounts/fileServices/shares",
"apiVersion": "2019-06-01",
"properties": {
"accessTier": "Hot"
},
"name": "[concat(variables('storageAccountName'), '/default/', parameters('fileShareName'))]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
]
},
{
"type": "Microsoft.ContainerInstance/containerGroups",
"name": "sftp-container-group",
"apiVersion": "2018-04-01",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', ????? )]" //how to get reference to specific Fileshare??? I've tried > [concat(variables('storageAccountName'), '/default/', parameters('fileShareName'))] but it didn't work
],
"properties": {
.......
}
}
]
}
and I don't know how to set dependency on Fileshare:
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', ????? )]" //how to get reference to specific Fileshare???
],
I've tried [concat(variables('storageAccountName'), '/default/', parameters('fileShareName'))] but it didn't work.
Any idea?
Thank you
Use following format:
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', variables('storageAccountName') , 'default', parameters('fileShareName') )]"
],
You could create two separate resources Microsoft.Storage/storageAccounts/fileServices and Microsoft.Storage/storageAccounts/fileServices/shares and try to set dependency on Fileshare like this:
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', variables('storageAccountName'), 'default', parameters('fileShareName') )]"
],
Alternatively, It's recommended to creates a storage account and a file share via azure-CLI in a Container Instance and refer to this quickstart template.
"variables": {
"image": "microsoft/azure-cli",
"cpuCores": "1.0",
"memoryInGb": "1.5",
"containerGroupName": "createshare-containerinstance",
"containerName": "createshare"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('storageAccountName')]",
"apiVersion": "2019-06-01",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('storageAccountType')]"
},
"kind": "StorageV2"
},
{
"name": "[variables('containerGroupName')]",
"type": "Microsoft.ContainerInstance/containerGroups",
"apiVersion": "2019-12-01",
"location": "[parameters('containerInstanceLocation')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]"
],
"properties": {
"containers": [
{
"name": "[variables('containerName')]",
"properties": {
"image": "[variables('image')]",
"command": [
"az",
"storage",
"share",
"create",
"--name",
"[parameters('fileShareName')]"
],
"environmentVariables": [
{
"name": "AZURE_STORAGE_KEY",
"value": "[listKeys(parameters('storageAccountName'),'2019-06-01').keys[0].value]"
},
{
"name": "AZURE_STORAGE_ACCOUNT",
"value": "[parameters('storageAccountName')]"
}
],
"resources": {
"requests": {
"cpu": "[variables('cpuCores')]",
"memoryInGb": "[variables('memoryInGb')]"
}
}
}
}
],
"restartPolicy": "OnFailure",
"osType": "Linux"
}
}
]
I found a couple of things that made it work for me:
ACI has to depend on the share otherwise it gets created ahead of volume sometimes
"dependsOn": ["resourceId('Microsoft.Storage/storageAccounts/fileServices/shares',variables('storage-account-name'), 'default', variables('file-share-name'))]"]
For some reason, the share wasn't working as a child resource so I had to make it a full resource
{
"type": "Microsoft.Storage/storageAccounts/fileServices/shares",
"apiVersion": "2021-04-01",
"name": "[concat(variables('storage-account-name'),'/default/',variables('nginx-share-name'))]",
"properties":{
"enabledProtocols": "SMB"
},
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storage-account-name'))]"
]
}
Also, I had to pay attention to default part of the resource ID
"name": "[concat(variables('storage-account-name'),'/default/',variables('nginx-share-name'))]"
And finally, ACI wasn't connecting properly unless I explicitly enabled SMB as a protocol
"properties":{
"enabledProtocols": "SMB"
}
This is a template I'm using to spin up NGINX in Azure Container instances with an Azure File Share as a mounted volume.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"containerGroups_name": {
"defaultValue": "container-app",
"type": "String"
},
"containerGroups_reverse_proxy_name": {
"defaultValue": "app-proxy",
"type": "String"
},
"acrPassword": {
"type": "securestring"
}
},
"variables": {
"nginx-proxy-image": "nginx:stable",
"storage-account-name": "[concat('storage', uniqueString(resourceGroup().name))]",
"nginx-share-name": "nginx-share",
"nginx-volume-name": "nginx-volume"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2017-10-01",
"name": "[variables('storage-account-name')]" ,
"location": "[resourceGroup().location]",
"kind": "StorageV2",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
}
},
{
"type": "Microsoft.Storage/storageAccounts/fileServices/shares",
"apiVersion": "2021-04-01",
"name": "[concat(variables('storage-account-name'),'/default/',variables('nginx-share-name'))]",
"properties":{
"enabledProtocols": "SMB"
},
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storage-account-name'))]"
]
},
{
"type": "Microsoft.ContainerInstance/containerGroups",
"apiVersion": "2021-03-01",
"name": "[parameters('containerGroups_name')]",
"location": "[resourceGroup().location]",
"properties": {
"sku": "Standard",
"containers": [
{
"name": "[parameters('containerGroups_reverse_proxy_name')]",
"properties" : {
"image": "[variables('nginx-proxy-image')]",
"ports": [
{
"protocol": "TCP",
"port": 80
},
{
"protocol": "TCP",
"port": 433
}
],
"volumeMounts" : [
{
"name": "[variables('nginx-volume-name')]",
"mountPath": "/etc/nginx"
}
],
"resources": {
"requests":{
"cpu": 1,
"memoryInGB": 1.5
}
}
}
}
],
"initContainers": [],
"restartPolicy": "OnFailure",
"osType": "Linux",
"volumes": [
{
"name": "[variables('nginx-volume-name')]",
"azureFile": {
"shareName": "[variables('nginx-share-name')]",
"storageAccountName": "[variables('storage-account-name')]",
"storageAccountKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts',variables('storage-account-name')),'2017-10-01').keys[0].value]"
}
}
]
},
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares',variables('storage-account-name'), 'default', variables('nginx-share-name'))]"
]
}
]
}
Related
Background
I am trying to create an AD app registration for my function app to use for authentication.
I would like it to be for just our tenant, using Azure AD. The app is function app made up of a few endpoints
When I deploy the ARM template below, I don't get any errors, but in poking around and comparing it with what happens when I create authentication manually for my app, i see the following problems:
the application registration is created but there's no Application ID URI specified. When I create this manually via the portal I believe it's auto filled with a value "api://[applicationClientId]"
there are no scopes defined. again, when i create an authentication policy for my app manually via the portal, it does create a user_impersonation scope for me.
When i open up the function app in the portal, under "authentication" this new app registration hasn't been associated with it / or added.
Code
Here's what the ARM template looks like:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"functionAppName": {
"type": "string",
"defaultValue": "[concat('widgets-', uniqueString(resourceGroup().id),'-app')]",
"minLength": 2,
"metadata": {
"description": "my function app"
}
},
"storageAccountName": {
"type": "string",
"defaultValue": "[concat('widgets', uniqueString(resourceGroup().id))]",
"minLength": 2,
"metadata": {
"description": "StorageAccount"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
"serviceBusNamespaceName": {
"type": "string",
"defaultValue": "[concat('widgets-', uniqueString(resourceGroup().id),'-bus')]",
"metadata": {
"description": "Name of the Service Bus namespace"
}
},
"serviceBusQueueName": {
"type": "string",
"defaultValue": "workspaces",
"metadata": {
"description": "Name of the Queue"
}
},
"queueAuthorizationRuleName": {
"type": "string",
"defaultValue": "myRule",
"metadata": {
"description": "Name of the Queue AuthorizationRule"
}
},
"aadAppClientId": {
"type": "string"
},
"tenant": {
"type": "string"
}
},
"variables": {
"appServicePlanPortalName": "[concat(parameters('functionAppName'),'servicePlan')]",
"appInsightsName": "[concat(parameters('functionAppName'),'-insights')]",
"identityName": "[concat(parameters('functionAppName'),'-userId')]",
"clientSecret": ""
},
"resources": [
{
"name": "[variables('identityName')]",
"type": "Microsoft.ManagedIdentity/userAssignedIdentities",
"apiVersion": "2018-11-30",
"location": "[parameters('location')]"
},
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('storageAccountName')]",
"apiVersion": "2019-06-01",
"location": "[parameters('location')]",
"kind": "StorageV2",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
}
},
{
"type": "Microsoft.Storage/storageAccounts/queueServices",
"apiVersion": "2020-08-01-preview",
"name": "[concat(parameters('storageAccountName'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
],
"properties": {
"cors": {
"corsRules": []
}
}
},
{
"type": "Microsoft.Storage/storageAccounts/queueServices/queues",
"apiVersion": "2020-08-01-preview",
"name": "[concat(parameters('storageAccountName'), '/default/workspaces')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
],
"properties": {
"metadata": {}
}
},
{
"type": "Microsoft.Storage/storageAccounts/tableServices/tables",
"apiVersion": "2021-06-01",
"name": "[concat(parameters('storageAccountName'), '/default/provisionedWorkspaces')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
],
"properties": {
"partitionName": "workspaces"
}
},
{
"type": "Microsoft.ServiceBus/namespaces",
"apiVersion": "2017-04-01",
"name": "[parameters('serviceBusNamespaceName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Standard"
},
"properties": {}
},
{
"type": "Microsoft.ServiceBus/namespaces/queues",
"apiVersion": "2017-04-01",
"name": "[format('{0}/{1}', parameters('serviceBusNamespaceName'), parameters('serviceBusQueueName'))]",
"properties": {
"lockDuration": "PT5M",
"maxSizeInMegabytes": 1024,
"requiresDuplicateDetection": false,
"requiresSession": false,
"defaultMessageTimeToLive": "P10675199DT2H48M5.4775807S",
"deadLetteringOnMessageExpiration": false,
"duplicateDetectionHistoryTimeWindow": "PT10M",
"maxDeliveryCount": 10,
"autoDeleteOnIdle": "P10675199DT2H48M5.4775807S",
"enablePartitioning": false,
"enableExpress": false
},
"resources": [
{
"apiVersion": "2017-04-01",
"name": "[parameters('queueAuthorizationRuleName')]",
"type": "AuthorizationRules",
"dependsOn": ["[parameters('serviceBusQueueName')]"],
"properties": {
"rights": ["Listen", "Send", "Manage"]
}
}
],
"dependsOn": [
"[resourceId('Microsoft.ServiceBus/namespaces', parameters('serviceBusNamespaceName'))]"
]
},
{
"apiVersion": "2015-05-01",
"name": "[variables('appInsightsName')]",
"type": "Microsoft.Insights/components",
"kind": "web",
"location": "[parameters('location')]",
"tags": {
"[concat('hidden-link:', resourceGroup().id, '/providers/Microsoft.Web/sites/', parameters('functionAppName'))]": "Resource"
},
"properties": {
"Application_Type": "web",
"ApplicationId": "[variables('appInsightsName')]"
}
},
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2020-06-01",
"name": "[variables('appServicePlanPortalName')]",
"location": "[parameters('location')]",
"sku": {
"tier": "Standard",
"name": "S1"
},
"kind": "functionapp,linux",
"properties": {
"name": "[variables('appServicePlanPortalName')]",
"reserved": true
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2020-06-01",
"name": "[parameters('functionAppName')]",
"location": "[parameters('location')]",
"kind": "functionapp,linux",
"identity": {
"type": "UserAssigned",
"userAssignedIdentities": {
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]": {}
}
},
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanPortalName'))]",
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]"
],
"properties": {
"reserved": true,
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanPortalName'))]",
"siteConfig": {
"linuxFxVersion": "DOTNETCORE|6.0",
"appSettings": [
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(resourceId('Microsoft.Insights/components', variables('appInsightsName')), '2015-05-01').InstrumentationKey]"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('storageAccountName'), ';EndpointSuffix=', environment().suffixes.storage, ';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value)]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~4"
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "dotnet"
}
],
"resources": [
{
"type": "config",
"apiVersion": "2020-12-01",
"name": "authsettingsV2",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Web/sites/', parameters('functionAppName'))]"
],
"properties": {
"platform": {
"enabled": true,
"runtimeVersion": "~1"
},
"identityProviders": {
"azureActiveDirectory": {
"isAutoProvisioned": false,
"registration": {
"clientId": "[parameters('aadAppClientId')]",
"clientSecret": "[variables('clientSecret')]",
"openIdIssuer": "[concat('https://sts.windows.net/', parameters('tenant'), '/v2.0')]"
},
"validation": {
"allowedAudiences": [
"https://management.core.windows.net/"
]
}
}
}
},
"login": {
"routes": {},
"tokenStore": {
"enabled": true,
"tokenRefreshExtensionHours": 72,
"fileSystem": {},
"azureBlobStorage": {}
},
"preserveUrlFragmentsForLogins": false,
"allowedExternalRedirectUrls": [],
"cookieExpiration": {
"convention": "FixedTime",
"timeToExpiration": "08:00:00"
},
"nonce": {
"validateNonce": true,
"nonceExpirationInterval": "00:05:00"
}
},
"globalValidation": {
"redirectToProvider": "azureactivedirectory",
"unauthenticatedClientAction": "RedirectToLoginPage"
},
"httpSettings": {
"requireHttps": true,
"routes": {
"apiPrefix": "/.auth"
},
"forwardProxy": {
"convention": "NoProxy"
}
}
}
]
}
}
}
]
}
Two comments in case they help / are relevant:
client secret - As you can see I have a variable defined, but its blank. I'm not supplying a client secret value because I was assuming it would auto create for me. But maybe I shouldn't include that parameter at all?
Also, I'm using a linux container for the web app.
Any tips on how to fix these issues would be appreciated.
EDIT 1
I manually created and added an authencation policy and then I've been using resources.azure.com to see what's been created for me. I have two relevant sections under config.
One is called authsettings and looks like this:
And the other is under authsettingsV2 and looks like this:
I'm trying to use the authsettingsV2 for now... but it's not clear where I should paste it into in the ARM template.
Any suggestions?
EDIT 2
Added all the authsettingsv2 stuff under the site resource. No errors. but still the same results.
Found out that I can use the Az Powershell commandlets:
New-AzADApplication
New-AzADAppCredential
I'm having errors while trying to deploy an ARM deploy with an SQL Database and its private endpoint.
here is the code below
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"sqlAdministratorLogin": {
"type": "string",
"metadata": {
"description": "The administrator username of the SQL logical server"
}
},
"sqlAdministratorLoginPassword": {
"type": "securestring",
"metadata": {
"description": "The administrator password of the SQL logical server."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
}
},
"variables": {
"vnetName": "powerStateManagement-vnet",
"subnet1Name": "default",
"sqlServerName": "[concat('sqlserver', uniqueString(resourceGroup().id))]",
"databaseName": "[concat(variables('sqlServerName'),'/sample-db')]",
"privateEndpointName": "myPrivateEndpoint",
"privateDnsZoneName": "[concat('privatelink', environment().suffixes.sqlServerHostname)]",
"pvtendpointdnsgroupname": "[concat(variables('privateEndpointName'),'/mydnsgroupname')]",
"vnetResourceGroup":"powerStateManagement"
},
"resources": [
{
"type": "Microsoft.Sql/servers",
"apiVersion": "2020-02-02-preview",
"name": "[variables('sqlServerName')]",
"location": "[parameters('location')]",
"kind": "v12.0",
"tags": {
"displayName": "[variables('sqlServerName')]"
},
"properties": {
"administratorLogin": "[parameters('sqlAdministratorLogin')]",
"administratorLoginPassword": "[parameters('sqlAdministratorLoginPassword')]",
"version": "12.0",
"publicNetworkAccess": "Disabled"
},
"resources": [
]
},
{
"type": "Microsoft.Sql/servers/databases",
"apiVersion": "2020-02-02-preview",
"name": "[variables('databaseName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Basic",
"tier": "Basic",
"capacity": 5
},
"dependsOn": [
"[resourceId('Microsoft.Sql/servers', variables('sqlServerName'))]"
],
"tags": {
"displayName": "[variables('databaseName')]"
},
"properties": {
"collation": "SQL_Latin1_General_CP1_CI_AS",
"edition": "Basic",
"maxSizeBytes": 104857600,
"requestedServiceObjectiveName": "Basic",
"sampleName": "AdventureWorksLT"
}
},
{
"type": "Microsoft.Network/privateEndpoints",
"apiVersion": "2020-06-01",
"name": "[variables('privateEndpointName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[variables('vnetName')]",
"[variables('sqlServerName')]"
],
"properties": {
"subnet": {
"id": "[resourceId(variables('vnetResourceGroup'),'/','Microsoft.Network/virtualNetworks','/',variables('vnetName'),'/',variables('subnet1Name'))]"
},
"privateLinkServiceConnections": [
{
"name": "[variables('privateEndpointName')]",
"properties": {
"privateLinkServiceId": "[resourceId('Microsoft.Sql/servers',variables('sqlServerName'))]",
"groupIds": [
"sqlServer"
]
}
}
]
}
},
{
"type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
"apiVersion": "2020-01-01",
"name": "[concat(variables('privateDnsZoneName'), '/', variables('privateDnsZoneName'), '-link')]",
"location": "global",
"dependsOn": [
"[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]",
"[resourceId(variables('vnetResourceGroup'),'Microsoft.Network/virtualNetworks',variables('vnetName'))]"
],
"properties": {
"registrationEnabled": false,
"virtualNetwork": {
"id": "/subscriptions/*****/resourceGroups/powerStateManagement/providers/Microsoft.Network/virtualNetworks/powerStateManagement-vnet"
}
}
},
{
"type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups",
"apiVersion": "2020-06-01",
"name": "[variables('pvtendpointdnsgroupname')]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]",
"[variables('privateEndpointName')]"
],
"properties": {
"privateDnsZoneConfigs": [
{
"name": "config1",
"properties": {
"privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]"
}
}
]
}
}
]
}
The challenge here is that when I try to run this code I always get this error
Deployment template validation failed: 'The template reference 'powerStateManagement-vnet' is not valid: could not find template resource or resource copy with this name.
The ''powerStateManagement-vnet' is an existing Virtual Network which has been referenced below
{
"type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
"apiVersion": "2020-01-01",
"name": "[concat(variables('privateDnsZoneName'), '/', variables('privateDnsZoneName'), '-link')]",
"location": "global",
"dependsOn": [
"[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]",
"[resourceId(variables('vnetResourceGroup'),'Microsoft.Network/virtualNetworks',variables('vnetName'))]"
],
"properties": {
"registrationEnabled": false,
"virtualNetwork": {
"id": "/subscriptions/*****/resourceGroups/powerStateManagement/providers/Microsoft.Network/virtualNetworks/powerStateManagement-vnet"
}
}
}
Please help
There is something wrong with your dependsOn param of Microsoft.Network/privateEndpoints. And seems there are some other issues in your template, I did some modification based on your template,just try it below:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"sqlAdministratorLogin": {
"type": "string",
"metadata": {
"description": "The administrator username of the SQL logical server"
}
},
"sqlAdministratorLoginPassword": {
"type": "securestring",
"metadata": {
"description": "The administrator password of the SQL logical server."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
}
},
"variables": {
"vnetName": "powerStateManagement-vnet",
"subnet1Name": "default",
"sqlServerName": "[concat('sqlserver', uniqueString(resourceGroup().id))]",
"databaseName": "[concat(variables('sqlServerName'),'/sample-db')]",
"privateEndpointName": "myPrivateEndpoint",
"privateDnsZoneName": "testdns.com",
"pvtendpointdnsgroupname": "[concat(variables('privateEndpointName'),'/mydnsgroupname')]",
"vnetResourceGroup": "powerStateManagement"
},
"resources": [{
"type": "Microsoft.Sql/servers",
"apiVersion": "2020-02-02-preview",
"name": "[variables('sqlServerName')]",
"location": "[parameters('location')]",
"kind": "v12.0",
"tags": {
"displayName": "[variables('sqlServerName')]"
},
"properties": {
"administratorLogin": "[parameters('sqlAdministratorLogin')]",
"administratorLoginPassword": "[parameters('sqlAdministratorLoginPassword')]",
"version": "12.0",
"publicNetworkAccess": "Disabled"
},
"resources": [
]
}, {
"type": "Microsoft.Sql/servers/databases",
"apiVersion": "2020-02-02-preview",
"name": "[variables('databaseName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Basic",
"tier": "Basic",
"capacity": 5
},
"dependsOn": [
"[resourceId('Microsoft.Sql/servers', variables('sqlServerName'))]"
],
"tags": {
"displayName": "[variables('databaseName')]"
},
"properties": {
"collation": "SQL_Latin1_General_CP1_CI_AS",
"edition": "Basic",
"maxSizeBytes": 104857600,
"requestedServiceObjectiveName": "Basic",
"sampleName": "AdventureWorksLT"
}
}, {
"type": "Microsoft.Network/privateEndpoints",
"apiVersion": "2020-06-01",
"name": "[variables('privateEndpointName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', variables('vnetName'))]",
"[resourceId('Microsoft.Sql/servers', variables('sqlServerName'))]"
],
"properties": {
"subnet": {
"id": "[concat(resourceId('Microsoft.Network/virtualNetworks', variables('vnetName')),'/subnets/default')]"
},
"privateLinkServiceConnections": [{
"name": "[variables('privateEndpointName')]",
"properties": {
"privateLinkServiceId": "[resourceId('Microsoft.Sql/servers',variables('sqlServerName'))]",
"groupIds": [
"sqlServer"
]
}
}
]
}
}, {
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2020-05-01",
"name": "[variables('vnetName')]",
"location": "[resourceGroup().location]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"172.22.0.0/16"
]
}
},
"resources": [{
"type": "subnets",
"apiVersion": "2020-05-01",
"location": "[resourceGroup().location]",
"name": "default",
"dependsOn": [
"[variables('vnetName')]"
],
"properties": {
"addressPrefix": "172.22.0.0/24",
"privateEndpointNetworkPolicies": "Disabled"
}
}
]
}, {
"type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
"apiVersion": "2020-01-01",
"name": "[concat(variables('privateDnsZoneName'), '/', variables('privateDnsZoneName'), '-link')]",
"location": "global",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', variables('vnetName'))]"
],
"properties": {
"registrationEnabled": false,
"virtualNetwork": {
"id":"[resourceId('Microsoft.Network/virtualNetworks', variables('vnetName'))]"
}
}
}, {
"type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups",
"apiVersion": "2020-06-01",
"name": "[variables('pvtendpointdnsgroupname')]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Network/privateEndpoints', variables('privateEndpointName'))]"
],
"properties": {
"privateDnsZoneConfigs": [{
"name": "config1",
"properties": {
"privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]"
}
}
]
}
}
]
}
This template creates a new virtual network with a default subnet together, I use my own private DNS zone named : testdns.com. I have tested on my side by powershell and it works for me.
Result
When enabling sql server vulnerabilityAssessments feature using arm template, following error is thrown when storage account has a firewall on.
"error": {
"code": "InvalidStorageAccountCredentials",
"message": "The provided storage account shared access signature or account storage key is not valid."
}
}
Template part:
{
"type": "Microsoft.Sql/servers/securityAlertPolicies",
"apiVersion": "2017-03-01-preview",
"name": "[concat(variables('sqls01Name'), '/Default')]",
"dependsOn": [
],
"properties": {
"state": "Enabled",
"emailAddresses": "[variables('emailActionGroupAddresses')]",
"emailAccountAdmins": false
}
},
{
"type": "Microsoft.Sql/servers/vulnerabilityAssessments",
"apiVersion": "2018-06-01-preview",
"location": "westeurope",
"name": "[concat(variables('sqls01Name'), '/Default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('defenderSa'))]"
],
"properties": {
"storageContainerPath": "[concat('https://',variables('defenderSa'),'.blob.core.windows.net/vulnerability-assessment/')]",
"storageAccountAccessKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('defenderSa')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value]",
"recurringScans": {
"isEnabled": true,
"emailSubscriptionAdmins": false,
"emails": "[variables('emailActionGroupAddresses')]"
}
}
},
{
"name": "[variables('defenderSA')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"location": "westeurope",
"properties": {
"accessTier": "Cool",
"allowBlobPublicAccess": false,
"supportsHttpsTrafficOnly": true,
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [{
"id": "[variables('subnetId')]",
"action": "Allow"
}],
"ipRules": [
],
"defaultAction": "Deny"
}
},
"dependsOn": [
],
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "StorageV2",
"tags": {
}
}
I notices that when enabling the feature from portal following communicate is displayed:
You have selected a storage that is behind a firewall or in a virtual network. Please be aware that using this storage will create a managed identity for the server and it will be granted 'storage blob data contributor' role on the selected storage.
The assignment is indeed created and the assessment works, however when I try to replicate this in arm template with following code it still fails.
{
"type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
"name": "[concat(variables('defenderSA'),'/Microsoft.Authorization/',guid(variables('sqls01Name')))]",
"apiVersion": "2018-09-01-preview",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts',variables('defenderSA'))]"
],
"properties": {
"roleDefinitionId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]",
"principalId": "[reference(resourceId('Microsoft.Sql/servers',variables('sqls01Name')),providers('Microsoft.Sql', 'servers').apiVersions[0],'Full').identity.principalId]"
}
}
Regarding the issue, please refer to the following template
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"clientIp": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "allow you client to access Azure storage "
}
},
"virtualNetworksName": {
"defaultValue": "testsql09",
"type": "String"
},
"serverName": {
"type": "string",
"defaultValue": "[uniqueString('sql', resourceGroup().id)]",
"metadata": {
"description": "The name of the SQL logical server."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
"administratorLogin": {
"type": "string",
"defaultValue": "sqladmin",
"metadata": {
"description": "The administrator username of the SQL logical server."
}
},
"administratorLoginPassword": {
"type": "securestring",
"defaultValue": "Password0123!",
"metadata": {
"description": "The administrator password of the SQL logical server."
}
},
"connectionType": {
"defaultValue": "Default",
"allowedValues": [ "Default", "Redirect", "Proxy" ],
"type": "string",
"metadata": {
"description": "SQL logical server connection type."
}
}
},
"variables": {
"serverResourceGroupName": "[resourceGroup().name]",
"subscriptionId": "[subscription().subscriptionId]",
"uniqueStorage": "[uniqueString(variables('subscriptionId'), variables('serverResourceGroupName'), parameters('location'))]",
"storageName": "[tolower(concat('sqlva', variables('uniqueStorage')))]",
"roleAssignmentName": "[guid(resourceId('Microsoft.Storage/storageAccounts', variables('storageName')), variables('storageBlobContributor'), resourceId('Microsoft.Sql/servers', parameters('serverName')))]",
"StorageBlobContributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]"
},
"resources": [
{
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2020-05-01",
"name": "[parameters('virtualNetworksName')]",
"location": "southeastasia",
"properties": {
"addressSpace": {
"addressPrefixes": [
"10.18.0.0/24"
]
},
"subnets": [
{
"name": "default",
"properties": {
"addressPrefix": "10.18.0.0/24",
"serviceEndpoints": [
{
"service": "Microsoft.Storage"
}
],
"delegations": [],
"privateEndpointNetworkPolicies": "Enabled",
"privateLinkServiceNetworkPolicies": "Enabled"
}
}
],
"virtualNetworkPeerings": [],
"enableDdosProtection": false,
"enableVmProtection": false
}
},
{
"type": "Microsoft.Network/virtualNetworks/subnets",
"apiVersion": "2020-05-01",
"name": "[concat(parameters('virtualNetworksName'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworksName'))]"
],
"properties": {
"addressPrefix": "10.18.0.0/24",
"serviceEndpoints": [
{
"service": "Microsoft.Storage"
}
],
"delegations": [],
"privateEndpointNetworkPolicies": "Enabled",
"privateLinkServiceNetworkPolicies": "Enabled"
}
},
{
"type": "Microsoft.Sql/servers",
"apiVersion": "2019-06-01-preview",
"name": "[parameters('serverName')]",
"location": "[parameters('location')]",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"administratorLogin": "[parameters('administratorLogin')]",
"administratorLoginPassword": "[parameters('administratorLoginPassword')]",
"version": "12.0"
}
},
{
"type": "Microsoft.Sql/servers/databases",
"apiVersion": "2019-06-01-preview",
"name": "[concat(parameters('serverName'), '/test')]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers', parameters('serverName'))]"
],
"sku": {
"name": "Basic",
"tier": "Basic",
"capacity": 5
},
"kind": "v12.0,user",
"properties": {
"collation": "SQL_Latin1_General_CP1_CI_AS",
"maxSizeBytes": 2147483648,
"catalogCollation": "SQL_Latin1_General_CP1_CI_AS",
"zoneRedundant": false,
"readScale": "Disabled",
"storageAccountType": "LRS"
}
},
{
"type": "Microsoft.Sql/servers/securityAlertPolicies",
"apiVersion": "2020-02-02-preview",
"name": "[concat(parameters('serverName'), '/Default')]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers', parameters('serverName'))]"
],
"properties": {
"state": "Enabled",
"emailAccountAdmins": false
}
},
{
"type": "Microsoft.Sql/servers/vulnerabilityAssessments",
"apiVersion": "2018-06-01-preview",
"name": "[concat(parameters('serverName'), '/Default')]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers', parameters('serverName'))]",
"[resourceId('Microsoft.Sql/servers/securityAlertPolicies', parameters('serverName'), 'Default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageName'))]",
"[extensionResourceId(resourceId('Microsoft.Storage/storageAccounts', variables('storageName')), 'Microsoft.Authorization/roleAssignments', variables('roleAssignmentName'))]"
],
"properties": {
"storageContainerPath": "[concat(reference(resourceId('Microsoft.Storage/storageAccounts', variables('storageName'))).primaryEndpoints.blob, 'vulnerability-assessment')]",
"recurringScans": {
"isEnabled": true,
"emailSubscriptionAdmins": false
}
}
},
{
"type": "Microsoft.Sql/servers/connectionPolicies",
"apiVersion": "2014-04-01",
"name": "[concat(parameters('serverName'), '/Default')]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers', parameters('serverName'))]"
],
"properties": {
"connectionType": "[parameters('connectionType')]"
}
},
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"name": "[variables('storageName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworksName'), 'default')]"
],
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2",
"properties": {
"minimumTlsVersion": "TLS1_2",
"allowBlobPublicAccess": true,
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [
{
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworksName'), 'default')]",
"action": "Allow",
"state": "Succeeded"
}
],
"ipRules": [
{
"value": "[parameters('clientIp')]",
"action": "Allow"
}
],
"defaultAction": "Deny"
}
}
},
{
"type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
"apiVersion": "2020-04-01-preview",
"name": "[concat(variables('storageName'), '/Microsoft.Authorization/', variables('roleAssignmentName'))]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers', parameters('serverName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageName'))]"
],
"properties": {
"roleDefinitionId": "[variables('StorageBlobContributor')]",
"principalId": "[reference(resourceId('Microsoft.Sql/servers', parameters('serverName')), '2020-02-02-preview', 'Full').identity.principalId]",
"scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageName'))]",
"principalType": "ServicePrincipal"
}
}
]
}
I can create a Private Endpoint for a Storage Queue through the portal just fine and it works as intended when checking with nameresolver.exe from KUDU. However, I am struggling to find an ARM template that does this in one go.
I have made this template work but I can see that the A record entry does not get generated in the Private DNS Zone that is generated. I don't know how to create that A record entry and cannot seem to find a ARM template online that describes this:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"privateEndpointName": {
"type": "string",
"defaultValue": "privendpoint-sapriv01-queue"
},
"vnetName": {
"type": "string",
"defaultValue": "vn-myvnet01"
},
"subnetName": {
"type": "string",
"defaultValue": "sn-private-endpoints"
},
"groupId": {
"type": "string",
"defaultValue": "queue"
}
},
"variables": {
"privateDNSZone_name": "[concat('privatelink', '.queue.', environment().suffixes.storage)]"
},
"resources": [
{
"apiVersion": "2019-04-01",
"name": "[parameters('privateEndpointName')]",
"type": "Microsoft.Network/privateEndpoints",
"location": "[resourceGroup().Location]",
"properties": {
"privateLinkServiceConnections": [
{
"name": "[parameters('privateEndpointName')]",
"properties": {
"privateLinkServiceId": "[resourceId('Microsoft.Storage/storageAccounts', 'saprivendpointdemo')]",
"groupIds": [
"[parameters('groupId')]"
]
}
}
],
"manualPrivateLinkServiceConnections": [],
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), parameters('subnetName') )]"
}
}
},
{
"type": "Microsoft.Network/privateDnsZones",
"apiVersion": "2018-09-01",
"name": "[variables('privateDNSZone_name')]",
"location": "global",
"tags": {},
"properties": {}
},
{
"type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
"apiVersion": "2018-09-01",
"name": "[concat(variables('privateDNSZone_name'), '/', parameters('vnetName'), 'link' )]",
"location": "global",
"dependsOn": [
"[resourceId('Microsoft.Network/privateDnsZones', variables('privateDNSZone_name'))]"
],
"properties": {
"virtualNetwork": {
"id": "[resourceId('Microsoft.Network/virtualNetworks', parameters('vnetName'))]"
},
"registrationEnabled": false
}
}
],
"outputs": {
}
}
I think Microsoft overcomplicated this. The Private IP is auto generated and I don't know how one would reference this IP in the ARM template.
If you want to add A record in your Azure Private DNS Zone, you can define Microsoft.Network/privateEndpoints/privateDnsZoneGroups in your template.
For example
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"privateEndpointName": {
"type": "string",
"defaultValue": "testqueue"
},
"vnetName": {
"type": "string",
"defaultValue": "teststorage"
},
"subnetName": {
"type": "string",
"defaultValue": "default"
},
"groupId": {
"type": "string",
"defaultValue": "queue"
}
},
"variables": {
"privateDNSZone_name": "[concat('privatelink', '.queue.', environment().suffixes.storage)]"
},
"resources": [
{
"apiVersion": "2019-04-01",
"name": "[parameters('privateEndpointName')]",
"type": "Microsoft.Network/privateEndpoints",
"location": "[resourceGroup().Location]",
"properties": {
"privateLinkServiceConnections": [
{
"name": "[parameters('privateEndpointName')]",
"properties": {
"privateLinkServiceId": "[resourceId('Microsoft.Storage/storageAccounts', 'teststorage05')]",
"groupIds": [
"[parameters('groupId')]"
]
}
}
],
"manualPrivateLinkServiceConnections": [],
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), parameters('subnetName') )]"
}
}
},
{
"type": "Microsoft.Network/privateDnsZones",
"apiVersion": "2018-09-01",
"name": "[variables('privateDNSZone_name')]",
"dependsOn": [
"[parameters('privateEndpointName')]"
],
"location": "global",
"tags": {},
"properties": {}
},
{
"type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
"apiVersion": "2018-09-01",
"name": "[concat(variables('privateDNSZone_name'), '/', parameters('vnetName'), 'link' )]",
"location": "global",
"dependsOn": [
"[resourceId('Microsoft.Network/privateDnsZones', variables('privateDNSZone_name'))]"
],
"properties": {
"virtualNetwork": {
"id": "[resourceId('Microsoft.Network/virtualNetworks', parameters('vnetName'))]"
},
"registrationEnabled": false
}
},
{
"type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups",
"apiVersion": "2020-03-01",
"name": "[concat(parameters('privateEndpointName'), '/', 'default')]",
"dependsOn": [
"[parameters('privateEndpointName')]",
"[variables('privateDNSZone_name')]"
],
"location": "[resourceGroup().Location]",
"properties": {
"privateDnsZoneConfigs": [
{
"name": "privatelink-queue-core-windows-net",
"properties": {
"privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones',variables('privateDNSZone_name'))]"
}
}
]
}
}
],
"outputs": {
}
}
For more details, please refer to here and here
I can create a Azure VM with a specific VHD from the template below but how do I also add it to an Availability Set. I can't do this after VM creation so I need to do it here.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string",
"metadata": {
"description": "Location to create the VM in"
}
},
"osDiskVhdUri": {
"type": "string",
"metadata": {
"description": "Uri of the existing VHD"
}
},
"osType": {
"type": "string",
"allowedValues": [
"Windows",
"Linux"
],
"metadata": {
"description": "Type of OS on the existing vhd"
}
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_D2",
"metadata": {
"description": "Size of the VM"
}
},
"vmName": {
"type": "string",
"metadata": {
"description": "Name of the VM"
}
}
},
"variables": {
"api-version": "2015-06-15",
"addressPrefix": "10.0.0.0/16",
"subnetName": "Subnet",
"subnetPrefix": "10.0.0.0/24",
"publicIPAddressName": "specializedVMPublicIP",
"publicIPAddressType": "Dynamic",
"virtualNetworkName": "specializedVMVNET",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
"subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]",
"nicName": "specializedVMNic"
},
"resources": [
{
"apiVersion": "[variables('api-version')]",
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"location": "[parameters('location')]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetPrefix')]"
}
}
]
}
},
{
"apiVersion": "[variables('api-version')]",
"type": "Microsoft.Network/networkInterfaces",
"name": "[variables('nicName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]",
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]"
},
"subnet": {
"id": "[variables('subnetRef')]"
}
}
}
]
}
},
{
"apiVersion": "[variables('api-version')]",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('publicIPAddressName')]",
"location": "[parameters('location')]",
"properties": {
"publicIPAllocationMethod": "[variables('publicIPAddressType')]"
}
},
{
"apiVersion": "[variables('api-version')]",
"type": "Microsoft.Compute/virtualMachines",
"name": "[parameters('vmName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('vmSize')]"
},
"storageProfile": {
"osDisk": {
"name": "[concat(parameters('vmName'),'-osDisk')]",
"osType": "[parameters('osType')]",
"caching": "ReadWrite",
"vhd": {
"uri": "[parameters('osDiskVhdUri')]"
},
"createOption": "Attach"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]"
}
]
}
}
}
]
}
The best way to figure things like this out is to poke through the templates until you find what you need!
So according to this template, you create an Availability Set like this
"resources": [
{
"type": "Microsoft.Compute/availabilitySets",
"name": "availabilitySet1",
"apiVersion": "2015-06-15",
"location": "[parameters('location')]",
"properties": {
"platformFaultDomainCount": "3",
"platformUpdateDomainCount": "20"
}
}
]
and then (according to this) you use it like this
"apiVersion": "[variables('apiVersion')]",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat('myvm', copyIndex())]",
"location": "[variables('location')]",
"copy": {
"name": "virtualMachineLoop",
"count": "[parameters('numberOfInstances')]"
},
"dependsOn": [
"[concat('Microsoft.Network/networkInterfaces/', 'nic', copyindex())]",
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]"
],
"properties": {
"availabilitySet": {
"id": "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]"
},
You would need to be looking at the Microsoft.Compute/availabilitySets resource provider, here is some sample JSON from one of my templates.
"resources": [
{
"type": "Microsoft.Compute/availabilitySets",
"name": "availabilitySet1",
"apiVersion": "2015-06-15",
"location": "[parameters('location')]",
"properties": {
"platformFaultDomainCount": "3",
"platformUpdateDomainCount": "20"
}
}
]
You then need to use the availabilitySet property of the virtualMachines resource provider to add the VMs to the availability set. Make sure you use dependsOn to ensure the availability set is created before the VM. As an example if you refering to it by name:
"properties": {
"hardwareProfile": { "vmSize": "Standard_A0" },
"networkProfile": ...,
"availabilitySet": { "id": "availabilitySet1" },
}