How to secure Azure Storage Account

Bas van Bennekom
16 min readFeb 7, 2022

--

Over the last couple of years, I have helped different enterprises to build secure and scalable Azure solutions that are consumable by internal DevOps teams. At the moment, I mainly focus on the concept of Azure Landing Zones, which uses Policy-driven Governance to enforce compliance out of the box. As a result, DevOps teams can consume Azure services in a variety of ways (e.g. Azure Portal or Terraform) as long as their configuration is aligned with the security standards of your enterprise.

In my previous blogpost, I have shared my experience with regard to securing Azure Key Vault. Within this blogpost, I want to focus on Azure Storage Account since it is another Azure service that is essential in a lot of solutions hosted on Microsoft Azure. For that reason, I will briefly discuss the service itself, its most relevant security components, and the Azure Policy Definitions you can use to enforce these security features.

Introduction to Azure Storage Account

An Azure Storage Account contains different Azure Storage objects. In essence, there are six different data entities that you can use:

  1. Blobs
  2. Files
  3. Shares
  4. Queues
  5. Tables
  6. Disks

Depending on the type of Storage Account, you can use any of these data objects to represent the data layer of your application. Be aware though, the use of a specific Storage Account type can restrict you from using a particular data entity. For instance, the ‘Premium file shares’ type only supports Azure Files whereas the ‘Premium block blobs’ type only allows you to use Azure Blobs. Hence, if your Azure Storage Account is multi-purpose, you can best select the ‘Standard general-purpose v2’ type. This Storage Account type supports both the standard option, as well as the Data Lake Storage Gen2 option, which focuses on big data analytics workloads. To use the latter option, you need to select the ‘Enable hierarchical namespace’ box during deployment as is visualized in Figure 1.

Figure 1: Setting the ‘Enable hierarchical namespace’ option to ‘Enabled’

You can also perform a Data Lake Gen2 upgrade post deployment, but that will result in your Azure Storage Account being unavailable for a short amount of time. With the introduction completed, it is time to check out the security features of this Azure service.

Security Features of Azure Storage Account

As mentioned earlier, Azure Storage Account can act as the data layer of your application. For that reason, it is important to protect it properly by taking into account the Azure security baseline for Azure Storage. The following sections will discuss the most important security features of Azure Storage Account and how you can monitor or enforce these using Azure Policy.

Be aware, the security features, and my recommendations on their usage, does not take your security standards and risk appetite into account. Therefore, your implementation might be very different from mine but still suffice the security needs of your company.

Network Security

Azure Storage Account is a multi-tenant Platform as a Service (PaaS) service that lives in Azure Public. In other words, this Azure service is not integrated with a Virtual Network, and traffic flows take place over the public internet. However, whether traffic flows are allowed or not completely depends on the networking option you select. For Azure Storage Account, there are two options:

  1. All networks
  2. Selected networks

If you select option 1, all traffic flows to your Azure Storage Account are allowed from a networking standpoint. In order to use this option, select the ‘Networking’ tab and click on ‘All networks’ as is visualized in Figure 2.

Figure 2: Setting the ‘Allow access from’ option to ‘All networks’

In some environments, this is not recommended since attackers would only need one of the Access Keys or Shared Access Signatures (SAS) to conduct read, write or delete operations from anywhere. Hence, if you rely on a (traditional) perimeter-based networking defense model, you should select option 2. This option creates a PaaS firewall in front of the Azure service that allows you to whitelist certain traffic based on either an IP address or Virtual Network. You can select option 2 by clicking on the ‘Networking’ tab and selecting ‘Selected networks’ as is displayed in Figure 3. Instead, you can also focus on the use of Identity Management controls. The ‘Identity Management’ Section provides more information on how you can accomplish this by for instance reducing the usage of the Access Keys and enforcing Azure Active Directory (AAD) authorization.

Figure 3: Setting the ‘Allow access from’ option to ‘Selected networks’

