Azure ARM Template with VM and subnet - azure

I have a resource group called network-rg containing a virtual network. I am trying to deploy a Virual Machine in a new resource group vm-rg. The VM should be connected to a new subnet on the vnet in network-rg. I am using one single ARM template with both the subnet and the VM and deploying to vm-rg. How do I specify the subnet in the ARM template when its vnet is in another resource group than the primary/default group for the deployment?
I would need to explicitly reference the vnet with the resource group. This would be similar to how a Network Interface deploy is referencing the subnet ID in its ipConfigurations properties list:
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/networkInterfaces",
"name": "[parameters('nicName')]",
"location": "[parameters('location')]",
"properties": {
"ipConfigurations": [{
"name": "ipconfig1",
"properties": {
"subnet": {
"id": "[variables('subnet1Ref')]"
}
}
}]
}

It seems you cannot create a subnet in another resource group in one template when you create a new resource group with resources. There no property for you to refer to the Vnet in another group.
If you really want to create a new subnet in another group in one template, you could take a look at linked and nested template. Hope this will help you.

You will need to add a variables (Resource in the template that references the parameter file) example below:
In the main.JSON file:
{
"name": "[parameters('networkInterfaceName')]",
"type": "Microsoft.Network/networkInterfaces",
"apiVersion": "2018-04-01",
"location": "[parameters('location')]",
"dependsOn": [
"[concat('Microsoft.Network/publicIpAddresses/', parameters('publicIpAddressName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"subnet": {
"id": "[variables('subnetRef')]"
},
"privateIPAllocationMethod": "Dynamic",
"publicIpAddress": {
"id": "[resourceId(parameters('resourceGroupName'),'Microsoft.Network/publicIpAddresses', parameters('publicIpAddressName'))]"
}
}
}
],
"enableAcceleratedNetworking": true,
"networkSecurityGroup": {
"id": "[resourceId(parameters('nsgResourceGroupName'), 'Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroupName'))]"
}
}
}
Add the following variables in main.JSON:
{
"name": "[parameters('networkInterfaceName')]",
"type": "Microsoft.Network/networkInterfaces",
"apiVersion": "2018-04-01",
"location": "[parameters('location')]",
"dependsOn": [
"[concat('Microsoft.Network/publicIpAddresses/', parameters('publicIpAddressName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"subnet": {
"id": "[variables('subnetRef')]"
},
"privateIPAllocationMethod": "Dynamic",
}
}
],
}
}
Then add the following parameters in the main.JSON file:
"parameters": {
"virtualNetworkName": {
"type": "string"
},
"subnetName": {
"type": "string"
},
In the main.parameters.json add the variable information:
"virtualNetworkName": {
"value": "<vnet name>"
},
"resourceGroupName": {
"value": "<whatever the rg is for the Network>"
},
"subnetName": {
"value": "<subnet name>"
},
Hope that helps.

Related

Add custom DNS Server IP to an Azure VM NIC using ARM Template

I have tried to use the ARM template code below to create an Azure VM NIC and custom its DNS Server IP address. However, it appears, the ARM template is not working. Please what could be wrong.
this line "dnsServers": "[[parameters('dnsAddress')]]" doesn't seem to work when the template is deployed and I get his error
"message": "Could not find member 'dnsSettings' on object of type 'NetworkInterfaceIpConfigurationProperties'. Path 'properties.ipConfigurations[0].properties.dnsSettings?
Has anyone else come across this issue?
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"dnsAddress": {
"type": "array",
"metadata": {
"Description": "The DNS address(es) of the DNS Server(s) used by the virtual network"
},
"defaultValue":["10.0.0.4"]
},
},
"variables": {
"nicName": "[concat(uniquestring(resourceGroup().id), 'myVMNic')]",
"addressPrefix": "10.0.0.0/16",
"subnetName": "Subnet",
"subnetPrefix": "10.0.0.0/24",
"virtualNetworkName": "MyVNET",
"subnetRef": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('virtualNetworkName'), variables('subnetName'))]"
},
"resources": [
{
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"apiVersion": "2020-05-01",
"location": "[resourceGroup().location]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetPrefix')]"
}
}
]
}
},
{
"type": "Microsoft.Network/networkInterfaces",
"name": "[variables('nicName')]",
"apiVersion": "2020-05-01",
"location": "[resourceGroup().location]",
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[variables('subnetRef')]"
},
"dnsSettings": {
"dnsServers": "[[parameters('dnsAddress')]]"
}
}
}
]
},
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
]
}
]
}
Based on the official ARM template reference of network interfaces, dnsSettings is not a member of ipConfigurations, it's at the same level as ipConfigurations under properties:
So just try to move dnsSettings to the same level as ipConfigurations as below:
{
"type": "Microsoft.Network/networkInterfaces",
"name": "[variables('nicName')]",
"apiVersion": "2020-05-01",
"location": "[resourceGroup().location]",
"properties": {
"ipConfigurations": [{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[variables('subnetRef')]"
}
}
}
],
"dnsSettings": {
"dnsServers": "[[parameters('dnsAddress')]]"
}
},
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
]
}

