Public Network Access to Azure Resources Is Too Easy to Configure
For some types of Microsoft Azure resources and subnets, it’s extremely easy to configure what is essentially public network access. We describe here some examples and how to reduce such risks.
Network access restriction is a crucial layer of cyber security – an important pillar in securing resources. This is true even when other security controls to protect resources are in use, such as username/password combination, connection strings or security tokens. Malicious actors find network restricted access difficult to get around. This was also the case when on-prem infrastructure was dominant. Security and network teams dedicated much time to configuring and auditing firewall rules to disallow network access to sensitive resources from outside the network.
As organizations grow larger, security teams are coming to realize that it is unrealistic to create a barrier that is impenetrable and beyond which full trust exists. Enter the rather overused – mea culpa – catchphrase of zero trust. In the case of network access, compartmentalization is the new order of the day, with teams architecting networks to separate network resources based on business functionality and sensitivity.
Still, many folks, operating under the concept that internal resources and cloud service provider services can be trusted more than external unknown resources, may be tempted to give access to a resource to a wide segment in their internal network. In Azure, this lax approach to internal network access, combined with a misunderstanding of some configuration attributes, can lead to even highly sensitive resources being made publicly available. Also, some Azure resources are provisioned with public network access by default; infrastructure admins must be mindful to configure such resources properly.
This post explores some of the above cases and offers guidance in how to reduce internal network access risk in Azure environments. In a few places, we have taken the liberty of adding bolding to quoted Azure documentation texts and red-framed boxes to Azure screenshots for emphasis.
Configurations to look out for
For some types of Azure resources, as well as subnets, configuring internal network access that is essentially public is extremely easy. We say “essentially” because some of these configurations allow access to any Azure resources created by any customer. While this is not technically public (that is - available to any machine anywhere), anyone can set up resources in Azure for which in those cases the access will be allowed. Even worse, the default configuration of several Azure resources is public network access.
Let’s review some of these Azure resource types and their relevant configurations.
SQL Servers
When configuring networking for an SQL Server in Azure under the networking blade, there’s an “Exceptions” section that has a single checkbox entitled:
Allow Azure services and resources to access this server
The checkbox may seem harmless as the server administrator may intuitively think that the configuration gives network access to the server for Azure services – that is, servers used internally by Azure services and administered by Microsoft and other Azure resources. The admin may also assume that the Azure resources referred to are only those which are in the subscription where the SQL Server resides.
I mean, why would that not be the case?
Operating under this understanding, the server administrator may find it perfectly reasonable to enable the feature and get things rolling rather than take the time to configure network rules granularly within the subscription’s resources.
Figure 1 - Azure SQL Servers networking blade - Explanation that appears when hovering over the information icon of the “Allow Azure services and resources to access this server” checkbox item
However, the reality is quite different.
Hovering over the information icon of the “Allow Azure services…” checkbox reveals what the configuration actually does.
This option configures the firewall to allow connections from IP addresses allocated to any Azure service or asset, including connections from the subscriptions of other customers.
By allowing this supposedly harmless configuration, you are in fact opening up the SQL Server to connections from any Azure resource, accessible by pretty much anyone.
The configuration essentially makes the server publicly accessible to network traffic – and eliminates the network security layer almost altogether.
Note that since it is considered an “Exception,” the feature overrides the other rules configured in the tab. In other words, the SQL Server will be open for network communication to anyone who can get any Azure resource. To actually access the server, a malicious actor needs only the server’s information and a connection string. Hopefully, neither are widely available but you don’t want that to be the only layer of security protecting the server.
You have of course more secure alternatives to this configuration. If you really want to have “public” access to the server (that is, allow the server to have a public IP address through which it can be accessed) you can configure the access to be authorized for only specific virtual networks within Azure and/or specific IP addresses.
Better yet, for a more secure approach, you can eliminate public access altogether and allow Azure resources to access the SQL Server using a private link by configuring Azure private access.
MySQL Servers
MySQL Servers have similar configuration options, with slight differences between flexible and single deployments.
Flexible Servers
When configuring a flexible server to allow public access, you have a similar configuration option as the one for SQL Servers. The flexible server checkbox is labeled:
Allow public access from any Azure service within Azure to this server
This statement, in referring to “any Azure service,” also does not intuitively convey that any resource, including those controlled by other Azure customers, would be allowed network access to the server.
Hovering over its information icon reveals what the configuration actually does:
This option configures the firewall to allow connections from IP addresses allocated to any Azure service or asset, including connections from the subscriptions of other customers.
Figure 2 - Azure MySQL Flexible server configuration network blade - Explanation that appears when hovering over the information icon of the “Allow public access from any Azure service within Azure to this server” checkbox item
Just like with SQL Servers, for a more secure approach, you can set network rules to allow public access for specific IPs only. You can also configure private access from specific virtual networks using VNet-Integration. Note, however, that you need to set this configuration when you create the server as it cannot be changed once created.
Figure 3 - You can only configure connectivity for MySQL servers before you create the server
Single Server
Similarly, when configuring a single MySQL server, under the “Connection security” blade, you can check a box called “Allow access to Azure services.”
Again, this could intuitively lead you to believe you’re actually allowing access only to services controlled by Microsoft. However, a simple hover over the information icon reveals this configuration (highlighting added for emphasis): “Configures the server's firewall to accept connections from all Azure resources, including resources not in your subscription.”
Single servers allow you to restrict public access to only specific IPs and/or Vnets or, better yet, to eliminate public access and use private endpoint connections.
Figure 4 - Hovering over the information icon of the “Allow access to Azure services” checkbox in the “Connection security” blade of MySQL single server.
When it comes to PostgreSQL, the configuration is quite similar to MySQL so we will not elaborate on it separately.
CosmosDB Databases
Regarding CosmosDB servers, this issue is particularly interesting.
First of all, CosmosDB servers may be configured to allow “All Networks” to have public network access to them -- the meaning is quite obvious.
Figure 5 - Configuring the CosmosDB server to have public network access for all networks
When you choose to allow public access for “Selected networks” only, you are shown a checkbox with an effect quite similar to those we’ve seen for other resources in this article. However there is some lack of clarity when you consider both the label on the checkbox – “Accept connections from within public Azure datacenters” – and the information that displays upon hovering over the information icon – “You may cautiously want to enable access from Azure IP range when you have interaction with another service on Azure which can't share IP range or is not hosted inside VNET.”
It is not clear from these descriptions that, when the option is checked, resources from other Azure subscriptions (of other customers!) can in fact have network access to the server.
Figure 6 - CosmosDB networking tab: Texts that appear when hovering over the information icon of the “Accept connections from within public Azure datacenters” option
Even Azure’s documentation on Configuring IP Firewall in Azure Cosmos DB provides a somewhat misleading description of the scope of this function:
If you access your Azure Cosmos DB account from services that don’t provide a static IP (for example, Azure Stream Analytics and Azure Functions), you can still use the IP firewall to limit access. You can enable access from other sources within the Azure by selecting the Accept connections from within Azure datacenters option.
The description could lead you to believe that all this configuration does is allow access to Azure services such as Azure Stream Analytics and Azure Functions. This is not the case. If you wish to see the greater access firsthand, set up a VM in an external subscription and watch as the configuration allows you to connect to a Cosmos DB server.
Cosmos DB also allows you to select specific virtual networks and/or IP addresses that will have public network access authorization or, preferably, to disable public access and use a private link.
Virtual machines
Network access for virtual machines is determined by applying Network Security Groups (NSGs). As the Azure documentation states:
A network security group contains security rules that allow or deny inbound network traffic to, or outbound network traffic from, several types of Azure resources. For each rule, you can specify source and destination, port, and protocol.
NSGs can be applied to the network interface of a VM and/or on the subnet where it resides. You can read the documentation to understand how traffic is evaluated in each of the different combinations of NSGs.
It’s important to understand that when you configure a new virtual machine and the subnet on which it’s designated to be configured is not associated with an NSG, a default NSG will be created on its network interface. Unless you edit it in the “Networking” tab, its configuration will look like this:
Figure 7 - “Basic” configuration for an NSG created for a VM instance
We see here that port 22 used for SSH would be open.
To make it clearer, we can look at the actual rule once the NSG is created:
Figure 8 - Port 22 is open for “Any” destination
Figure 8 clearly shows that the NSG created allows SSH access from anywhere – which is not very secure – so keep this in mind.
The issue is that, by default, as seen in Figure 9, subnets are created without an NSG association. This means that unless otherwise denied (e.g. by using a firewall), access to the subnet will not be restricted by the subnet and would have to be restricted by an NSG on the VM’s network interface.
Figure 9 - By default, subnets are created unassociated with an NSG
Proper management of network access to virtual machines is actually made up of two parts: first, and as an essential best practice, make sure that subnets have a proper NSG associated with them; also, as needed - on top of that - have each VM associated with an NSG to fine tune access to it.
Key vaults
As Azure Key Vault documentation states:
By default, when you create a new key vault, the Azure Key Vault firewall is disabled. All applications and Azure services can access the key vault and send requests to the key vault. Note, this configuration does not mean that any user will be able to perform operations on your key vault. The key vault still restricts to secrets, keys, and certificates stored in key vault by requiring Azure Active Directory authentication and access policy permissions.
This is very easily visible when you review the networking tab of a key vault:
Figure 10 - Default configuration of Azure Key Vault firewall
Of course, key vaults still require authorization (by RBAC or Key Vault access policy) for anyone who needs to access them - and these authentication and authorization methods are much easier to control than connection strings databases. However, not having network access restricted properly eliminates a significant layer of security for their protection, which is really a shame as these resources are usually very sensitive.
As we’ve seen with other resources, key vaults also allow for configuring private links as an alternative to public access (which can then be eliminated altogether) or for public access to specific network and/or IP addresses.
One difference for this resource in contrast to some of the other resources seen above: When it comes to exceptions to the firewall rules, for key vaults you can check the box labeled “Allow trusted Microsoft services to bypass this firewall.” This does not allow just any Azure resources from other customers’ environments to have network access to the Key Vault; it only allows access to trusted Azure services and, according to the documentation for Azure Key Vault network security, ”the trusted services list encompasses services where Microsoft controls all of the code that runs on the service.”
Figure 11 - Exception configuration to Key Vault firewall
This Azure documentation explanation means that this configuration is far less risky than some of the exceptions we saw before that essentially made resources public for network access.
Storage accounts
Another resource type that’s worthy of discussion is storage accounts.
Like Key Vault, storage accounts are configured to not have inbound connections restricted to them. As the Azure documentation on storage accounts states:
By default, storage accounts accept connections from clients on any network. You can limit access to selected networks or prevent traffic from all networks and permit access only through a private endpoint.
This can also be very clear when reviewing the “Networking” blade of a storage account.
Figure 12 - Unrestricted access to storage account
Needless to say, storage accounts may be very sensitive resources depending on the kind of information residing in them.
Another interesting point about storage accounts is that even though they support RBAC access control, they also provide (by default) access keys as an authentication method. Access keys are similar to a database’s connection string in that, once leaked, they can allow anyone who has them to access the storage account – and have full control of it. This is the case unless access to the storage account is otherwise limited, such as by limiting network access to it.
So it’s critical not to leave network access public to a storage account and configure public access for specific virtual networks and/or IPs; alternatively, remove public access altogether and use public links. This approach is especially important if you have access keys enabled and cannot easily disable them without being assured that such action won’t hurt business functions.
Similarly to key vaults, when it comes to exceptions on the firewall: Storage account firewall configuration allows you to set an exception for trusted Azure services that does not open the network access to the storage account to any Azure resources, just for those that belong to the trusted service(s) and are registered in your subscription. As specified in the Azure documentation for configuring storage account firewalls:
Resources of some services, when registered in your subscription, can access your storage account in the same subscription for select operations, such as writing logs or backup
Figure 13 - Exception setting for trusted Azure services in storage account network configuration
The other two checkboxes do allow public access to logging/metrics - so look out for them as well!
Takeaways
Managing network access effectively is a complex issue that can’t be fully covered in the scope of this document. However, following up on points covered here, you can perform a few actions that will reduce some of the risk that may arise from the misconfigurations we discussed.
Takeaway 1. Be judicious in using public network access. Be mindful of the configurations that make resources public and do not ever use them unless it’s an absolute must.
Takeaway 2. Reduce permissions to configuring network access. Understanding the potential damage from such misconfigurations, which often occur due to lack of attention to details, can be a great motivator for reducing the permissions granted to developers and other R&D teams that configure resources. They may easily make unintentional, novice mistakes when making such configurations, simply due to unclear UI.
Takeaway 3. Detect and remove current misconfigurations that allow public access. For current configurations of resources, if you don’t have a tool such as Tenable Cloud Security that automatically looks for misconfigurations like those presented here, you may want to use the Azure CLI to detect them. For example, the short bash script we created and present below looks for all SQL Servers (in all the subscriptions that the identity currently logged in has access to) where the checkbox “Allow Azure services and resources to access this server” is checked:
azure_prefix="https://management.azure.com"
firewall_suffix="/firewallRules?api-version=2021-02-01-preview"
servers_suffix="/providers/Microsoft.Sql/servers?api-version=2021-02-01-preview"
az rest --url "https://management.azure.com/subscriptions?api-version=2020-01-01" | jq ".value | .[] | .id" -r | while read subscription_id; do
echo "Subscription ID: "$subscription_id
az rest --url $azure_prefix$subscription_id$servers_suffix | jq ".value | .[] | .id" -r | while read id; do
url=$azure_prefix$id$firewall_suffix
array=$(az rest --url $url | jq "(.value | .[] | .name)")
if [[ " ${array[@]} " =~ "AllowAllWindowsAzureIps" ]]; then
echo $id
fi
done
done
The permissions needed for this to run are:
Microsoft.Sql/servers/read
Microsoft.Sql/servers/firewallRules/read
If you create a specific identity for performing this function, we recommend that you create a custom role with these permissions and assign it to that identity on the subscriptions you’re looking to scan.
This script is just an example and by no means a comprehensive review of network access. Rules allowing access from “Any” source may still cause the SQL Server to have public network access and of course there are many other types of resources to review.
It’s also important to be aware that any change to network configuration needs to be made responsibly to ensure that business functionality is not compromised. In the case of the SQL Server example, before unchecking the box allowing public access, you would make sure that connections to it aren’t made from locations which would otherwise be denied access to the server. You can do this check by reviewing your architecture and understanding from where connections are supposed to be made. However, a more automated (and probably less error prone) way of doing this would be to review logs of connections made to the server.
This review could be done on an SQL Server by first enabling auditing of it by the methods available. In our example, we used the Log Analytics option:
Figure 14 - Enabling Azure SQL logging with the Log Analytics option
You then allow logs to be collected for a reasonable period of time during which connections would be made. You can then use this syntax to query the logs to look for connections made:
AzureDiagnostics
| where Category == 'SQLSecurityAuditEvents'
and action_name_s == 'DATABASE AUTHENTICATION SUCCEEDED'
| distinct client_ip_s
The query result would present you with the connection creating events and show distinct results based on the IP from which the connection was made.
Figure 15 - Querying SQL Server logs to detect from where connections were made
Once you detect all the sources that require access to the SQL server, you can remove the full public access and replace it with public access to the virtual networks where these machines reside. This approach is superior to allowing access to specific IPs/CIDR ranges as it relies on the purpose of the virtual network and not on an IP address, which may change, or on an IP range, which may be over inclusive. You may of course also use private links, which allow you to eliminate public access altogether.
Takeaway 4. Use network storage groups to restrict access for subnets. Make sure that all subnets have restricted network access using an NSG. Be especially sure to limit SSH access to specific ranges/locations from which administrative access can be made.
Takeaway 5. Disable default public network access. Disable the default public network access for resources such as key vaults and storage accounts. Do this kind of reconfiguration responsibly by replacing the public access with more restricted access rules that still allow all communication sources that require access to these resources.
Final Thoughts
All these misconfigurations can be complicated to detect and even more complicated to remediate responsibly. It is clear that automation has an important role to play in staying on top of detecting, mitigating and preventing the all-too-easy misconfigurations involving public network access that expose Azure resources and subnets.
Related Articles
- Cloud
- Cloud