When IP-based filtering is used, you can define the IP addresses or IP address ranges from which traffic to the Azure Storage Account is permitted. If you want to allow traffic from a specific Subnet, within a Virtual Network, you need to create a Service Endpoint. On the Azure Storage Account itself, you subsequently need to whitelist this traffic by allowing requests from a specific Virtual Network. Instead of using the Public or Service Endpoint, you can also use a Private Endpoint. This option allows clients on a Virtual Network, to securely access data over a Private Link. In other words, network traffic traverses over the Virtual Network and a Private Link on the Microsoft backbone network, eliminating exposure from the public internet. Be aware, this option is only feasible for traffic that originates from Azure Private or On-premises. When traffic originates from for instance Azure Public, the Private Endpoint of the Azure Storage Account cannot be used since the Domain Name System (DNS) records cannot be resolved properly.

On top of these generic networking options, Azure Storage Account also enables you to define so-called Exceptions, which bypass the PaaS Firewall. First, you can grant access to trusted Microsoft services, by selecting the ‘Allow Azure services on the trusted services list to access this storage account’ setting. Since these Azure services use strong authentication (e.g. System-assigned Managed Identity) to securely connect to your Azure Storage Account, the residual risk of enabling this setting is minimal. On the other hand, this setting provides great benefits as you do not have to whitelist trusted Microsoft services that have no default IP addresses or IP address ranges. Second, the ‘Allow read access to storage logging from any network’ and ‘Allow read access to storage metrics from any network’ settings allow read access to the logs and metrics of an Azure Storage Account from any network. Since information on your storage analytics can be used for malicious purposes like Distributed Denial of Service (DDoS) attacks, I recommend not to enable these settings unless you really need to. In Figure 4, the above-mentioned options, and their associated traffic flows, are visualized.

Figure 4: Selecting a networking option for Azure Storage Account

Finally, you can configure the ‘Routing preference’ setting to determine how traffic should travel from its source (e.g. App Service) to an Azure endpoint. Since this setting is not related to security, but to network performance and costs, I will not discuss it in more detail. For more information on this topic, check out Network routing preference for Azure Storage.

Identity Management

As almost every Azure service, Azure Storage Account has a control plane and a data plane. The control plane enables you to for instance configure the diagnostic settings or delete a storage container. On the other hand, the data plane comprises the containers, file shares, queues and tables used to store actual data in.

Access to the control plane of Azure Storage Account is managed by Role-based Access Control (RBAC). In this way, you can use a custom or built-in Role Definition to create a Role Assignment for any AAD object (e.g. User). As is visualized in Figure 5, you can create Role Definitions and Role Assignments by clicking on the ‘Access control (IAM)’ tab and subsequently hitting the ‘Add’ button.

Figure 5: Creating a Role Definition and Assignment for control plane access

There are three options to grant access to the data plane of an Azure Storage Account:

  1. AAD authorization
  2. Access Key authorization
  3. SAS authorization

From a security standpoint, it is recommended to use AAD authorization so that requests to Blobs, Queues, and Tables are sent to AAD by default. You can default to AAD authorization by clicking on the ‘Configuration’ tab and then configuring the ‘Default to Azure Active Directory authorization in the Azure portal’ setting to ‘Enabled’ as is visualized in Figure 6.

Figure 6: Setting the ‘Default to Azure Active Directory authorization in the Azure portal’ option to ‘Enabled’

You can even take it one step further and deny the usage of Access Key and SAS authorization completely. In this way, only identities (e.g. Service Principal) that are included in the AAD of your organization can access the data in an Azure Storage Account. As is visualized in Figure 7, you can enforce this behavior by selecting the ‘Configuration’ tab and subsequently setting the ‘Allow storage account key access’ option to ‘Disabled’.

Figure 7: Setting the ‘Allow storage account key access’ option to ‘Disabled’

Unfortunately, AAD authorization is not an option when using applications that do not have an identity in AAD. Applications that are not developed in-house sometimes suffer from this drawback. Therefore, either Access Key or SAS authorization needs to be used. Authorization via Access Keys is the riskiest approach since it provides the user of the Access Key, read, write, and delete permissions on the data plane of the Azure Storage Account. You can read and rotate the Access Keys of the Azure Storage Account when clicking on the ‘Access keys’ tab as is displayed in Figure 8.

