ARM templates cyclic/circular dependency resolution - azure

I created few resrources through Azure Portal in the following order.
Created a virtual network with two subnets and on one the subnet1 I enabled the Storage Service End point.
Created a storage account stgaccount1 and then on the firewall settings for the storage account, I added the subnet1.
Created a Service Endpoint Policy which allowed access only to stgaccount1 and associated this policy to subnet1.
This setup worked for me just fine and now I wanted to automate it and hence I generated the template for it, however just by looking at the template it seemed like there were circular dependencies in the template and when I tried deploying it failed as expected.
The dependency flow looked like this.
Service Endpoind policy is dependent on Storage Account.
Storage Account is dependent on subnet1 as the access is allowed only for this subnet.
Now since subnet is also associated with ServiceEndpoint policy, it is dependent on Service End Point Policy.
I am not sure who can I resolved this dependency chain or what is the right way for it.
Below is the template for reference.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymenttemplate.json#",
"contentversion": "1.0.0.0",
"parameters": {
"virtual_network_name": {
"defaultvalue": "vnet",
"type": "string"
},
"serviceEndPointPolicyName": {
"type": "string",
"defaultvalue": "storageEndPointPolicy"
}
},
"variables": {
"storageAccountName": "[tolower(concat(resourceGroup().name, 'storageaccount'))]",
"virtualNetworkName": "[concat(resourceGroup().name, parameters('virtual_network_name'))]"
},
"resources": [
{
"type": "Microsoft.Network/serviceEndpointPolicies",
"apiVersion": "2019-11-01",
"name": "[parameters('serviceEndPointPolicyName')]",
"location": "eastus",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
],
"properties": {
"serviceEndpointPolicyDefinitions": [
{
"name": "[concat(parameters('serviceEndPointPolicyName'), '_Microsoft.Storage')]",
"properties": {
"service": "Microsoft.Storage",
"serviceResources": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
]
}
}
]
}
},
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"name": "[variables('storageAccountName')]",
"location": "eastus",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('virtualNetworkName'), 'subent1')]"
],
"sku": {
"name": "Standard_RAGRS",
"tier": "Standard"
},
"kind": "StorageV2",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [
{
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('virtualNetworkName'), 'subent1')]",
"action": "Allow",
"state": "Succeeded"
}
],
"ipRules": [
],
"defaultAction": "Deny"
},
"supportsHttpsTrafficOnly": false,
"encryption": {
"services": {
"file": {
"keyType": "Account",
"enabled": true
},
"blob": {
"keyType": "Account",
"enabled": true
}
},
"keySource": "Microsoft.Storage"
},
"accessTier": "Hot"
}
},
{
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2019-11-01",
"name": "[variables('virtualNetworkName')]",
"location": "eastus",
"dependsOn": [
"[resourceId('Microsoft.Network/serviceEndpointPolicies', parameters('serviceEndPointPolicyName'))]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"10.0.0.0/16"
]
},
"subnets": [
{
"name": "subnet2",
"properties": {
"addressPrefix": "10.0.1.0/24",
"delegations": [
],
"privateEndpointNetworkPolicies": "Enabled",
"privateLinkServiceNetworkPolicies": "Enabled"
}
},
{
"name": "subent1",
"properties": {
"addressPrefix": "10.0.0.0/24",
"serviceEndpointPolicies": [
{
"id": "[resourceId('Microsoft.Network/serviceEndpointPolicies', parameters('serviceEndPointPolicyName'))]"
}
],
"serviceEndpoints": [
{
"service": "Microsoft.Storage",
"locations": [
"*"
]
}
],
"delegations": [
],
"privateEndpointNetworkPolicies": "Enabled",
"privateLinkServiceNetworkPolicies": "Enabled"
}
}
],
"virtualNetworkPeerings": [
],
"enableDdosProtection": false,
"enableVmProtection": false
}
},
{
"type": "Microsoft.Network/virtualNetworks/subnets",
"apiVersion": "2019-11-01",
"name": "[concat(variables('virtualNetworkName'), '/subent1')]",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]",
"[resourceId('Microsoft.Network/serviceEndpointPolicies', parameters('serviceEndPointPolicyName'))]"
],
"properties": {
"addressPrefix": "10.0.0.0/24",
"serviceEndpointPolicies": [
{
"id": "[resourceId('Microsoft.Network/serviceEndpointPolicies', parameters('serviceEndPointPolicyName'))]"
}
],
"serviceEndpoints": [
{
"service": "Microsoft.Storage",
"locations": [
"*"
]
}
],
"delegations": [
],
"privateEndpointNetworkPolicies": "Enabled",
"privateLinkServiceNetworkPolicies": "Enabled"
}
},
{
"type": "Microsoft.Network/virtualNetworks/subnets",
"apiVersion": "2019-11-01",
"name": "[concat(variables('virtualNetworkName'), '/subnet2')]",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]"
],
"properties": {
"addressPrefix": "10.0.1.0/24",
"delegations": [
],
"privateEndpointNetworkPolicies": "Enabled",
"privateLinkServiceNetworkPolicies": "Enabled"
}
}
]
}

