Rohit
Rohit

Reputation: 4158

ARM templates cyclic/circular dependency resolution

I created few resrources through Azure Portal in the following order.

  1. Created a virtual network with two subnets and on one the subnet1 I enabled the Storage Service End point.
  2. Created a storage account stgaccount1 and then on the firewall settings for the storage account, I added the subnet1.
  3. 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.

  1. Service Endpoind policy is dependent on Storage Account.
  2. Storage Account is dependent on subnet1 as the access is allowed only for this subnet.
  3. 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"
            }
        }

    ]
}

Upvotes: 1

Views: 1458

Answers (1)

bmoore-msft
bmoore-msft

Reputation: 8717

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

Upvotes: 1

Related Questions