Figure 8: Reading or rotating the Access Keys of the Azure Storage Account

Instead, you can also use a SAS token. This form of authentication has two main benefits over the use of an Access Key since it provides more granular control in terms of applicable services and permissions, and it is time-based. As a consequence, you can for instance provide read permissions to a specific blob container for only 24 hours. In short, the impact of a comprised SAS token can be way lower in comparison to an Access Token that has been obtained by a malicious user. Be aware, this statement is only valid if a customer is using the granularity and time-based features of this authorization method correctly. In order to create a new SAS token, click on the ‘Shared access signature’ tab, fill out the details and hit ‘Generate SAS and connection string’. In Figure 9, these steps are visualized.

Figure 9: Creating a SAS token for the Azure Storage Account

Despite stating that there are only three authorization options, there actually is a fourth one, only applicable to Azure Blobs. Anonymous public read access enables clients to read blob data without authorization. In other words, anyone can read the data that is hosted in your container from an identity perspective. As you can imagine, this option only applies to very specific use cases. So, to disable this authorization option, click on the ‘Configuration’ tab, and set the ‘Allow Blob public access’ option to ‘Disabled’, as is displayed in Figure 10.

Figure 10: Setting the ‘Allow Blob public access’ option to ‘Disabled’

Out of the four different authorization options that have been discussed, I would recommend the use AAD authorization since it decreases the chance of data leakage substantially. Unfortunately, not all applications support this form of authorization, forcing you to adopt one of the other options. In that case, I would use SAS authorization due to its granularity and time-based features, enabling you to decrease the likelihood of data leakage in comparison to for instance Access Key authorization.

Data Protection

In terms of data protection, there are two main topics at hand. First of all, you need to protect data in transit so that attackers cannot perform actions like traffic capture. To accomplish this, encryption needs to be enforced so that attackers cannot read or modify data as it moves between your Azure Storage Account and the client application. For this Azure service, you can enable secure transfer so that your Azure Storage Account only accepts requests from secure, HTTPS connections. The use of this protocol ensures authentication between the client and the Azure service and thus protects data in transit from network layer attacks such as man-in-the-middle, eavesdropping, and session-hijacking. As is visualized in Figure 11, you need to click on the ‘Configuration’ tab and after that, set the ‘Secure transfer required’ option to ‘Enabled’.

Figure 11: Setting the ‘Secure transfer required’ option to ‘Enabled’

In essence, Transport Layer Security (TLS) acts as a sublayer on top of the HTTP protocol, turning it into the HTTPS protocol. As a result, all data in transit will be encrypted using TLS certificates. Currently, this Azure service supports three versions of TLS: 1.0, 1.1 and 1.2. To enforce the strictest security measures in terms of data protection, it is advised to use TLS version 1.2. In order to enforce this TLS version on your Storage Account, hit the ‘Configuration’ tab and set the ‘Minimum TLS version’ option to ‘Version 1.2’. In Figure 11, the above-mentioned actions are visualized. Be aware, client applications should also use this TLS version as otherwise, requests to your Azure Storage Account are dropped. In order to detect the TLS version that is being used by your application, you can use the Azure Storage logs in Azure Monitor.

Since Azure Storage Account hosts different types of data (e.g. Azure Blobs), this Azure service needs to protect data at rest as well. By default, Server-side Encryption (SSE) is enabled so that data is encrypted at the moment it is written to a storage entity and decrypted when you access it. SSE cannot be disabled, implying that data at rest is always protected using Microsoft-managed keys. If customers require a higher level of assurance with regard to data protection, the use of infrastructure encryption is recommended. This option enables 256-bit AES encryption at the Azure Storage infrastructure level. Hence, data in an Azure Storage Account is encrypted twice, once at the service level and once at the infrastructure level, with two different encryption algorithms and two different keys. As such, it protects against a scenario where one of the encryption algorithms or keys may be compromised. Be aware, infrastructure encryption needs to be enabled at the creation of your Azure Storage Account and is only available to the ‘Standard general-purpose v2’ type. After deployment, double encryption cannot be disabled or enabled anymore. In order to enable this encryption option, click on the ‘Encryption’ tab and subsequently hit the ‘Enable infrastructure encryption’ setting. In Figure 12, these steps are displayed as well.