Nested ARM template and dependsOn in another Resource Group

I am trying to create a Function App with VNET Integration in ARM. I have made all that work just fine in one main template.
Now I have a new requirement where the VNET needs to be in another RG and thus seperate from the Func App RG, but the Func App still needs to have VNET integration to the VNET in the other RG.
I'm struggling how to define the ARM template, so that I deploy the Func App in one RG and VNET in another. The hard part is how to define this so that the Func App integrates into a VNET in another RG in the same ARM template using nested template.
Here is my ARM template:
"resources": [{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2019-10-01",
"name": "nestedTemplate",
"resourceGroup": "[parameters('VNETPeered_RG_Name')]",
"subscriptionId": "0a2009c0-e2ae-4991-aa0e-5c34c141e4cb",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [{
"comments": "Virtual Network for VNET integration feature in the Premium Plan for the Function App",
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2019-11-01",
"name": "[variables('virtual_network_name')]",
"location": "[resourceGroup().location]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('vnetAddressPrefix')]"
]
},
"subnets": [{
"name": "[variables('subnet_name')]",
"properties": {
"addressPrefix": "[parameters('subnet1Prefix')]",
"serviceEndpoints": [{
"service": "Microsoft.Storage",
"locations": [
"[resourceGroup().location]"
]
}
}
}]
}
}]
}
}
},
{
"comments": "Function App to host the functions themselves. Integrates into a VNET and makes use of Azure DNS Private Zones.",
"type": "Microsoft.Web/sites",
"apiVersion": "2019-08-01",
"name": "[variables('function_app_name')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"nestedTemplate",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storage_account_name'))]",
"[resourceId('Microsoft.Web/serverfarms', variables('app_service_plan_name'))]"
],
"kind": "functionapp",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('app_service_plan_name'))]",
"siteConfig": {
"appSettings": [{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(variables('application_insights_resourceId'), '2018-05-01-preview').InstrumentationKey]"
}]
},
"clientAffinityEnabled": true
},
"resources": [{
"type": "networkConfig",
"apiVersion": "2019-08-01",
"name": "virtualNetwork",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('function_app_name'))]"
],
"properties": {
"subnetResourceId": "[reference(resourceId('RG-FunctionsGroup','Microsoft.Network/virtualNetworks/subnets', 'vn-MY-VNET', 'sn-MY-SUBNET'),'2020-05-01')]",
"isSwift": true
}
}]
]
}
On this I get the following error when I try to deploy it with az deployment group command from az cli:
Deployment failed. Correlation ID: 39b0173b-8a51-42c5-a796-1d3427556194. {
"error": {
"code": "InternalServerError",
"message": "There was an unexpected InternalServerError. Please try again later. x-ms-correlation-request-id: 844e9f35-2e9c-411a-817d-9045511558cb"
}
}
reference() will work but TLDR; it's a little heavyweight
https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions-resource#resourceid
is all you need in this case. To "reference" any resource in ARM you'll use the resourceId - there are a handful of functions to help but it really helps if you understand the basics of the resourceId, which is summarized here:
https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions-resource#return-value-6
When you want a resourceId to a resource in the same deployment (which is not the same as the same template) you can use the shorthand version
resourceId({namespace/resourceType}, {resourceName})
If it's in a different RG, you need to add the RG param, and if it's in a different sub you need to add that too. I can't tell for certain with your snippet, but it looks like all you need in your case is this (assuming the vnet and fn app are in the same subscription):
"subnetResourceId": "[resourceId(parameters('VNETPeered_RG_Name'), 'Microsoft.Network/virtualNetworks/subnets', variables('virtual_network_name'), variables('subnet_name'))]"
That help?
Your problem is in this part of code:
"properties": {
"subnetResourceId": "[reference(resourceId('RG-FunctionsGroup','Microsoft.Network/virtualNetworks/subnets', 'vn-MY-VNET', 'sn-MY-SUBNET'),'2020-05-01')]",
"isSwift": true
}
You are pointing the subnet with the wrong resource group. Change the resource group where the vnet and the subnet is deployed.
"properties": {
"subnetResourceId": "[reference(resourceId(parameters('VNETPeered_RG_Name'),'Microsoft.Network/virtualNetworks/subnets', variables('virtual_network_name'), variables('subnet_name')),'2020-05-01')]",
"isSwift": true
}