Export problems aside, follow the same steps in your template (sequence) that you followed in the portal. Below is my version of that... Essentially you'll deploy the vnet first without the policies and then add the policy later...
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymenttemplate.json#",
"contentversion": "1.0.0.0",
"parameters": {
"virtual_network_name": {
"defaultvalue": "vnet",
"type": "string"
},
"serviceEndPointPolicyName": {
"type": "string",
"defaultvalue": "storageEndPointPolicy"
}
},
"variables": {
"storageAccountName": "[uniqueString(resourceGroup().id)]",
"virtualNetworkName": "[parameters('virtual_network_name')]"
},
"resources": [
{
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2019-11-01",
"name": "[variables('virtualNetworkName')]",
"location": "eastus",
"properties": {
"addressSpace": {
"addressPrefixes": [
"10.0.0.0/16"
]
},
"subnets": [
{
"name": "subnet2",
"properties": {
"addressPrefix": "10.0.1.0/24",
"delegations": [
],
"privateEndpointNetworkPolicies": "Enabled",
"privateLinkServiceNetworkPolicies": "Enabled"
}
},
{
"name": "subent1",
"properties": {
"addressPrefix": "10.0.0.0/24",
"serviceEndpoints": [
{
"service": "Microsoft.Storage",
"locations": [
"*"
]
}
],
"privateEndpointNetworkPolicies": "Enabled",
"privateLinkServiceNetworkPolicies": "Enabled"
}
}
],
"enableDdosProtection": false,
"enableVmProtection": false
}
},
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"name": "[variables('storageAccountName')]",
"location": "eastus",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]"
],
"sku": {
"name": "Standard_RAGRS",
"tier": "Standard"
},
"kind": "StorageV2",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [
{
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('virtualNetworkName'), 'subent1')]",
"action": "Allow",
"state": "Succeeded"
}
],
"defaultAction": "Deny"
},
"supportsHttpsTrafficOnly": false,
"encryption": {
"services": {
"file": {
"keyType": "Account",
"enabled": true
},
"blob": {
"keyType": "Account",
"enabled": true
}
},
"keySource": "Microsoft.Storage"
},
"accessTier": "Hot"
}
},
{
"type": "Microsoft.Network/serviceEndpointPolicies",
"apiVersion": "2019-11-01",
"name": "[parameters('serviceEndPointPolicyName')]",
"location": "eastus",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
],
"properties": {
"serviceEndpointPolicyDefinitions": [
{
"name": "[concat(parameters('serviceEndPointPolicyName'), '_Microsoft.Storage')]",
"properties": {
"service": "Microsoft.Storage",
"serviceResources": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
]
}
}
]
}
},
{
"type": "Microsoft.Network/virtualNetworks/subnets",
"apiVersion": "2019-11-01",
"name": "[concat(variables('virtualNetworkName'), '/subent1')]",
"dependsOn": [
"[resourceId('Microsoft.Network/serviceEndpointPolicies', parameters('serviceEndPointPolicyName'))]"
],
"properties": {
"addressPrefix": "10.0.0.0/24",
"serviceEndpointPolicies": [
{
"id": "[resourceId('Microsoft.Network/serviceEndpointPolicies', parameters('serviceEndPointPolicyName'))]"
}
],
"serviceEndpoints": [
{
"service": "Microsoft.Storage",
"locations": [
"*"
]
}
],
"privateEndpointNetworkPolicies": "Enabled",
"privateLinkServiceNetworkPolicies": "Enabled"
}
}
]
}

