Data breaches caused by cloud misconfiguration have been seen for the past few years. One of the most common misconfigurations is granting public access to cloud storage service. Such a data is often unprotected, making them to be accessed without any authentication method. Microsoft recently introduced a new protection feature to help avoid public access on storage account. The feature introduces a new property named allowBlobPublicAccess.
In this article, let’s explore the feature as well as how to deploy and monitor it at scale.
Overview
As said from the beginning of the article, allowBlobPublicAccess is a new property in Azure Storage which allows you to control public access on all Blob storage objects. This is a boolean type with only two values: False or True. When allowBlobPublicAccess is set False, the following operations are failed:
- Access to blob(s) without authentication (Access Key, SAS, Azure AD)
- Change ACL on a container (from Private to Public).
- Create a new container with public access setting.
When creating a new storage account, you can enable/disable this feature in Advanced tab.
Enable/Disable allowBlobPublicAccess
allowBlobPublicAccess can be easily enabled or disabled via Azure Portal from Configuration page of the target storage account.
You can use Azure CLI to enable
storage_account='jpstoragedata' rg_name='azsec-corporate-rg' resourceId=$(az storage account show -g $rg_name \ -n $storage_account \ --query id \ --output tsv) az resource update --ids $resourceId \ --set properties.allowBlobPublicAccess=false
or Azure PowerShell
$storage_account = 'jpstoragedata2' $rg_name = 'azsec-corporate-rg' $storage = Get-AzStorageAccount -ResourceGroupName $rg_name ` -Name $storage_account $resource = Get-AzResource -ResourceId $storage.Id $resource.Properties.allowBlobPublicAccess = 'False' $resource | Set-AzResource -Force
Verify allowBlobPublicAccess
There are ways to verify allowBlobPublicAccess:
- Use Azure Portal to check storage account configuration
- Use Azure CLI or Azure PowerShell to read allowBlobPublicAccess property.
- Use Azure Resource Graph Explorer.
- Use Azure Policy
Azure Resource Graph Query
Because allowBlobPublicAccess is a property in storage account resource so you can use Azure Resource Graph query:
resources | where type =~ 'Microsoft.Storage/storageAccounts' | extend allowBlobPublicAccess = parse_json(properties).allowBlobPublicAccess | project name, resourceGroup, allowBlobPublicAccess
If you see allowBlobPublicAccess property’s value is Null it means the storage account still permits public access until the property is set False.
Azure Policy
For on-demand audit and verification you can use Azure Portal or CLI/PowerShell. If you would like to periodically audit allowBlobPublicAccess you can use Azure Policy. See the reference below:
{ "mode": "All", "policyRule": { "if": { "allOf": [ { "field": "type", "equals": "Microsoft.Storage/storageAccounts" }, { "anyOf": [ { "field": "Microsoft.Storage/storageAccounts/allowBlobPublicAccess", "equals": "true" }, { "field": "Microsoft.Storage/storageAccounts/allowBlobPublicAccess", "equals": "false" }, { "field": "Microsoft.Storage/storageAccounts/allowBlobPublicAccess", "equals": "" } ] } ] }, "then": { "effect": "audit" } } }
Prevent allowBlobPublicAccess being set True
There is a use case that you want to prevent people from creating a storage account in which allowBlobPublicAccess is set True. In this case the most common approach is use Azure Policy with Deny mode.
{ "mode": "All", "policyRule": { "if": { "allOf": [ { "field": "type", "equals": "Microsoft.Storage/storageAccounts" }, { "field": "Microsoft.Storage/storageAccounts/allowBlobPublicAccess", "equals": "true" } ] }, "then": { "effect": "deny" } } }
Once you assign the Deny policy you can create a new storage account to verify the policy.
Remediate allowBlobPublicAccess
There are several ways to disable allowBlobPublicAccess in a scale. For example you can create a runbook and create a schedule to run it. You can also develop a script and run it manually once a day. This article shows you another way – Azure Policy with deployIfNotExists mode.
{ "properties": { "displayName": "Disable allowPublicAccess on Storage Account", "mode": "All", "description": "Disable allowPublicAccess on Storage Account", "parameters": { "allowBlobPublicAccess": { "type": "string", "defaultValue": "false" } }, "policyRule": { "if": { "allOf": [ { "field": "type", "equals": "Microsoft.Storage/storageAccounts" }, { "anyOf": [ { "field": "Microsoft.Storage/storageAccounts/allowBlobPublicAccess", "equals": "" }, { "field": "Microsoft.Storage/storageAccounts/allowBlobPublicAccess", "equals": "true" } ] } ] }, "then": { "effect": "deployIfNotExists", "details": { "type": "Microsoft.Storage/storageAccounts", "name": "[field('name')]", "existenceCondition": { "field": "Microsoft.Storage/storageAccounts/allowBlobPublicAccess", "equals": "false" }, "roleDefinitionIds": [ "/providers/microsoft.authorization/roleDefinitions/17d1049b-9a84-46fb-8f53-869881c3d3ab" ], "deployment": { "properties": { "mode": "incremental", "template": { "$schema": "http://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "allowBlobPublicAccess": { "type": "string" }, "storageAccountName": { "type": "string" }, "location": { "type": "string" } }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2019-06-01", "name": "[parameters('storageAccountName')]", "location": "[parameters('location')]", "dependsOn": [], "properties": { "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]" } } ] }, "parameters": { "location": { "value": "[field('location')]" }, "storageAccountName": { "value": "[field('name')]" }, "allowBlobPublicAccess": { "value": "[parameters('allowBlobPublicAccess')]" } } } } } } } } }
The role definition ID defined in the template is built-in RBAC role – Storage Account Contributor.