Reputation: 1767
I am able to grant my SQL Server Identity membership of the Storage Blob Contributor role on my storage account using an ARM template.
However, when creating my Audit resource (which has dependsOn references to both the Storage Account and to the SQL Server) it looks like it is trying to create this before the RBAC permission has been granted as I get
{
"status": "Failed",
"error": {
"code": "ResourceDeploymentFailure",
"message": "The resource operation completed with terminal provisioning state 'Failed'.",
"details": [
{
"code": "BlobAuditingInsufficientStorageAccountPermissions",
"message": "Insufficient read or write permissions on storage account 'myStorage'. Add permissions to the server Identity to the storage account."
}
]
}
}
Oddly, I have this for Vulnerability Scans from the same server to another Storage Account and this succeeded. I don't know if that was simply a quirk of the way that Azure decided to order the deployment.
Anyway, is there a way to add a dependsOn reference to the RBAC permission so that I don't try to create the Audit destination to Storage until it has permissions?
To be clear, the RBAC assignment is a sub-resource of the Storage Account:
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"name": "[variables('auditStorageAccount')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[variables('uniqueSQLName')]"
],
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "StorageV2",
"properties": {
"isHnsEnabled": false,
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [],
"ipRules": [],
"defaultAction": "Deny"
},
"supportsHttpsTrafficOnly": true,
"encryption": {
"services": {
"file": {
"keyType": "Account",
"enabled": true
},
"blob": {
"keyType": "Account",
"enabled": true
}
},
"keySource": "Microsoft.Storage"
},
"accessTier": "Hot"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
"apiVersion": "2020-03-01-preview",
"name": "[concat(variables('auditStorageAccount'), '/Microsoft.Authorization/', guid(uniqueString(variables('auditStorageAccount'))))]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('auditStorageAccount'))]",
"[resourceId('Microsoft.Sql/servers', variables('uniqueSQLName'))]"
],
"properties": {
"roleDefinitionId": "[variables('StorageBlobContributor')]",
"principalId": "[reference(resourceId('Microsoft.Sql/servers', variables('uniqueSQLName')), '2019-06-01-preview', 'Full').identity.principalId]",
"scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('auditStorageAccount'))]",
"principalType": "ServicePrincipal"
}
}
]
}
My assumption was that having it as a sub-resource would ensure that it was in place for anything that then had a dependsOn to the Storage Account
Upvotes: 0
Views: 1308
Reputation: 23111
According to the error, I think when you deploy the SQL audit log resource, the assigned role action does not complete successfully.So We need to define in the template that the audit log resource depends on the role assignment actions
For example
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"sqlServerName": {
"type": "string",
"defaultValue": "[concat('sql-', uniqueString(resourceGroup().id))]",
"metadata": {
"description": "Name of the SQL server"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
"sqlAdministratorLogin": {
"type": "string",
"defaultValue":"sqladmin",
"metadata": {
"description": "The administrator username of the SQL Server."
}
},
"sqlAdministratorLoginPassword": {
"type": "securestring",
"defaultValue":"Password0123!",
"metadata": {
"description": "The administrator password of the SQL Server."
}
},
"storageAccountName": {
"type": "string",
"defaultValue": "[concat('sqlaudit', uniqueString(resourceGroup().id))]",
"metadata": {
"description": "The name of the auditing storage account."
}
}
},
"variables": {
"StorageBlobContributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]",
"uniqueRoleGuid": "[guid(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), variables('storageBlobContributor'), resourceId('Microsoft.Sql/servers', parameters('sqlServerName')))]"
},
"resources": [{
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('storageAccountName')]",
"apiVersion": "2019-06-01",
"location": "[parameters('location')]",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"defaultAction": "Allow"
}
},
"resources": [{
"type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
"apiVersion": "2020-03-01-preview",
"name": "[concat(parameters('storageAccountName'), '/Microsoft.Authorization/', variables('uniqueRoleGuid'))]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers', parameters('sqlServerName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
],
"properties": {
"roleDefinitionId": "[variables('StorageBlobContributor')]",
"principalId": "[reference(resourceId('Microsoft.Sql/servers', parameters('sqlServerName')), '2019-06-01-preview', 'Full').identity.principalId]",
"scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]",
"principalType": "ServicePrincipal"
}
}
]
}, {
"type": "Microsoft.Sql/servers",
"apiVersion": "2019-06-01-preview",
"location": "[parameters('location')]",
"name": "[parameters('sqlServerName')]",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"administratorLogin": "[parameters('sqlAdministratorLogin')]",
"administratorLoginPassword": "[parameters('sqlAdministratorLoginPassword')]",
"version": "12.0"
},
"tags": {
"displayName": "[parameters('sqlServerName')]"
},
"resources": [{
"type": "auditingSettings",
"apiVersion": "2019-06-01-preview",
"name": "DefaultAuditingSettings",
"dependsOn": [
"[parameters('sqlServerName')]",
"[parameters('storageAccountName')]",
"[extensionResourceId(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), 'Microsoft.Authorization/roleAssignments/', variables('uniqueRoleGuid'))]"
],
"properties": {
"state": "Enabled",
"storageEndpoint": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').PrimaryEndpoints.Blob]",
"storageAccountAccessKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value]",
"auditActionsAndGroups": [
"SUCCESSFUL_DATABASE_AUTHENTICATION_GROUP",
"FAILED_DATABASE_AUTHENTICATION_GROUP",
"BATCH_COMPLETED_GROUP"
],
"storageAccountSubscriptionId": "[subscription().subscriptionId]",
"isStorageSecondaryKeyInUse": false
}
}
]
}
]
}
New-AzResourceGroupDeployment -ResourceGroupName <resource-group-name> -TemplateFile <path-to-template>
For more details, please refer to the sample
Upvotes: 1