Related

ARM template for 2 nets in mutual peering

I need to build a custom arm template that does the following:
create virtual-network-1
create virtual-network-2
create peering from virtual-network-1 to virtual-network-2
create peering from virtual-network-2 to virtual-network-1
I have created these resources manually, and generated the corresponding arm template, but when I try to run the template I receive a circular dependency error.
Any help is appreciated!
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"virtualNetworks_vnet1_name": {
"defaultValue": "vnet1",
"type": "String"
},
"virtualNetworks_vnet2_name": {
"defaultValue": "vnet2",
"type": "String"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2020-11-01",
"name": "[parameters('virtualNetworks_vnet1_name')]",
"location": "centralus",
"dependsOn": [
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"10.1.0.0/16"
]
},
"enableDdosProtection": false
}
},
{
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2020-11-01",
"name": "[parameters('virtualNetworks_vnet2_name')]",
"location": "centralus",
"dependsOn": [
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"10.2.0.0/16"
]
},
"enableDdosProtection": false
}
},
{
"type": "Microsoft.Network/virtualNetworks/subnets",
"apiVersion": "2020-11-01",
"name": "[concat(parameters('virtualNetworks_vnet1_name'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworks_vnet1_name'))]"
],
"properties": {
"addressPrefix": "10.1.0.0/24",
"delegations": [],
"privateEndpointNetworkPolicies": "Enabled",
"privateLinkServiceNetworkPolicies": "Enabled"
}
},
{
"type": "Microsoft.Network/virtualNetworks/subnets",
"apiVersion": "2020-11-01",
"name": "[concat(parameters('virtualNetworks_vnet2_name'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworks_vnet2_name'))]"
],
"properties": {
"addressPrefix": "10.2.0.0/16",
"delegations": [],
"privateEndpointNetworkPolicies": "Enabled",
"privateLinkServiceNetworkPolicies": "Enabled"
}
},
{
"type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings",
"apiVersion": "2020-11-01",
"name": "[concat(parameters('virtualNetworks_vnet1_name'), '/peer1')]",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworks_vnet1_name'))]",
"[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworks_vnet2_name'))]"
],
"properties": {
"peeringState": "Connected",
"remoteVirtualNetwork": {
"id": "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworks_vnet2_name'))]"
},
"allowVirtualNetworkAccess": true,
"allowForwardedTraffic": true,
"allowGatewayTransit": false,
"useRemoteGateways": false,
"remoteAddressSpace": {
"addressPrefixes": [
"10.2.0.0/16"
]
}
}
},
{
"type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings",
"apiVersion": "2020-11-01",
"name": "[concat(parameters('virtualNetworks_vnet2_name'), '/peer2')]",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworks_vnet2_name'))]",
"[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworks_vnet1_name'))]"
],
"properties": {
"peeringState": "Connected",
"remoteVirtualNetwork": {
"id": "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworks_vnet1_name'))]"
},
"allowVirtualNetworkAccess": true,
"allowForwardedTraffic": true,
"allowGatewayTransit": false,
"useRemoteGateways": false,
"remoteAddressSpace": {
"addressPrefixes": [
"10.1.0.0/16"
]
}
}
}
]
}

Circular dependency issue in ARM template for Cosmos DB with encryption

