Search code examples
azureazure-sql-databaseazure-storageazure-rm-template

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

Solution

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

    enter image description here