How to fix the Azure and Bicep setup when Defender for Storage is enabled, but on-upload malware scanning still refuses to turn on.#
Enabling Microsoft Defender for Storage with Bicep sounds straightforward. In practice, you can end up in a frustrating half-working state: the Defender resource is created, you are Owner on the subscription, and on-upload malware scanning still stays disabled.
One of those Azure moments: everything looks right, you are Owner on the subscription, the Bicep deployment says the Defender resource was created, and the portal still shows this gem:
| |
Even better, the storage account is already StorageV2, soft delete is enabled, and you are now deep enough into the rabbit hole that every new portal blade feels slightly personal.
We ran into exactly that while enabling Microsoft Defender for Storage with Bicep. The good news: it does work. The annoying news: there are a couple of hidden prerequisites and one very misleading failure mode.
If you found this post because you searched for one of these errors, you are in the right place:
Could not enable on-upload malware scanningPlan enablement partially succeeded. Could not enable on-upload malware scanning: Failed to update malware scanning.The attempt to configure storage notifications for the provided storage account failedFailed to retrieve credentials ... listAccountSas ... InvalidAuthenticationTokenat least one of the claims 'puid' or 'altsecid' or 'oid' should be present
TL;DR#
If you just want the shortest possible answer, this is what solved it for us:
- Register
Microsoft.EventGridon the subscription - Set
dataScannerResourceIdexplicitly in the Bicep resource - Re-run the same deployment once after provider registration
If step 2 is missing, the Defender resource may be created while malwareScanning.onUpload still stays disabled. If step 1 was done only moments ago, the first retry can still fail with Storage Notification or InvalidAuthenticationToken before the next run succeeds.
🧩 The Setup#
The goal was straightforward:
- Enable Defender for Storage on a
StorageV2account via Bicep - Turn on on-upload malware scanning
- Write scan results to blob index tags / Log Analytics
- Use built-in remediation with
BlobSoftDelete
In our case the Bicep module looked roughly like this:
| |
That any(...) is not there because I enjoy chaos. It is there because the API accepted a property the published Bicep type definition did not properly expose in our case.
😵 The Misleading Part: Owner Was Not Enough#
At first glance, this smelled like a permissions problem. After all, the error included things like Unauthorized, InvalidAuthenticationToken, and listAccountSas.
Naturally, the first reaction is:
“But I am Owner on the subscription. What else do you want from me, Azure?”
Turns out: quite a bit.
Being Owner was not the actual missing piece in our case.
The real blocker was that Azure still needed infrastructure behind the scenes for storage notifications, and that depends on the Microsoft.EventGrid resource provider being registered in the subscription.
So yes, RBAC and resource provider registration are two different levers. Azure was perfectly happy to let us be Owner while still refusing to make progress because the required provider was not available. Classic.
🔌 The Hidden Dependency: Microsoft.EventGrid#
Even though our Bicep did not directly declare an Event Grid resource, Defender for Storage on-upload malware scanning still depended on it.
Why? Because Azure configures storage notifications behind the scenes for on-upload scanning.
This was the missing step:
| |
And if you want to verify it:
| |
If the provider is not registered, you can end up with errors like:
| |
That is the part I wish someone had highlighted in giant flashing letters somewhere in the docs.
🕵️ Another Gotcha: dataScannerResourceId#
There was one more surprise.
After working with support, it turned out that for our scenario the API only reliably persisted the malware scanning values when we explicitly set:
| |
Without that, Defender itself could be enabled, but the malwareScanning.onUpload block was not applied the way we expected.
So if your deployment says the resource was created, but the portal still shows something like this:
| |
then this property is worth checking.
⚠️ The Weird 401 After EventGrid Registration#
Here comes the part that made this feel extra fun.
After registering Microsoft.EventGrid, we expected the next deployment to just work.
It did not.
Instead, we got this:
| |
At that point the natural instinct is to start tearing apart your Bicep, your identities, your storage config, your life choices, and possibly your coffee machine.
In our case, that would have been the wrong move.
The actual fix was simply:
- Register
Microsoft.EventGrid - Re-run the same deployment
That second run worked.
So at least in our case, this looked very much like a race condition or delayed backend propagation immediately after provider activation.
🧪 Things We Checked That Were Not the Root Cause#
To save you a few hours of random portal clicking:
- The storage account was already
StorageV2 - Soft delete was enabled manually and it still did not fix the problem
- The subscription role was already
Owner
Soft delete is relevant for BlobSoftDelete remediation, but it was not the missing prerequisite that made on-upload malware scanning start working.
✅ What Finally Worked#
For us, the practical checklist was:
- Use
Microsoft.Security/defenderForStorageSettings@2025-09-01-preview - Set the
malwareScanningblock explicitly in Bicep - Set
dataScannerResourceIdexplicitly - Make sure the subscription has
Microsoft.EventGridregistered - If the first deployment after provider registration fails with
Storage Notification/InvalidAuthenticationToken, run the same deployment again
🔗 Related Azure Posts#
If you are currently wiring up more of your Azure platform around the same solution, these might also be useful:
- Configuring Scoped Settings from App Configurations or Secrets and injecting them into Providers
- Simplify Your Life: Logging to Application Insights with Serilog
📌 Final Takeaway#
If you are trying to enable Defender for Storage on-upload malware scanning with Bicep and it keeps failing, the short version is:
Owneron the subscription does not automatically mean all hidden platform prerequisites are in placeMicrosoft.EventGridmay be required even if your Bicep never mentions Event Grid directlydataScannerResourceIdcan be the difference between “resource created” and “settings actually applied”- A 401 right after Event Grid registration may just be a transient first-run failure, not proof that your entire setup is broken
In other words: if Azure tells you that malware scanning could not be enabled, it might not be your Bicep that is wrong. Sometimes Azure just wants one more provider registration, one more backend sync, and one more deployment run for emotional support.
Happy deploying, and may your onUpload.isEnabled finally stay true.