I want to create an ARM template for encrypted CosmosDB by customer managed key
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
...
},
"functions": [],
"variables": {
...
},
"resources": [
{
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2020-04-01-preview",
"name": "[variables('keyVaultName')]",
"location": "westeurope",
"properties": {
"sku": {
"family": "A",
"name": "Standard"
},
"tenantId": "[parameters('tenantId')]",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('dbAccountName'))]"
],
"accessPolicies": [
{
"tenantId": "[parameters('tenantId')]",
"objectId": "[reference(resourceId('Microsoft.DocumentDB/databaseAccounts', variables('dbAccountName')), '2021-03-01-preview', 'full').identity.principalId]",
"permissions": {
"keys": [
"get",
"wrapKey",
"unwrapKey"
]
}
}
],
"enabledForDeployment": false,
"enabledForDiskEncryption": false,
"enabledForTemplateDeployment": false,
"enableSoftDelete": true,
"softDeleteRetentionInDays": 90,
"enableRbacAuthorization": false,
"vaultUri": "[concat('https://', variables('keyVaultName'), '.vault.azure.net/')]",
"provisioningState": "Succeeded",
"enablePurgeProtection": true
}
},
{
"type": "Microsoft.KeyVault/vaults/keys",
"apiVersion": "2020-04-01-preview",
"name": "[concat(variables('keyVaultName'), '/', variables('keyVaultName'), '-cosmos-db')]",
"location": "westeurope",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]"
],
"properties": {
"crv": "P-256",
"kty": "EC",
"key_size": 4096,
"keyOps": [
"wrapKey",
"unwrapKey"
],
"attributes": {
"enabled": true
}
}
},
{
"type": "Microsoft.DocumentDB/databaseAccounts",
"name": "[variables('dbAccountName')]",
"apiVersion": "2021-01-15",
"location": "[parameters('location')]",
"kind": "MongoDB",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"consistencyPolicy": "[variables('consistencyPolicy')[parameters('defaultConsistencyLevel')]]",
"locations": "[variables('locations')]",
"databaseAccountOfferType": "Standard",
"apiProperties": {
"serverVersion": "[parameters('serverVersion')]"
},
"keyVaultKeyUri": "[concat('https://', variables('keyVaultName'), '.vault.azure.net/keys/', variables('keyVaultName'), '-cosmos-db')]"
},
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults/keys', variables('keyVaultName'), concat(variables('keyVaultName'), '-cosmos-db'))]"
]
}
],
"outputs": {
...
}
}
I was trying approach with nested template but getting such error after deployment: "DatabaseAccount name '****' already exists"
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
...
},
"functions": [],
"variables": {
...
},
"resources": [
{
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2020-04-01-preview",
"name": "[variables('keyVaultName')]",
"location": "westeurope",
"properties": {
"sku": {
"family": "A",
"name": "Standard"
},
"tenantId": "[parameters('tenantId')]",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('dbAccountName'))]",
"[resourceId('Microsoft.Web/sites', variables('appName'))]"
],
"accessPolicies": [
{
"tenantId": "[parameters('tenantId')]",
"objectId": "[reference(resourceId('Microsoft.DocumentDB/databaseAccounts', variables('dbAccountName')), '2021-03-01-preview', 'full').identity.principalId]",
// "objectId": "d8749310-a50e-457e-97cb-c6e8ea601eb9",
"permissions": {
"keys": [
"get",
"wrapKey",
"unwrapKey"
]
}
}
],
"enabledForDeployment": false,
"enabledForDiskEncryption": false,
"enabledForTemplateDeployment": false,
"enableSoftDelete": true,
"softDeleteRetentionInDays": 90,
"enableRbacAuthorization": false,
"vaultUri": "[concat('https://', variables('keyVaultName'), '.vault.azure.net/')]",
"provisioningState": "Succeeded",
"enablePurgeProtection": true
}
},
{
"type": "Microsoft.KeyVault/vaults/keys",
"apiVersion": "2020-04-01-preview",
"name": "[concat(variables('keyVaultName'), '/', variables('keyVaultName'), '-cosmos-db')]",
"location": "westeurope",
// "dependsOn": [
// "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]"
// ],
"properties": {
"crv": "P-256",
"kty": "EC",
"key_size": 4096,
"keyOps": [
"wrapKey",
"unwrapKey"
],
"attributes": {
"enabled": true
}
}
},
{
"type": "Microsoft.DocumentDB/databaseAccounts",
"name": "[variables('dbAccountName')]",
"apiVersion": "2021-01-15",
"location": "[parameters('location')]",
"kind": "MongoDB",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"consistencyPolicy": "[variables('consistencyPolicy')[parameters('defaultConsistencyLevel')]]",
"locations": "[variables('locations')]",
"databaseAccountOfferType": "Standard",
"apiProperties": {
"serverVersion": "[parameters('serverVersion')]"
}
// "keyVaultKeyUri": "[concat('https://', variables('keyVaultName'), '.vault.azure.net/keys/', variables('keyVaultName'), '-cosmos-db')]"
},
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults/keys', variables('keyVaultName'), concat(variables('keyVaultName'), '-cosmos-db'))]"
]
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2020-10-01",
"name": "databaseUpdate",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults/keys', variables('keyVaultName'), concat(variables('keyVaultName'), '-cosmos-db'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.DocumentDB/databaseAccounts",
"name": "[variables('dbAccountName')]",
"apiVersion": "2021-01-15",
"location": "[parameters('location')]",
"kind": "MongoDB",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"consistencyPolicy": "[variables('consistencyPolicy')[parameters('defaultConsistencyLevel')]]",
"locations": "[variables('locations')]",
"databaseAccountOfferType": "Standard",
"apiProperties": {
"serverVersion": "[parameters('serverVersion')]"
},
"keyVaultKeyUri": "[concat('https://', variables('keyVaultName'), '.vault.azure.net/keys/', variables('keyVaultName'), '-cosmos-db')]"
}
},
{
"type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases",
"name": "[concat(variables('dbAccountName'), '/', variables('dbName'))]",
"apiVersion": "2021-01-15",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts/', variables('dbAccountName'))]"
],
"properties": {
"resource": {
"id": "[variables('dbName')]"
},
"options": {
"throughput": "[parameters('throughput')]"
}
}
}
]
}
}
}
],
"outputs": {
...
}
}
I was also trying to create key vault resource and key vault access policy separately. But getting exception
{"code":"DeploymentFailed","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.","details":[{"code":"BadRequest","message":"Access policies operation not permitted. Allowed operations are "add", "replace", and "remove"."}]}