Figure 12: Setting the ‘Enable infrastructure encryption’ option to ‘Enabled’

Infrastructure encryption relies on Microsoft-managed keys. However, SSE supports the use of both Microsoft-managed and Customer-managed keys. In this way, you can manage the key that is used to encrypt your data at rest via for example Azure Key Vault. One important aspect of Customer-managed keys is that support for Queue and Table storage is not configured by default. Hence, during the deployment of Azure Storage Account, you need to set the ‘Enable support for customer-managed keys’ option to ‘All service types (blobs, files, tables and queues)’ as is visualized in Figure 13.

Figure 13: Setting the ‘Enable support for customer-managed keys’ option to ‘All service types (blobs, files, tables and queues)’

Note, the above-mentioned setting needs to be enabled during the deployment of your Azure Storage Account and cannot be changed afterwards. On top of that, this setting only focuses on enabling support for Customer-managed keys, not their actual usage. To actually encrypt data at rest using a Customer-managed key, you need to configure the ‘Encryption type’ setting to ‘Customer-managed keys (CMK)’ and subsequently fill out the details on the Azure Key Vault you would like to use. In Figure 13, the above-mentioned steps are visualized.

Monitoring and Threat Detection

In terms of monitoring, you can take different actions to secure your Azure Storage Account. The activity logs for instance contain information on the creation, modification or deletion of this Azure service. These logs are aggregated on a Subscription level and can be streamed to four different solutions: Log Analytics Workspace, Storage Account, Event Hub and Partner Solution. If you want to enable the activity logs on a Subscription, click on the ‘Activity log’ tab and after that on the ‘Export Activity Logs’ button, as is visualized in Figure 14.

Figure 14: Enabling the diagnostic settings for the activity logs

Next to that, Azure Storage Account also generates logs and metrics on the behavior of the Azure service. These logs and metrics can be used to track the behavior of your Azure Storage Account since information on for example transactions or write operations can be collected and subsequently investigated. One of the main differences compared with other Azure services is that the logs and metrics can be collected for the parent Azure service or one of the child resources (e.g. Azure Blobs). Just as with the activity logs, the diagnostic settings offers you the possibility to stream these logs and metrics to a Log Analytics Workspace, Storage Account, Event Hub and Partner Solution. Be aware, enabling the activity logs and diagnostic settings is a step in the right direction, but in order to truly improve the security posture of this Azure service you should define and implement monitoring use cases using for instance Azure Monitor. As Figure 15 visualizes, you need to click on the ‘Diagnostic settings’ tab and then hit the ‘Add diagnostic setting’ button to configure the Diagnostic setting for Azure Storage Account.

Figure 15: Enabling the diagnostic settings for the resource-specific logs and metrics

Unfortunately, not every company is able to develop the above-mentioned monitoring capabilities in-house. Luckily, they can rely on Microsoft Defender for Cloud. This tool continuously monitors your Azure Storage Account to identify security vulnerabilities and subsequently defines actions to mitigate these in order to reduce the attack surface and increase your security posture. Microsoft Defender for Cloud is enabled on the Subscription level. After enabling it, you can check the security posture of your Azure Storage Account when selecting the ‘Security’ tab and checking the ‘Recommendations’ list. In Figure 16, these steps are displayed.

Figure 16: Checking the security posture of your Azure Storage Account

Backup and Recovery

Data in your Azure Storage Account is automatically replicated to ensure high availability and durability. This is not necessarily a security feature but will help you to protect your data from unplanned events such as transient hardware failures or outages. In terms of Azure Storage redundancy, there are four main options:

  1. Locally redundant storage (LRS)
  2. Zone-redundant storage (ZRS)
  3. Geo-redundant storage (GRS)
  4. Geo-zone-redundant storage (GZRS)

