azure-netapp-volume-write-export-policy
volumes/write permission on ANF volume enables export policy mutation.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_class(?volume) == Storage and node_type(?volume) ==
FileStorage
?volume.provider_type == 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes'
?principal has EFFECTIVE Microsoft.NetApp/netAppAccounts/capacityPools/volumes/write at ?volume scope (Owner, Contributor, or custom role with volumes/write)
?volume.properties.provisioningState == 'Succeeded' # volume is online
emit
| source type | Identity |
|---|---|
| target type | FileStorage |
| source | ?principal |
| target | ?volume |
| permissions | Microsoft.NetApp/netAppAccounts/capacityPools/volumes/write |
| conditions | iam_permission |
| state logic | if a deny assignment covers volumes/write at effective scope: BLOCKED; elif ?volume.properties.provisioningState != 'Succeeded': CONDITIONAL(service_state); else ACTIVE. volumes/write is a control-plane action that allows export policy mutation (opening NFS export to arbitrary IP ranges or widening SMB ACL scope). This configuration change can enable data-plane access but does NOT itself constitute data-plane write access. Data-plane CanWriteData is gated on network_reachability to the delegated subnet. |
Narrative
{principal.name} has ARM write permission on ANF volume {volume.name} (Microsoft.NetApp/netAppAccounts/capacityPools/volumes/write) and can mutate the export policy to include their own IP or open it to 0.0.0.0/0. Actual data-plane write access requires network reachability to the delegated subnet.
Raw rule rules/derived/azure/netapp.yaml
id: azure-netapp-volume-write-export-policy
emits: CanModifyConfiguration
description: volumes/write permission on ANF volume enables export policy mutation.
match:
- - principal: null
- HasPermission
- volume: null
where:
- node_class(?volume) == Storage and node_type(?volume) == FileStorage
- ?volume.provider_type == 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes'
- ?principal has EFFECTIVE Microsoft.NetApp/netAppAccounts/capacityPools/volumes/write at ?volume scope
(Owner, Contributor, or custom role with volumes/write)
- '?volume.properties.provisioningState == ''Succeeded'' # volume is online'
emit:
source_type: Identity
target_type: FileStorage
source: ?principal
target: ?volume
permissions:
- Microsoft.NetApp/netAppAccounts/capacityPools/volumes/write
conditions:
- iam_permission
state_logic: 'if a deny assignment covers volumes/write at effective scope: BLOCKED; elif ?volume.properties.provisioningState
!= ''Succeeded'': CONDITIONAL(service_state); else ACTIVE. volumes/write is a control-plane action
that allows export policy mutation (opening NFS export to arbitrary IP ranges or widening SMB ACL
scope). This configuration change can enable data-plane access but does NOT itself constitute data-plane
write access. Data-plane CanWriteData is gated on network_reachability to the delegated subnet.'
confidence: '0.90'
derived_from:
- ?principal HasPermission ?volume
false_positive_note: volumes/write grants control-plane mutation of export policy rules (IP ranges,
access levels, Kerberos enforcement) and NFS re-export, or SMB ACL settings. This is a configuration
capability, NOT data-plane access. After mutating the export policy, the attacker still requires network
reachability to the delegated subnet to mount the volume and write data. CanModifyConfiguration correctly
models the control-plane mutation; downstream data-plane CanWriteData should be CONDITIONAL(network_reachability).
A deny assignment on volumes/write DOES block this capability.
narrative: '{principal.name} has ARM write permission on ANF volume {volume.name} (Microsoft.NetApp/netAppAccounts/capacityPools/volumes/write)
and can mutate the export policy to include their own IP or open it to 0.0.0.0/0. Actual data-plane
write access requires network reachability to the delegated subnet.'