This check flags Azure Service Bus namespaces that accept traffic from any public IP. Open messaging endpoints expose your queues and topics to the internet, widening the blast radius if a connection string or SAS token leaks. Disable public network access and route traffic through private endpoints or scoped IP firewall rules.
Azure Service Bus is the backbone of a lot of asynchronous architectures: order processing pipelines, event fan-out, decoupling between microservices, and integration with on-prem systems. Because it sits in the middle of so much traffic, a misconfigured namespace can quietly become one of the most sensitive doors in your environment. The servicebus_publicaccess check looks at whether a namespace allows connections from the public internet, which is the default when you create one without explicitly locking it down.
What this check detects
The check inspects each Azure Service Bus namespace and evaluates its publicNetworkAccess property along with its network rule set. A namespace fails the check when public network access is enabled, meaning the namespace endpoint is reachable from any IP address on the internet rather than being restricted to a private network or an explicit allow list.
Concretely, a namespace is flagged when either of these is true:
publicNetworkAccessis set toEnabled- The network rule set default action is
Allowwith no IP restrictions or private endpoint enforcement
Note: Standard and Premium tiers behave differently here. Network rule sets, IP firewall rules, and private endpoints are a Premium tier feature. On the Standard tier you can still toggle public network access, but you cannot apply granular IP rules or attach private endpoints. If you need strict network isolation, you generally need Premium.
Why it matters
A public Service Bus endpoint is not exploitable on its own. Authentication still applies, whether through a SAS token or Microsoft Entra ID. The problem is what happens when that authentication layer is the only thing standing between an attacker and your messaging plane.
SAS connection strings have a habit of ending up in the wrong places: committed to a public repo, pasted into a support ticket, hardcoded in a mobile app, or logged in plaintext by a misbehaving service. When the namespace is reachable from anywhere, a leaked token is immediately usable from anywhere. There is no network boundary to slow the attacker down or give you time to rotate.
The damage from a compromised messaging plane is broad:
- Message interception. An attacker with read access can drain queues and read sensitive payloads, which often include PII, payment data, or internal events never meant to leave your network.
- Message injection. Write access lets an attacker inject crafted messages that downstream consumers trust implicitly. If your order processor acts on whatever lands in its queue, that is a direct path to fraud or data corruption.
- Denial of service and cost. Flooding a namespace with messages can stall legitimate consumers and run up your bill.
- Lateral movement. Service Bus often connects systems across trust boundaries, so a foothold in the messaging layer can become a pivot point into both cloud and on-prem environments.
Warning: SAS tokens with a long or non-expiring TTL make this much worse. A leaked token plus a public endpoint plus no expiry is a standing invitation. Treat tokens and network exposure as two layers of the same problem.
How to fix it
The goal is to stop accepting traffic from the open internet. There are two main paths, and they are not mutually exclusive: disable public access entirely and use private endpoints, or keep public access but restrict it to a tight IP allow list.
Option 1: Disable public network access (recommended)
This is the cleanest option for namespaces consumed only by resources inside your VNet.
Danger: Disabling public access will immediately cut off any client connecting over the public internet, including CI/CD agents, on-prem systems, or developer machines without VNet connectivity. Confirm every consumer can reach the namespace privately before you run this in production, or you will cause an outage.
az servicebus namespace update \
--resource-group my-rg \
--name my-namespace \
--public-network-access Disabled
Then create a private endpoint so resources inside your VNet can still reach the namespace:
az network private-endpoint create \
--resource-group my-rg \
--name sb-private-endpoint \
--vnet-name my-vnet \
--subnet my-subnet \
--private-connection-resource-id \
$(az servicebus namespace show -g my-rg -n my-namespace --query id -o tsv) \
--group-id namespace \
--connection-name sb-connection
Finish by wiring up a private DNS zone (privatelink.servicebus.windows.net) so the namespace FQDN resolves to the private endpoint IP from inside the VNet. Without it, clients will still try to resolve the public address.
Option 2: Restrict public access with IP firewall rules
If some clients genuinely need public connectivity (a partner system, a fixed egress IP), keep public access on but default-deny everything and allow only what you trust. This requires the Premium tier.
# Set the default action to Deny
az servicebus namespace network-rule-set update \
--resource-group my-rg \
--namespace-name my-namespace \
--default-action Deny
# Allow a specific IP or CIDR range
az servicebus namespace network-rule-set ip-rule add \
--resource-group my-rg \
--namespace-name my-namespace \
--ip-address 203.0.113.10 \
--action Allow
Terraform example
If you manage infrastructure as code, bake the restriction into the resource definition so it never drifts back open:
resource "azurerm_servicebus_namespace" "main" {
name = "my-namespace"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
sku = "Premium"
capacity = 1
public_network_access_enabled = false
network_rule_set {
default_action = "Deny"
public_network_access_enabled = false
trusted_services_allowed = true
}
}
Tip: Set trusted_services_allowed = true so first-party Azure services like Event Grid and Azure Monitor can still reach the namespace even with public access locked down. Otherwise you may break diagnostic settings or event subscriptions without an obvious cause.
How to prevent it from happening again
Fixing one namespace is easy. Stopping the next one from shipping wide open is the real win. Put a gate in front of provisioning so a public namespace cannot reach production unnoticed.
Azure Policy
Azure Policy can audit or outright deny namespaces with public access enabled. Use the built-in policy or a custom definition like this:
{
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.ServiceBus/namespaces"
},
{
"field": "Microsoft.ServiceBus/namespaces/publicNetworkAccess",
"notEquals": "Disabled"
}
]
},
"then": {
"effect": "deny"
}
}
Assign it at the subscription or management group scope. Start with audit to measure your current state, then switch to deny once you have remediated existing namespaces.
Note: A deny effect only blocks new or updated resources. It does not retroactively fix namespaces that already exist. Pair it with a remediation task or your IaC pipeline to clean up the back catalog.
CI/CD gates
Catch the misconfiguration before it deploys. If you use Terraform, run a policy-as-code check in the pipeline. A Checkov or OPA rule that fails the build when public_network_access_enabled is true stops the issue at code review rather than in production.
# Run Checkov against your Terraform plan
checkov -d ./infra --framework terraform \
--check CKV_AZURE_199
Continuous monitoring
Policy and pipeline checks handle the path you control. Lensix continuously scans live resources, so namespaces created through the portal, click-ops, or a forgotten script still surface in your findings. That closes the gap between what your IaC says and what is actually running.
Best practices
- Default to private. Treat public network access as something you opt into deliberately, not the starting point. Most internal messaging never needs to leave the VNet.
- Prefer Microsoft Entra ID over SAS. Use managed identities and RBAC instead of shared access keys wherever possible. It eliminates the long-lived secret that makes public exposure so dangerous.
- Scope tokens tightly. When you must use SAS, give each token the minimum rights it needs (Send, Listen, or Manage) and set a real expiry. Avoid namespace-level keys for application clients.
- Use private endpoints with private DNS. A private endpoint without the matching DNS zone leaves clients resolving the public name, which defeats the purpose.
- Allow trusted Azure services explicitly. Lock down the namespace, then re-enable the first-party integrations you actually rely on rather than leaving the door open for all.
- Audit regularly. Network configuration drifts. Periodically confirm that namespaces still match your intended posture, and alert when one flips back to public.
Locking down network access does not replace good identity hygiene, and good identity hygiene does not replace network controls. Service Bus sits at a junction of sensitive traffic, so it deserves both layers. Disable public access where you can, restrict it tightly where you cannot, and put a policy gate in place so the next namespace starts off closed.

