azure-sb-sas-send-writedata
Holding a SAS connection string with Send rights (obtained via CanReadSecret/listKeys) grants data-plane send to the scoped namespace/queue/topic - equivalent to the Entra Data Sender role but credential-based.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?connstr) ==
ConnectionString
?connstr is a Service Bus SAS connection string whose rights include Send or Manage
?entity is the namespace, queue, or topic scoped by the connection string
emit
| source type | Identity |
|---|---|
| target type | Messaging |
| source | ?principal |
| target | <queue or topic (Queue/Topic) or namespace (GenericMessaging) scoped by ?connstr> |
| state logic | ACTIVE when CanReadSecret(?principal, ?connstr) is ACTIVE (i.e., listKeys confirmed and disableLocalAuth=false) AND the connection string's rights include 'Send' or 'Manage'. CONDITIONAL if the CanReadSecret contributing edge is CONDITIONAL. A Manage right implicitly includes Send. BLOCKED if disableLocalAuth=true (no SAS active) or if the listKeys action is denied. Scoped to the entity the connection string was issued for: a queue-scoped Send SAS does NOT grant send to other queues or the namespace broadly. |
Narrative
{principal.name} obtained a SAS connection string for {target.name} with Send rights (via listKeys); this credential grants data-plane send to {target.name} without Entra RBAC, equivalent to the Data Sender role.
Raw rule rules/derived/azure/servicebus.yaml
id: azure-sb-sas-send-writedata
emits: CanWriteData
description: "Holding a SAS connection string with Send rights (obtained via CanReadSecret/listKeys) grants\
\ data-plane send to the scoped namespace/queue/topic \u2014 equivalent to the Entra Data Sender role\
\ but credential-based."
match:
- - principal: null
- CanReadSecret
- connstr: null
where:
- node_type(?connstr) == ConnectionString
- ?connstr is a Service Bus SAS connection string whose rights include Send or Manage
- ?entity is the namespace, queue, or topic scoped by the connection string
emit:
source_type: Identity
target_type: Messaging
source: ?principal
target: <queue or topic (Queue/Topic) or namespace (GenericMessaging) scoped by ?connstr>
permissions: []
conditions: []
state_logic: 'ACTIVE when CanReadSecret(?principal, ?connstr) is ACTIVE (i.e., listKeys confirmed and
disableLocalAuth=false) AND the connection string''s rights include ''Send'' or ''Manage''. CONDITIONAL
if the CanReadSecret contributing edge is CONDITIONAL. A Manage right implicitly includes Send. BLOCKED
if disableLocalAuth=true (no SAS active) or if the listKeys action is denied. Scoped to the entity
the connection string was issued for: a queue-scoped Send SAS does NOT grant send to other queues
or the namespace broadly.'
confidence: min(contributing_confidences)
derived_from:
- ?principal CanReadSecret ?connstr (azure-sb-namespace-listkeys or queue/topic equivalents)
- connection string rights array includes 'Send' or 'Manage'
- 'messaging-chains.yaml: messaging-publish-triggers-consumer (rule 1) consumes this CanWriteData'
false_positive_note: 'Only emit when the rights array contains ''Send'' or ''Manage''. A Listen-only
SAS key does NOT grant send. A Manage right includes Send implicitly (Manage = Send + Listen + Manage).
Honor the scope of the connection string: a queue-scoped Send SAS covers only that queue; a namespace-scoped
Send SAS covers all queues and topics. If disableLocalAuth=true, no SAS key is active and this edge
must not be emitted.'
narrative: '{principal.name} obtained a SAS connection string for {target.name} with Send rights (via
listKeys); this credential grants data-plane send to {target.name} without Entra RBAC, equivalent
to the Data Sender role.'