This check flags Azure Storage accounts whose network ACLs do not allow trusted Microsoft services to bypass the firewall. Many Azure services, like backup, monitoring, and Event Grid, need this bypass to function, so disabling it can silently break integrations. Set --bypass AzureServices on the storage account network rule set.
When you lock down an Azure Storage account with network rules, you draw a line: only specific virtual networks and IP ranges can reach the data. That is good hygiene. But Azure itself runs a long list of platform services that need to read from or write to your storage account on your behalf. Backup jobs, diagnostic log exporters, Azure Monitor, Event Grid, and others all connect through Microsoft's own infrastructure, which does not come from your VNets or your office IP range.
The Microsoft services bypass setting controls whether those trusted platform services are exempt from your network ACL. This Lensix check, storage_nomicrosoftbypass, fires when that bypass is turned off, which usually means something you rely on is about to fail or already has.
What this check detects
Every Azure Storage account has a network rule set that includes a bypass property. This property accepts a comma-separated list of traffic categories that are allowed to skip the firewall rules. The valid values are:
AzureServices— trusted Microsoft services such as Azure Backup, Azure Site Recovery, and Azure MonitorLogging— write access to loggingMetrics— write access to metricsNone— no bypass, every connection is subject to the network rules
The check inspects the account's networkAcls.bypass value. If it is set to None, or if AzureServices is missing from the list while the default action is Deny, the check is marked as failing.
Note: The bypass only matters when your default action is Deny. If the account allows all networks (defaultAction = Allow), nothing is being blocked in the first place, so the bypass is moot. The real risk shows up once you start restricting access.
Why it matters
This is less of a classic "open door" finding and more of an operational and reliability risk that hides inside a security control. Here is what tends to go wrong in practice.
Backups silently stop working
Azure Backup and Azure Site Recovery connect to storage accounts to stage and store recovery data. If you flip the firewall to deny-by-default and forget the Microsoft services bypass, those jobs start failing with connectivity errors. The painful part is that nobody notices until a restore is needed, and by then the recovery points you assumed existed were never written.
Diagnostic logs and metrics go dark
Many teams route platform logs into a storage account for long-term retention. Azure Monitor uses the trusted services path to write those logs. Block it, and your audit trail quietly stops, which is both a compliance gap and an incident response problem. You only learn the gap exists during a postmortem when the logs you needed are not there.
Service integrations break
Event Grid, Azure Synapse, Azure Stream Analytics, and a number of other first-party services rely on the trusted services bypass to read or write blobs. Pipelines fail, triggers stop firing, and the error messages point at the network ACL rather than the integration itself, which makes diagnosis slow.
Warning: The trusted services bypass grants access to a category of Microsoft services, not to a specific resource. For some of those services Azure still requires a system-assigned managed identity with an explicit role assignment before access is actually granted. Treat the bypass as a prerequisite, not a complete authorization on its own.
There is a real security tradeoff to be aware of. Enabling AzureServices widens the set of identities that can reach the account through the platform path. For the vast majority of accounts that depend on Azure-native tooling, that tradeoff is worth it. For an account holding extremely sensitive data with no platform integrations at all, you may deliberately want it off. The point of the check is to make that a conscious decision rather than an accident.
How to fix it
The fix is to add AzureServices to the storage account's bypass list. Below are the common ways to do it.
Azure CLI
Update the network rule set on an existing account:
az storage account update \
--name mystorageaccount \
--resource-group my-rg \
--bypass AzureServices \
--default-action Deny
You can combine multiple bypass categories in a single call if you also want logging and metrics traffic exempted:
az storage account update \
--name mystorageaccount \
--resource-group my-rg \
--bypass AzureServices Logging Metrics \
--default-action Deny
Confirm the result:
az storage account show \
--name mystorageaccount \
--resource-group my-rg \
--query "networkRuleSet.bypass" \
--output tsv
Danger: Changing the network rule set on a production storage account takes effect immediately. If you run a command that also alters --default-action or removes existing VNet and IP rules, you can cut off live application traffic in the same call. Review the full rule set before applying and change one thing at a time.
Azure Portal
- Open the storage account in the Azure Portal.
- Go to Security + networking → Networking.
- On the Firewalls and virtual networks tab, make sure access is set to Enabled from selected virtual networks and IP addresses.
- Under Exceptions, check Allow Azure services on the trusted services list to access this storage account.
- Click Save.
Terraform
If you manage storage accounts with Terraform, set the bypass attribute inside the network_rules block:
resource "azurerm_storage_account" "example" {
name = "mystorageaccount"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
account_tier = "Standard"
account_replication_type = "LRS"
network_rules {
default_action = "Deny"
bypass = ["AzureServices"]
ip_rules = ["203.0.113.0/24"]
virtual_network_subnet_ids = [azurerm_subnet.example.id]
}
}
Note that in the azurerm provider, the default value of bypass is already ["AzureServices"], so the most common cause of this finding is someone explicitly overriding it to ["None"]. Check for that override first.
Bicep
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: 'mystorageaccount'
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
networkAcls: {
bypass: 'AzureServices'
defaultAction: 'Deny'
ipRules: []
virtualNetworkRules: []
}
}
}
Tip: After enabling the bypass, verify that the services you actually depend on are working rather than assuming they are. Trigger a test backup, confirm diagnostic logs are landing in the account, and check that any Event Grid or pipeline integrations still fire. The bypass is only useful if the downstream service is also configured correctly.
How to prevent it from happening again
Setting this once does not stop the next engineer from overriding it in a new module or a hotfix. Push the guardrail into your delivery pipeline so it cannot regress unnoticed.
Azure Policy
Use a custom policy that audits or denies storage accounts where the bypass excludes Azure services. The condition below targets accounts that deny by default but do not allow the trusted services bypass:
{
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
{
"field": "Microsoft.Storage/storageAccounts/networkAcls.defaultAction",
"equals": "Deny"
},
{
"field": "Microsoft.Storage/storageAccounts/networkAcls.bypass",
"notContains": "AzureServices"
}
]
},
"then": {
"effect": "audit"
}
}
Start with audit to measure your estate, then move to deny once you have remediated existing accounts and confirmed no legitimate account relies on having the bypass off.
IaC scanning in CI
Catch the misconfiguration before it ever reaches Azure by scanning Terraform and Bicep in your pull request pipeline. Tools like Checkov and tfsec flag this directly. A simple gate in a GitHub Actions workflow:
- name: Scan Terraform for storage misconfigurations
run: |
pip install checkov
checkov -d . --framework terraform \
--check CKV_AZURE_36 \
--compact
Tip: Pair the CI scan with continuous monitoring in Lensix. CI catches what is in your IaC, but it cannot see drift introduced by console changes, scripts, or other teams. The storage_nomicrosoftbypass check runs against your live environment, so a manual override gets flagged within your next scan even if it never touched a repository.
Best practices
- Treat deny-by-default and the bypass as a pair. The moment you set
defaultAction = Deny, decide deliberately what the bypass should be. Do not change one without considering the other. - Prefer private endpoints for application traffic. Private endpoints route access over the Microsoft backbone and remove the need to open public IP ranges. The trusted services bypass is for platform integrations, not a substitute for proper network isolation of your own workloads.
- Use resource-scoped access where it exists. For some services you can grant access to a specific resource instance through a resource instance rule rather than the whole
AzureServicescategory, which narrows the blast radius. Use it when the service supports it. - Document the exceptions. If you intentionally run an account with the bypass off, record why. That note saves the next on-call engineer hours of debugging when a backup quietly fails.
- Audit logging accounts especially carefully. Any storage account that holds diagnostic logs or audit trails should keep the bypass on, because losing that data undermines both compliance and incident response.
The trusted services bypass is one of those settings that looks like a loosening of security but is usually the opposite of a problem. Turning it off without understanding the dependencies trades a small reduction in attack surface for broken backups, missing logs, and failed integrations. Make the choice on purpose, enforce it with policy, and let continuous monitoring catch the drift.