Why is my ARM-deployment in a Invalidrequestformat

ARM template
Hey guys, we're trying out to implement a few new templates where we deploy a private Endpoint in an existing subnet. We've successfully set the PrivateEndpoint policies property using ARM, however when deploying the private Endpoint resource we run into a problem:
"resources": [
{
"name": "[variables('privateEndpointName')]",
"location": "[resourceGroup().location]",
"type": "Microsoft.Network/privateEndpoints",
"apiVersion": "2019-04-01",
"properties": {
"subnet": {
"id": "[parameters('subnetId')]"
},
"PrivateLinkServiceConnections": [
{
"properties": {
"privateLinkServiceId": "[parameters('privateLinkResource')]",
"groupIds": "[parameters('targetSubResource')]",
"requestMessage": "[parameters('requestMessage')]"
}
}
]
},
"tags": {
}
}
]
The parameters fed to the template are identical to deployment when using the portal and contain full resource URI's. Deploying to another resource, storage account or SQL has the same outcome.
We've verified the variable privateEndpointName using an empty deployment generating just output. So that's not the issue, but we still receive the following error:
Error
New-AzResourceGroupDeployment : 11:56:20 - Resource Microsoft.Network/privateEndpoints 'privateEndpointSubnet-pe-nameofthesqlserver' failed with message '{
"error": {
"code": "InvalidRequestFormat",
"message": "Cannot parse the request.",
"details": []
}
}'
Portal Template
Deployment with this using the portal is successful
"resources": [
{
"location": "[parameters('location')]",
"name": "[parameters('privateEndpointName')]",
"type": "Microsoft.Network/privateEndpoints",
"dependsOn": [
"[parameters('subnetDeploymentName')]"
],
"apiVersion": "2019-04-01",
"properties": {
"subnet": {
"id": "[parameters('subnet')]"
},
"privateLinkServiceConnections": [
{
"name": "[parameters('privateEndpointName')]",
"properties": {
"privateLinkServiceId": "[parameters('privateLinkResource')]",
"groupIds": "[parameters('targetSubResource')]"
}
}
]
},
"tags": {}
},
{
"apiVersion": "2017-05-10",
"name": "[parameters('subnetDeploymentName')]",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "[parameters('virtualNetworkResourceGroup')]",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"name": "tst2testst-weu-vnet-t/subnet-1",
"id": "/subscriptions/removedsubid/resourceGroups/blabla3/providers/Microsoft.Network/virtualNetworks/tst2testst-weu-vnet-t/subnets/subnet-1",
"properties": {
"provisioningState": "Succeeded",
"addressPrefix": "192.168.0.0/24",
"networkSecurityGroup": {
"id": "/subscriptions/removedsubid/resourceGroups/blabla3/providers/Microsoft.Network/networkSecurityGroups/vnet-id-nsg"
},
"serviceEndpoints": [],
"delegations": [],
"privateEndpointNetworkPolicies": "Disabled",
"privateLinkServiceNetworkPolicies": "Enabled"
},
"type": "Microsoft.Network/virtualNetworks/subnets",
"apiVersion": "2019-04-01"
}
]
}
}
}
]
Fixed!
privateLinkServiceConnections JSON-object also requires a name, doesn't look required in the Private Endpoint Arm reference. I'll set up a GitHub issue for it.