The main difference between option 1 and 2, and option 3 and 4 is that the latter options replicate your data to a secondary paired Azure region, thereby protecting your Azure Storage account in the case of a complete regional outage. The secondary Azure region is essentially paired to the primary region. More information on how Azure regions are paired can be found here. One of the main benefits of Azure Storage redundancy is that you can switch between the four options, described above. As a result, you can start with LRS, and gradually move up as the importance of your application, and thus its data layer, increases. As visualized in Figure 17, you can set your Azure Storage redundancy by clicking on the ‘Configuration’ tab and subsequently selecting one of the options from the ‘Replication’ drop down.

Figure 17: Setting the ‘Replication’ option to ‘Read-access geo-redundant storage (RA-GRS)’

Afterwards, you can check the Azure Storage redundancy option, and the impact it will have on your Azure Storage Account, by hitting the ‘Geo-replication’ tab. On this page, you can even conduct a failover if your Azure service is impacted by an unplanned event. In order to do so, click on the ‘Prepare for failover’ button as displayed in Figure 18.

Figure 18: Conducting a failover of your Azure Storage Account

Azure Policy

The previous section discussed the main security features of Azure Storage Account that can be used to increase the security posture of this Azure service. By using Policy Definitions, Policy Sets and Policy Assignments, most of these features can be either monitored or enforced. Below, I have defined a couple of Policy Definitions, whether these are custom or built-in, and the security feature to which they are linked. In terms of the built-in Policy Definitions, I have only included the ones I deemed relevant. You can find the complete list at ‘Azure Policy built-in definitions for Azure Storage’.

  1. Storage Account - Firewall Settings AUDIT [Custom] | Network Security
  2. Storage Account - Firewall Settings DENY [Custom] | Network Security
  3. Storage Accounts should use a virtual network service endpoint [Built-in] | Network Security
  4. Storage accounts should use private link [Built-in] | Network Security
  5. Configure Storage account to use a private link connection [Built-in] | Network Security
  6. Storage Account - Trusted Azure Services AUDIT [Custom] | Network Security
  7. Storage Account - Trusted Azure Services DENY [Custom] | Network Security
  8. Storage Account - Read Access Logs and Metrics AUDIT [Custom] | Network Security
  9. Storage Account - Read Access Logs and Metrics DENY [Custom] | Network Security
  10. Storage Account - Access Key Setting AUDIT [Custom] | Identity Management
  11. Storage Account - Access Key Setting DENY [Custom] | Identity Management
  12. Storage account public access should be disallowed [Built-in] | Identity Management
  13. Secure transfer to storage accounts should be enabled [Built-in] | Data Protection
  14. Storage Account - TLS Setting AUDIT [Custom] | Data Protection
  15. Storage Account - TLS Setting DENY [Custom] | Data Protection
  16. Storage account encryption scopes should use double encryption for data at rest [Built-in] | Data Protection
  17. Storage Account - Customer Managed Keys Queue and Table Storage AUDIT [Custom] | Data Protection
  18. Storage Account - Customer Managed Keys Queue and Table Storage DENY [Custom] | Data Protection
  19. Storage Account - Customer Managed Keys Blob and File Storage AUDIT [Custom] | Data Protection
  20. Storage Account - Customer Managed Keys Blob and File Storage DENY [Custom] | Data Protection
  21. Storage accounts should prevent cross tenant object replication [Built-in] | Data Protection
  22. Storage Account - Diagnostic Settings AINE [Custom] | Monitoring and Threat Detection
  23. Storage Account - Diagnostic Settings DINE [Custom] | Monitoring and Threat Detection
  24. Deploy Advanced Threat Protection on storage accounts [Built-in] | Monitoring and Threat Detection
  25. Geo-redundant storage should be enabled for Storage Accounts [Built-in] | Backup and Recovery

I hope that you enjoyed this blog post on ‘How to secure Azure Storage Account?’. If you have any questions or comments, feel free to reach out!

--

--

Bas van Bennekom

I am a freelance Azure consultant that likes to share knowledge on technical topics through blogs and code examples