How to enable using arm template vulnerabilityAssessments for sql server with storage account behind firewall

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"
}
}
]
}

Arm template if condition

I am trying to implement if condition for the arm template. Idea is from the parameter to read if it suppose to deploy in prod or nonprod sub and have the subnets predefined. Then deploy storage and add some subnets to the storage account virtual network list.
The following line causing troubles:
"virtualNetworkRules": "[if(equals(parameters('Sub'), 'nonprod'),'variables('nonprodvirtualNetworkSubnets').virtualNetworkRulesCopy', 'variables('prodvirtualNetworkSubnets').virtualNetworkRulesCopy', )]",
All help is much appreciated.
"Parameters": {
"Sub": {
"type": "string",
"defaultValue": "nonprod",
"metadata": {
"description": "Prod or nonprod sub"
}
}
},
"variables": {
"subscriptionId": "[subscription().subscriptionId]",
"resourcegroupName": "[toUpper(concat(parameters('splitSubscriptionName')[0], '-', parameters('splitSubscriptionName')[1], '-', parameters('splitSubscriptionName')[2], '-02-NET-RSG'))]",
"virtualNetworkname": "[toLower(concat(parameters('splitSubscriptionName')[0], '-', parameters('splitSubscriptionName')[1], '-', parameters('splitSubscriptionName')[2], '-02-NET-', parameters('splitSubscriptionName')[3], '-00-net'))]",
"storageAccountType": "Standard_LRS", // "allowedValues": ["Standard_LRS", "Standard_GRS", "Standard_ZRS", "Premium_LRS"]
"blobServicesName": "default",
"VirtualNetworkExternalId": "[concat('/subscriptions/', variables('subscriptionId'), '/resourceGroups/', variables('resourcegroupName'), '/providers/Microsoft.Network/virtualNetworks/', variables('virtualNetworkname'), '/subnets/')]",
"nonprodAllowedSubnets": [
"mngm00-devtest-sub",
"mngm01-devtest-sub",
"mngm02-devtest-sub"
],
"prodAllowedSubnets": [
"mngm00-prod-sub",
"mngm01-prod-sub"
],
"nonprodvirtualNetworkSubnets": {
"copy": [
{
"name": "virtualNetworkRulesCopy",
"count": "[length(variables('nonprodAllowedSubnets'))]",
"input": {
"id": "[concat(variables('VirtualNetworkExternalId'), variables('nonprodAllowedSubnets')[copyIndex('virtualNetworkRulesCopy')])]",
"action": "Allow",
"state": "Succeeded"
}
}
]
},
"prodvirtualNetworkSubnets": {
"copy": [
{
"name": "virtualNetworkRulesCopy",
"count": "[length(variables('prodAllowedSubnets'))]",
"input": {
"id": "[concat(variables('VirtualNetworkExternalId'), variables('prodAllowedSubnets')[copyIndex('virtualNetworkRulesCopy')])]",
"action": "Allow",
"state": "Succeeded"
}
}
]
}
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-04-01",
"name": "[parameters('storageAccountName')]",
"location": "[resourceGroup().location]",
"sku": {
"name": "[variables('storageAccountType')]"
},
"kind": "[parameters('storageAccountKind')]",
"properties": {
"accessTier": "[parameters('accessTier')]",
"supportsHttpsTrafficOnly": true,
"allowBlobPublicAccess": false,
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": "[if(equals(parameters('Sub'), 'nonprod'),'variables('nonprodvirtualNetworkSubnets').virtualNetworkRulesCopy', 'variables('prodvirtualNetworkSubnets').virtualNetworkRulesCopy', )]",
"defaultAction": "Deny"
},
"encryption": {
"services": {
"file": {
"enabled": true
},
"blob": {
"enabled": true
}
},
"keySource": "Microsoft.Storage"
}
}
}
]
}
it should be like this:
[if(equals(parameters('Sub'), 'nonprod'), variables('nonprodvirtualNetworkSubnets').virtualNetworkRulesCopy, variables('prodvirtualNetworkSubnets').virtualNetworkRulesCopy]
so drop ' from your if

Why does setting CosmosDB throughputSettings result in "Entity with the specified id does not exist in the system"?

While trying to deploy a CosmosDB instance with 2 collections ("MyCollection1", "MyCollection2") I keep getting the error:
NotFound: Entity with the specified id does not exist in the system
So I keep searching for "resourceId" in my custom ARM template (please see below) but cannot find the erorr cause.
I don't understand, why does not the pipeline at least print the line number for me?
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"accountName": {
"defaultValue": "my-cosmosdb",
"type": "String"
}
},
"variables": {
"resourceName": "[concat(resourceGroup().name, '-', parameters('accountName'))]",
"resourceId": "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('resourceName'))]",
"apiVersion": "[providers('Microsoft.DocumentDB', 'databaseAccounts').apiVersions[0]]"
},
"outputs": {
"CosmosDbConnectionString": {
"type": "string",
"value": "[concat('AccountEndpoint=https://', variables('resourceName'), '.documents.azure.com:443/;AccountKey=', listKeys(variables('resourceId'), variables('apiVersion')).primaryMasterKey, ';')]"
},
"DatabaseName": {
"type": "string",
"value": "MyDB"
},
"CollectionName1": {
"type": "string",
"value": "MyCollection1"
},
"CollectionName2": {
"type": "string",
"value": "MyCollection2"
}
},
"resources": [
{
"type": "Microsoft.DocumentDB/databaseAccounts",
"apiVersion": "2020-03-01",
"name": "[variables('resourceName')]",
"location": "[resourceGroup().location]",
"tags": {
"defaultExperience": "DocumentDB"
},
"kind": "GlobalDocumentDB",
"properties": {
"publicNetworkAccess": "Enabled",
"enableAutomaticFailover": false,
"enableMultipleWriteLocations": false,
"isVirtualNetworkFilterEnabled": false,
"virtualNetworkRules": [],
"disableKeyBasedMetadataWriteAccess": false,
"databaseAccountOfferType": "Standard",
"consistencyPolicy": {
"defaultConsistencyLevel": "Session",
"maxIntervalInSeconds": 5,
"maxStalenessPrefix": 100
},
"locations": [
{
"locationName": "[resourceGroup().location]",
"provisioningState": "Succeeded",
"failoverPriority": 0,
"isZoneRedundant": false
}
],
"capabilities": []
}
},
{
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases",
"apiVersion": "2020-03-01",
"name": "[concat(variables('resourceName'), '/MyDB')]",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('resourceName'))]"
],
"properties": {
"resource": {
"id": "MyDB"
},
"options": {}
}
},
{
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers",
"apiVersion": "2020-03-01",
"name": "[concat(variables('resourceName'), '/MyDB/MyCollection1')]",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', variables('resourceName'), 'MyDB')]",
"[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('resourceName'))]"
],
"properties": {
"resource": {
"id": "MyCollection1",
"indexingPolicy": {
"indexingMode": "consistent",
"automatic": true,
"includedPaths": [
{
"path": "/*"
}
],
"excludedPaths": [
{
"path": "/\"_etag\"/?"
}
]
},
"partitionKey": {
"paths": [
"/partitionKey"
],
"kind": "Hash"
},
"uniqueKeyPolicy": {
"uniqueKeys": []
},
"conflictResolutionPolicy": {
"mode": "LastWriterWins",
"conflictResolutionPath": "/_ts"
}
},
"options": {}
}
},
{
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers",
"apiVersion": "2020-03-01",
"name": "[concat(variables('resourceName'), '/MyDB/MyCollection2')]",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', variables('resourceName'), 'MyDB')]",
"[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('resourceName'))]"
],
"properties": {
"resource": {
"id": "MyCollection2",
"indexingPolicy": {
"indexingMode": "consistent",
"automatic": true,
"includedPaths": [
{
"path": "/*"
}
],
"excludedPaths": [
{
"path": "/\"_etag\"/?"
}
]
},
"partitionKey": {
"paths": [
"/partitionKey"
],
"kind": "Hash"
},
"uniqueKeyPolicy": {
"uniqueKeys": []
},
"conflictResolutionPolicy": {
"mode": "LastWriterWins",
"conflictResolutionPath": "/_ts"
}
},
"options": {}
}
},
{
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/throughputSettings",
"apiVersion": "2020-03-01",
"name": "[concat(variables('resourceName'), '/MyDB/default')]",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', variables('resourceName'), 'MyDB')]",
"[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('resourceName'))]"
],
"properties": {
"resource": {
"throughput": 400
}
}
}
]
}
UPDATE:
I have removed the part creating collections and the error is still there.
UPDATE 2:
The following part seemingly causes the error, but why?
{
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/throughputSettings",
"apiVersion": "2020-03-01",
"name": "[concat(variables('resourceName'), '/MyDB/default')]",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', variables('resourceName'), 'MyDB')]",
"[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('resourceName'))]"
],
"properties": {
"resource": {
"throughput": 400
}
}
}
What is wrong with the dependsOn entry "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', variables('resourceName'), 'MyDB')]?
UPDATE 3:
Trying to deploy the complete ARM template listed above manually results in:
Try setting your throughput in the options for your database.
UPDATE: You cannot specify throughput on a resource that did not have it when initially provisioned. Databases and containers provisioned without throughput cannot be updated later to have it. Conversely, a resource provisioned with throughput, cannot be updated to remove. You must delete and recreate the resource. This will require migrating your data.
{
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases",
"apiVersion": "2020-03-01",
"name": "[concat(variables('resourceName'), '/MyDB')]",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('resourceName'))]"
],
"properties": {
"resource": {
"id": "MyDB"
},
"options": { "throughput": "[parameters('throughput')]" }
}
},
btw, there are lots of samples you can use to start with here Cosmos DB templates
The following has worked for me, I had to replace "sqlDatabases/throughputSettings" by "sqlDatabases/containers/throughputSettings":
{
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/throughputSettings",
"apiVersion": "2020-03-01",
"name": "[concat(variables('resourceName'), '/', variables('DatabaseName'), '/', variables('CollectionName1'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', variables('resourceName'), variables('databaseName'), variables('CollectionName1'))]",
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', variables('resourceName'), variables('databaseName'))]",
"[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('resourceName'))]"
],
"properties": {
"resource": {
"throughput": 400
}
}
}
And then similar entry for CollectionName2

Resources