Azure RM Template. Deploy copy VM with unique secret from Key Vault

I would like to be able to create VMs amount of which I specify via parameters (achieved by copy) with different secret for each VM (ex. secret1 for VM1, secret2 for VM2, etc.) Here is a basic example of copy VM template:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"numberOfVMs": {
"type": "int",
"defaultValue": 1,
"minvalue": 1
},
"vmAdminUserName": {
"type": "string",
"minLength": 1
},
"vmAdminPassword": {
"type": "securestring"
}
},
"variables": {
"storageAccountName": "[concat('stor567', uniqueString(resourceGroup().id))]",
"storageAccountType": "Standard_LRS",
"vmWindowsOSVersion": "2016-Datacenter",
"vnetPrefix": "10.0.0.0/16",
"vnetSubnet1Name": "Subnet-1",
"vnetSubnet1Prefix": "10.0.0.0/24",
"nicVnetID": "[resourceId('Microsoft.Network/virtualNetworks', 'vnet')]",
"nicSubnetRef": "[concat(variables('nicVnetID'), '/subnets/', variables('vnetSubnet1Name'))]",
"vmImagePublisher": "MicrosoftWindowsServer",
"vmImageOffer": "WindowsServer",
"vmVmSize": "Standard_DS1_v2",
"vmVnetID": "[resourceId('Microsoft.Network/virtualNetworks', 'vnet')]",
"vmSubnetRef": "[concat(variables('vmVnetID'), '/subnets/', variables('vnetSubnet1Name'))]",
"vmStorageAccountContainerName": "vhds"
},
"resources": [
{
"name": "[variables('storageAccountName')]",
"type": "Microsoft.Storage/storageAccounts",
"location": "[resourceGroup().location]",
"apiVersion": "2015-06-15",
"dependsOn": [ ],
"properties": {
"accountType": "[variables('storageAccountType')]"
}
},
{
"name": "vnet",
"type": "Microsoft.Network/virtualNetworks",
"location": "[resourceGroup().location]",
"apiVersion": "2016-03-30",
"dependsOn": [ ],
"tags": {
"displayName": "vnet"
},
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('vnetPrefix')]"
]
},
"subnets": [
{
"name": "[variables('vnetSubnet1Name')]",
"properties": {
"addressPrefix": "[variables('vnetSubnet1Prefix')]"
}
}
]
}
},
{
"name": "[concat('NIC',copyindex())]",
"type": "Microsoft.Network/networkInterfaces",
"location": "[resourceGroup().location]",
"copy": {
"name": "nicLoop",
"count": "[parameters('numberOfVMs')]"
},
"apiVersion": "2016-03-30",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', 'vnet')]"
],
"tags": {
"displayName": "nic"
},
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[variables('nicSubnetRef')]"
}
}
}
]
}
},
{
"name": "[concat('VM',copyindex())]",
"type": "Microsoft.Compute/virtualMachines",
"location": "[resourceGroup().location]",
"copy": {
"name": "virtualMachineLoop",
"count": "[parameters('numberOfVMs')]"
},
"apiVersion": "2015-06-15",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]",
"nicLoop"
],
"tags": {
"displayName": "vm"
},
"properties": {
"hardwareProfile": {
"vmSize": "[variables('vmVmSize')]"
},
"osProfile": {
"computerName": "[concat('VM',copyindex())]",
"adminUsername": "[parameters('vmAdminUsername')]",
"adminPassword": "[parameters('vmAdminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('vmImagePublisher')]",
"offer": "[variables('vmImageOffer')]",
"sku": "[variables('vmWindowsOSVersion')]",
"version": "latest"
},
"osDisk": {
"name": "vmOSDisk",
"vhd": {
"uri": "[concat(reference(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2016-01-01').primaryEndpoints.blob, variables('vmStorageAccountContainerName'), '/', 'VM',copyIndex(),'-','OSdisk.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', concat('NIC',copyindex()))]"
}
]
}
}
}],
"outputs": {}
}
However, I'm struggling to integrate using of password as unique secrets from Key Vault in that template. If I use example from official documentation Reference a secret with static id VMs with secret1 for each VM will be created. And I can’t wrap Reference a secret with dynamic id into nested template because that would deploy my copied VMs again and again for the each number of VMs I would like to deploy. Please help me understand, how this challenge can be solved?
Links: Parent and Nested.
I'm not sure if that's what you meant (because i still think that i struggle to understand your problem).
These templates allow to deploy variable amount of vm's and use different keyvault keys as passwords for those. Example:
2 Windows VM's with one secret and 3 Ubuntu VM's with another
1 Windows VM with one secret and 4 Ubuntu VM's with another
You can easily extend that to other images, like centos.
As you can probably see after looking at the templates I'm using arrays and copyindex() to feed proper values where they belong.
Tell me if that's not what you are after. Be careful when using those, github raw links use some form of caching, so deploying from github might not work for you with errors, in that case just use the links I've provided (NOT RAW) to copy to local machine and upload to some service like pastebin, and deploy from there.

