Every “lift the file server to Azure” project stalls at the same place: somebody opens the share, gets prompted for credentials that do not match their domain account, and the migration is suddenly “blocked on storage.” The fix is almost never more storage – it is wiring identity correctly so that NTFS ACLs the business has maintained for fifteen years keep working, and that the wire protocol stays Kerberos rather than falling back to a storage account key everyone can extract. Azure gives you two managed SMB platforms for this: Azure Files (a feature of the storage account) and Azure NetApp Files (a bare-metal NetApp service fronted by an Azure resource provider). They overlap on the marketing slide and diverge sharply in operation. This is how to choose between them, stand up identity-based SMB without leaking a key, lock the data plane to private endpoints, and protect the data with snapshots and replication that survive a region loss.
1. Azure Files vs Azure NetApp Files: tiers, performance, and cost
Both speak SMB 3.x and NFS, both do snapshots, both integrate with AD. The decision usually comes down to latency floor, throughput ceiling, and how much operational surface you want to own.
| Dimension | Azure Files | Azure NetApp Files (ANF) |
|---|---|---|
| Resource model | Feature of Microsoft.Storage/storageAccounts |
Microsoft.NetApp/netAppAccounts -> capacity pool -> volume |
| SMB tiers | Standard (HDD, GPv2) and Premium (SSD, FileStorage account) |
Standard / Premium / Ultra service levels (set on the capacity pool) |
| Latency | Premium low-single-digit ms; Standard higher and burstier | Sub-millisecond typical on Premium/Ultra |
| Throughput scaling | Premium scales with provisioned size (or v2 provisioned IOPS/throughput) | Throughput follows pool service level and volume quota |
| Min footprint | A 100 GiB Premium share | 1 TiB capacity pool (auto QoS) or 2 TiB volume floor on manual pools |
| Protocols | SMB, NFSv4.1, REST | SMB, NFSv3, NFSv4.1, dual-protocol |
| Data protection | Share snapshots, soft delete, Backup vault (vaulted) | Volume snapshots, snapshot policies, backup, cross-region replication |
| Best fit | General-purpose shares, app config, FSLogix, Azure File Sync hub | Latency-sensitive workloads: SAP, HPC scratch, large EDA/render, databases on NFS |
Rule of thumb I use on reviews: if the workload tolerates a few milliseconds and you want one resource to manage, Azure Files Premium. If the workload’s SLO mentions microseconds, or it is SAP/HPC/EDA, ANF – and budget for the 1 TiB+ pool floor whether you use it or not.
A subtle cost trap: Azure Files Premium (the original v1 model) bills on provisioned size, not used size, and throughput is a function of that provisioned size. Over-provisioning for IOPS headroom is the single biggest line item I see on file-storage bills. The newer Premium SSD v2 model decouples capacity from IOPS and throughput so you provision each independently, which usually lowers spend on bursty shares.
2. Identity-based access: on-prem AD DS vs Entra Kerberos
Azure Files supports three SMB identity sources. Pick exactly one per storage account.
| Source | Where identities live | Best for |
|---|---|---|
| On-prem AD DS | Your existing Active Directory, synced to Entra ID via Entra Connect | Domain-joined servers and clients, hybrid file servers, lift-and-shift |
| Microsoft Entra Kerberos | Entra ID (cloud-only) | Entra-joined / hybrid-joined Windows endpoints, FSLogix profiles in AVD |
| Entra Domain Services | Managed domain (AAD DS) | When you want a managed DC and no on-prem AD |
The mechanics are the same in spirit: a computer object representing the storage account is created in the identity source, the account holds a Kerberos key for that object, and clients get a Kerberos ticket for cifs/<account>.file.core.windows.net. The user’s NTFS-level access is then evaluated against the file/folder ACLs.
For on-prem AD DS, the AzFilesHybrid PowerShell module does the domain join. Run this from a machine that is domain-joined and can reach a domain controller, signed in as someone who can create the AD object:
# Import the AzFilesHybrid module (download from the AzureFilesHybrid GitHub release)
Import-Module .\AzFilesHybrid.psd1
Connect-AzAccount -Subscription "<sub-id>"
# Creates an AD object (computer or service logon account) for the storage account
# and configures the account to use AD DS Kerberos for SMB.
Join-AzStorageAccount `
-ResourceGroupName "rg-files-prod" `
-StorageAccountName "stfilesprod01" `
-SamAccountName "stfilesprod01" `
-DomainAccountType "ComputerAccount" `
-OrganizationalUnitDistinguishedName "OU=AzureFiles,OU=Servers,DC=corp,DC=contoso,DC=com"
# Verify the storage account now advertises AD DS as its directory service
$acct = Get-AzStorageAccount -ResourceGroupName "rg-files-prod" -StorageAccountName "stfilesprod01"
$acct.AzureFilesIdentityBasedAuth.DirectoryServiceOptions # expect: AD
For Entra Kerberos (cloud identities, no on-prem AD object), you enable it on the account and grant admin consent to the auto-created app registration:
az storage account update \
--resource-group rg-files-prod \
--name stfilesprod01 \
--enable-files-aadkerb true
# Then in Entra ID -> App registrations, grant admin consent to the
# "[Storage Account] <name>.file.core.windows.net" app (openid/profile/User.Read).
Hard constraint worth internalizing: Entra Kerberos authenticates the user, but NTFS-level permissions are still enforced against AD DS SIDs. For pure cloud-only file servers without any on-prem AD, that means you configure share-level RBAC for access and rely on default file ACLs – you cannot set fine-grained per-user NTFS ACLs by cloud identity unless those identities are synced from AD DS. Plan FSLogix/AVD deployments accordingly.
3. NTFS permissions, share-level RBAC, and Kerberos flows
Access in Azure Files is a two-gate model, and confusing the two is the most common support ticket I triage.
- Share-level (RBAC) decides who can mount the share at all. You assign Azure roles scoped to the file share. The three built-ins:
Storage File Data SMB Share ReaderStorage File Data SMB Share ContributorStorage File Data SMB Share Elevated Contributor(can also modify NTFS ACLs)
- Directory/file-level (NTFS) decides what you can do once mounted. Standard Windows ACLs, set with
icaclsover the mounted share, enforced against AD SIDs.
Assign share-level access to an AD group that is synced to Entra ID:
# Scope the role to the specific file share, not the whole account
scope=$(az storage account show -g rg-files-prod -n stfilesprod01 --query id -o tsv)/fileServices/default/fileshares/projects
az role assignment create \
--assignee "<entra-group-object-id>" \
--role "Storage File Data SMB Share Contributor" \
--scope "$scope"
Mount the share on a domain-joined client. Do not pass a storage account key – that defeats identity-based auth and is exactly what we are avoiding. With AD DS configured, the client transparently gets a Kerberos ticket:
# No key, no /user, no password -- Kerberos SSO against the signed-in domain user
net use Z: \\stfilesprod01.file.core.windows.net\projects
# Confirm you actually got Kerberos (not NTLM) and a ticket for the storage account
klist | Select-String "cifs/stfilesprod01.file.core.windows.net"
Set the actual NTFS ACLs once, from an Elevated Contributor session, then let the directory tree inherit:
icacls Z:\engineering /grant "CORP\eng-team:(OI)(CI)M" # Modify, inherited to children
icacls Z:\engineering /remove "CORP\Everyone"
The Kerberos flow underneath: the client requests a service ticket (TGS) for the SPN cifs/stfilesprod01.file.core.windows.net from a DC, the storage account decrypts it with the Kerberos key minted during Join-AzStorageAccount, Azure maps the user SID, and then the NTFS ACL is evaluated. If clients fall back to NTLM, the SMB mount fails by design – Azure Files does not accept NTLM for AD identities. Three usual culprits: the SPN does not exist on the AD object, the client cannot reach a DC (so no TGS), or DNS resolves the account to a public IP and Kerberos is rejected.
4. Private endpoints, DNS, and eliminating public access
By default *.file.core.windows.net resolves to a public IP. For Kerberos to behave and for the data plane to stay off the internet, front the account with a Private Endpoint and shut public access.
# 1) Create the private endpoint targeting the 'file' sub-resource
az network private-endpoint create \
--resource-group rg-files-prod \
--name pe-stfilesprod01-file \
--vnet-name vnet-hub --subnet snet-privatelink \
--private-connection-resource-id "$(az storage account show -g rg-files-prod -n stfilesprod01 --query id -o tsv)" \
--group-id file \
--connection-name plsc-stfilesprod01-file
# 2) Wire it to the Private DNS zone so the FQDN resolves to the private IP
az network private-endpoint dns-zone-group create \
--resource-group rg-files-prod \
--endpoint-name pe-stfilesprod01-file \
--name pdnszg-file \
--private-dns-zone "privatelink.file.core.windows.net" \
--zone-name file
# 3) Disable public network access entirely
az storage account update -g rg-files-prod -n stfilesprod01 --public-network-access Disabled
The DNS detail that bites everyone: the storage account FQDN is stfilesprod01.file.core.windows.net, but the private DNS zone is privatelink.file.core.windows.net. Azure’s public DNS returns a CNAME from the former to the latter; your private zone resolves privatelink.file.core.windows.net to the PE’s private IP. On-prem clients must be able to resolve that private zone – via DNS forwarders pointing at an Azure DNS Private Resolver inbound endpoint, or conditional forwarders to a DNS VM in the hub. If on-prem still resolves the account to a public IP, mounts fail or quietly egress over the internet.
5. Snapshots, soft delete, and share-level data protection
Azure Files gives you three independent layers. Use all three for anything that matters.
Share snapshots are read-only, incremental, point-in-time copies surfaced to users through the Previous Versions tab on Windows:
az storage share snapshot \
--account-name stfilesprod01 \
--name projects \
--auth-mode login
Soft delete keeps deleted shares (and snapshots) recoverable for a retention window – your safety net against a fat-fingered az storage share delete:
az storage account file-service-properties update \
--resource-group rg-files-prod \
--account-name stfilesprod01 \
--enable-delete-retention true \
--delete-retention-days 14
Vaulted backup via a Backup vault adds scheduled snapshot management with offsite retention and, critically, an immutable copy that an attacker with storage-account rights cannot purge. Snapshots and soft delete live in the same account as the data; backup does not. Treat them as defense in depth, not substitutes – snapshots cover oops, backup covers ransomware.
6. Azure File Sync: cloud tiering and multi-site replication
Azure File Sync turns one or more Windows file servers into cached endpoints of an Azure file share. The hot working set stays on local NTFS; cold files become tiered pointers (reparse points) whose data lives only in Azure. This is the answer to “we have 40 TB on a branch file server but only touch 2 TB a month.”
# On each Windows Server file server, after installing the Azure File Sync agent:
Register-AzStorageSyncServer -ResourceGroupName "rg-filesync" -StorageSyncServiceName "sss-corp"
# Create a server endpoint with cloud tiering: keep ~20% free space locally,
# and tier anything not touched in 30 days.
New-AzStorageSyncServerEndpoint `
-ResourceGroupName "rg-filesync" `
-StorageSyncServiceName "sss-corp" `
-SyncGroupName "sg-projects" `
-ServerLocalPath "F:\Projects" `
-CloudTiering $true `
-VolumeFreeSpacePercent 20 `
-TierFilesOlderThanDays 30
Add multiple server endpoints to the same sync group and you get multi-site replication: a server endpoint in each office, all converging on the same cloud share. Two operational rules I enforce: never run unsupervised antivirus or backup against a tiered volume without recall-on-read exclusions (you will rehydrate the entire dataset and blow your egress budget), and always back up the cloud share, not the cached servers – the cloud share is the source of truth.
7. ANF volumes, capacity pools, snapshots, and cross-region replication
Azure NetApp Files has its own hierarchy: a NetApp account, then one or more capacity pools (which set the service level and therefore throughput), then volumes carved from the pool. The volume’s throughput on manual-QoS pools is quota_TiB x service_level_MiBps.
resource "azurerm_netapp_account" "this" {
name = "anf-prod"
resource_group_name = azurerm_resource_group.anf.name
location = "westeurope"
# Bind ANF to AD so SMB volumes can do Kerberos against your domain
active_directory {
username = var.ad_join_username
password = var.ad_join_password
smb_server_name = "ANFSMB"
dns_servers = ["10.10.0.4", "10.10.0.5"]
domain = "corp.contoso.com"
organizational_unit = "OU=AzureNetApp,DC=corp,DC=contoso,DC=com"
}
}
resource "azurerm_netapp_pool" "premium" {
name = "pool-premium-01"
account_name = azurerm_netapp_account.this.name
resource_group_name = azurerm_resource_group.anf.name
location = azurerm_netapp_account.this.location
service_level = "Premium"
size_in_tb = 4
}
resource "azurerm_netapp_volume" "sap" {
name = "vol-sap-data"
account_name = azurerm_netapp_account.this.name
pool_name = azurerm_netapp_pool.premium.name
resource_group_name = azurerm_resource_group.anf.name
location = azurerm_netapp_account.this.location
volume_path = "sap-data"
service_level = "Premium"
subnet_id = azurerm_subnet.anf_delegated.id # subnet MUST be delegated to Microsoft.NetApp/volumes
storage_quota_in_gb = 2048
protocols = ["CIFS"] # SMB; use ["NFSv4.1"] or both for dual-protocol
snapshot_directory_visible = true
}
The delegated subnet is mandatory and non-obvious: ANF volumes get injected into a subnet delegated to Microsoft.NetApp/volumes, and that subnet cannot host other resources. ANF snapshots are near-instant and storage-efficient (no copy on create). For DR, cross-region replication mirrors a volume to a paired region on a schedule:
# Create the destination as a data-protection volume that replicates from the source,
# then authorize the source to replicate to it.
az netapp volume replication approve \
--resource-group rg-anf-dr \
--account-name anf-dr \
--pool-name pool-premium-dr \
--name vol-sap-data-dr \
--remote-volume-resource-id "$SRC_VOL_ID"
az netapp volume replication status \
--resource-group rg-anf-dr --account-name anf-dr \
--pool-name pool-premium-dr --name vol-sap-data-dr \
--query "mirrorState" # expect: mirrored
Replication is one-directional until you break the peering to fail over, at which point the destination becomes writable. Rehearse the break-and-resync; do not discover the sequence during an incident.
8. Performance tuning, throughput provisioning, and monitoring
On Azure Files Premium v1, baseline IOPS and throughput scale linearly with provisioned size, plus a burst-credit pool. If you are throttled, the lever is provisioned GiB – or move to Premium SSD v2 and provision IOPS/throughput independently. On ANF, the levers are service level (Standard/Premium/Ultra) and volume quota; raising either raises throughput, and you can change pool service level without an outage. Two extra knobs on ANF for throughput-bound SMB and NFS workloads are SMB Multichannel and NFS nconnect, which fan a single mount across multiple TCP connections.
Watch the right metrics in Azure Monitor. For Azure Files, throttling shows up as 429 responses, not slowness:
// Azure Files: catch throttling on the file share (server-side success vs throttle)
StorageFileLogs
| where TimeGenerated > ago(1h)
| where StatusCode == 429 or StatusText has "ThrottlingError"
| summarize Throttled = count() by bin(TimeGenerated, 5m), OperationName
| order by TimeGenerated desc
For capacity and latency on the storage account, the platform metrics Transactions, SuccessE2ELatency, and FileCapacity (Files namespace) tell you whether to provision more. For ANF, VolumeConsumedSizePercentage, ReadLatency/WriteLatency, and ThroughputLimitReached are the signals that you are quota- or service-level-bound.
Enterprise scenario
A pharma client ran AVD for 9,000 users with FSLogix profile containers on a single Azure Files Premium share. Every weekday at 08:30 the login storm hammered the share; users saw 90-second profile loads and intermittent “profile failed to attach.” Azure Monitor showed a wall of 429s during the storm – the share was IOPS-throttled, not latency-bound. The naive fix was to provision the v1 Premium share up to absorb peak IOPS, but that meant paying for ~30 TiB of provisioned capacity to buy IOPS they did not need on a dataset under 6 TiB. The cost delta was roughly 5x.
They solved it two ways. First, they migrated profiles to Premium SSD v2, decoupling IOPS from capacity so they could provision peak IOPS against the actual ~6 TiB footprint. Second, they sharded profiles across multiple shares with FSLogix’s Cloud Cache / per-share assignment so the login storm fanned across independent IOPS budgets. Identity was the part that almost derailed it: the endpoints were hybrid-joined, so they used Entra Kerberos, and the hard-won lesson was that NTFS ACLs still resolve against AD DS SIDs – so the AD accounts had to be synced via Entra Connect and the FSLogix container ACLs set to the synced identities, not cloud-only ones.
# Premium SSD v2: provision IOPS and throughput independently of capacity
az storage account create \
--resource-group rg-avd-profiles \
--name stavdprofv2 \
--sku PremiumV2_LRS \
--kind FileStorage \
--location westeurope
az storage share-rm create \
--resource-group rg-avd-profiles \
--storage-account stavdprofv2 \
--name fslogix \
--quota 6144 \
--provisioned-iops 30000 \
--provisioned-bandwidth-mibps 2048
Result: 08:30 profile loads dropped from ~90 seconds to under 6, the 429s disappeared, and the monthly storage line fell because they stopped buying capacity to rent IOPS.
Verify
Run these after configuration. Each should produce the noted result, not just “no error.”
# Identity source is configured on the account (AD or AADKERB), not None
az storage account show -g rg-files-prod -n stfilesprod01 \
--query "azureFilesIdentityBasedAuthentication.directoryServiceOptions" -o tsv
# Public access is actually disabled (data plane is private-only)
az storage account show -g rg-files-prod -n stfilesprod01 \
--query "publicNetworkAccess" -o tsv # expect: Disabled
# Soft delete is on with a sane retention
az storage account file-service-properties show -g rg-files-prod \
--account-name stfilesprod01 \
--query "shareDeleteRetentionPolicy" -o json
# From a domain-joined client: the FQDN resolves to the PRIVATE endpoint IP
Resolve-DnsName stfilesprod01.file.core.windows.net | Select-Object Name, IPAddress
# The mount used Kerberos, not NTLM (a cifs ticket for the account must exist)
net use Z: \\stfilesprod01.file.core.windows.net\projects
klist | Select-String "cifs/stfilesprod01"
# ANF cross-region replication is actually mirroring
az netapp volume replication status \
--resource-group rg-anf-dr --account-name anf-dr \
--pool-name pool-premium-dr --name vol-sap-data-dr \
--query "mirrorState" -o tsv # expect: mirrored
If directoryServiceOptions returns None, clients are authenticating with the storage key and you have not achieved identity-based access. If klist shows no cifs/... ticket, the mount fell back to a key or NTLM – check the SPN and DC reachability before anything else.