Deploy Azure Resource Manager Template to existing VNET via CLI

I have a VNET set up in Azure with a number of subnets each with their own NSG defining inbound and outbound rules.
Into these subnets I would like to deploy VM scale sets with autoscale rules (based on https://raw.githubusercontent.com/gbowerman/azure-myriad/master/vmss-ubuntu-scale/azuredeploy.json for example) with certain extensions (perhaps pulling some repos from github/docker).
In my template how do I define that the scale set / VM should be assigned to an existing subnet/NSG etc?
Well, that's fairly straight forward, you just need to specify the ID of the resource you are referencing.
Let's say you want to use existing subnet:
"parameters": {
...
"existingVirtualNetworkName": {
"type": "string",
"metadata": {
"description": "Name of the existing VNET"
}
},
"existingVirtualNetworkResourceGroup": {
"type": "string",
"metadata": {
"description": "Name of the existing VNET resource group"
}
},
"subnetName": {
"type": "string",
"metadata": {
"description": "Name of the subnet in the virtual network you want to use"
}
},
...
},
"variables": {
...
"vnetID": "[resourceId(parameters('existingVirtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('existingVirtualNetworkName'))]",
"subnetRef": "[concat(variables('vnetID'),'/subnets/', parameters('subnetName'))]",
...
}
"resources": [
...
{
"apiVersion": "[variables('api-version')]",
"type": "Microsoft.Network/networkInterfaces",
"name": "[variables('nicName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]"
],
"tags": {
"displayName": "NetworkInterface"
},
"properties": {
"ipConfigurations": [{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]"
},
"subnet": {
"id": "[variables('subnetRef')]"
}
}
}]
}
},
You would use the same approach for the Network Security Group.
Take a look here for more: https://github.com/Azure/azure-quickstart-templates/blob/master/201-vm-specialized-vhd-existing-vnet/azuredeploy.json

Resources