This check flags Azure Event Hub namespaces that accept traffic from any public IP. Exposing your messaging backbone to the open internet widens your attack surface for free. Disable public network access and route traffic through private endpoints or scoped firewall rules.
Event Hubs sits at the center of a lot of Azure architectures. It ingests telemetry, streams application logs, feeds analytics pipelines, and acts as the buffer between producers and downstream consumers. Because it handles so much data in motion, leaving its namespace open to the public internet is one of those quiet misconfigurations that rarely shows up in a demo but matters a great deal in production.
The eventhub_publicaccess check looks for namespaces where public network access is enabled, meaning the namespace endpoint is reachable from any network rather than restricted to your private infrastructure.
What this check detects
Every Event Hub namespace has a publicNetworkAccess property. When it is set to Enabled, the namespace's hostname (something like your-namespace.servicebus.windows.net) resolves to a public IP and accepts connections from anywhere on the internet, subject to authentication.
This check fires when:
- The namespace has
publicNetworkAccessset toEnabled - No network rule set restricts inbound traffic to specific virtual networks or IP ranges
Note: Public access being enabled does not mean the data is unauthenticated. Event Hubs still requires a valid SAS token or Azure AD identity to publish or consume. The risk is about reachability and attack surface, not an open door to your event streams.
Why it matters
Authentication is your last line of defense, not your only one. When a namespace is publicly reachable, a few things change for the worse.
The attack surface expands to the whole internet
Any actor anywhere can attempt to connect, probe, or brute force credentials against your endpoint. SAS tokens leak more often than people expect. They end up in client-side code, committed to git history, baked into container images, or pasted into support tickets. A leaked token plus a publicly reachable endpoint equals immediate exploitation. A leaked token against a namespace that only accepts traffic from your VNet is far less useful to an attacker who has no foothold inside your network.
Data exfiltration and injection
If an attacker obtains a connection string with send permissions, they can inject junk or malicious events into your stream. With listen permissions, they can siphon off whatever you are ingesting, which might include customer data, application logs with secrets in them, or financial transactions. Event Hubs is often the place where sensitive data is least scrutinized because it is treated as a transport layer.
Compliance findings
Frameworks like PCI DSS, HIPAA, and SOC 2 expect data services to be segmented from public networks unless there is a documented reason. A publicly exposed Event Hub namespace is a common audit flag, and "it requires authentication" rarely satisfies an assessor on its own.
Warning: Disabling public access will break any producer or consumer that connects from outside your private network, including developer machines, third party SaaS integrations, and resources in other clouds. Map your traffic sources before you flip the switch.
How to fix it
The right fix depends on where your traffic comes from. Most production workloads should use a private endpoint. If you have a small number of known external sources, IP firewall rules are an acceptable middle ground.
Option 1: Disable public access and use a private endpoint (recommended)
First, turn off public network access on the namespace.
az eventhubs namespace update \
--resource-group my-rg \
--name my-namespace \
--public-network-access Disabled
Then create a private endpoint so resources in your VNet can still reach it.
# Find the namespace resource ID
NAMESPACE_ID=$(az eventhubs namespace show \
--resource-group my-rg \
--name my-namespace \
--query id -o tsv)
# Create the private endpoint in your subnet
az network private-endpoint create \
--resource-group my-rg \
--name my-namespace-pe \
--vnet-name my-vnet \
--subnet my-subnet \
--private-connection-resource-id "$NAMESPACE_ID" \
--group-id namespace \
--connection-name my-namespace-connection
Finally, link a private DNS zone so the namespace hostname resolves to the private IP inside your VNet.
az network private-dns zone create \
--resource-group my-rg \
--name "privatelink.servicebus.windows.net"
az network private-dns link vnet create \
--resource-group my-rg \
--zone-name "privatelink.servicebus.windows.net" \
--name my-dns-link \
--virtual-network my-vnet \
--registration-enabled false
Danger: Setting --public-network-access Disabled takes effect immediately. If any active producer or consumer relies on the public endpoint and you have not yet established a private path, those connections will start failing the moment the command completes. Roll this out to a non-production namespace first.
Option 2: Keep public access but scope it with firewall rules
If you genuinely need public connectivity (for example, a partner integration over the internet), restrict it to known IP ranges instead of leaving it wide open.
# Default deny, then allow specific ranges
az eventhubs namespace network-rule-set create \
--resource-group my-rg \
--namespace-name my-namespace \
--default-action Deny
az eventhubs namespace network-rule-set ip-rule add \
--resource-group my-rg \
--namespace-name my-namespace \
--ip-rule ip-address=203.0.113.10 action=Allow
You can also allow a trusted VNet subnet directly:
az eventhubs namespace network-rule-set virtual-network-rule add \
--resource-group my-rg \
--namespace-name my-namespace \
--subnet /subscriptions//resourceGroups/my-rg/providers/Microsoft.Network/virtualNetworks/my-vnet/subnets/my-subnet
Verify the change
az eventhubs namespace show \
--resource-group my-rg \
--name my-namespace \
--query "{publicAccess: publicNetworkAccess}" -o table
Tip: Private endpoints have a per hour and per gigabyte cost. If you have dozens of namespaces, consider consolidating them into fewer namespaces with multiple event hubs each, then sharing a single private endpoint, rather than provisioning one endpoint per namespace.
Fixing it in infrastructure as code
If you manage Event Hubs with Terraform, set the public access argument explicitly so it never defaults back on after a refactor.
resource "azurerm_eventhub_namespace" "main" {
name = "my-namespace"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
sku = "Standard"
public_network_access_enabled = false
network_rulesets {
default_action = "Deny"
trusted_service_access_enabled = true
}
}
For Bicep, the property lives on the namespace properties block:
resource namespace 'Microsoft.EventHub/namespaces@2024-01-01' = {
name: 'my-namespace'
location: location
sku: {
name: 'Standard'
}
properties: {
publicNetworkAccess: 'Disabled'
}
}
How to prevent it from happening again
Manual fixes drift. The namespace someone spins up next month will start with public access enabled because that is the platform default. Close the loop with policy and pipeline gates.
Enforce with Azure Policy
Azure ships a built-in policy for exactly this. Assign it in deny mode so non-compliant namespaces cannot be created.
az policy assignment create \
--name "deny-eventhub-public-access" \
--scope "/subscriptions/" \
--policy "/providers/Microsoft.Authorization/policyDefinitions/" \
--params '{"effect": {"value": "Deny"}}'
Look for the definition named "Event Hub namespaces should disable public network access" in the policy catalog, or filter for it:
az policy definition list \
--query "[?contains(displayName, 'Event Hub') && contains(displayName, 'public')].{name:name, display:displayName}" \
-o table
Catch it in CI/CD
Scan your IaC before it merges. A Checkov or tfsec run in a pull request stops a public namespace from ever reaching your subscription. For Terraform, Checkov already includes a check for this:
checkov -d ./infra --check CKV_AZURE_201
Tip: Pair the policy assignment with continuous monitoring in Lensix so you catch namespaces created through paths that bypass your pipeline, such as the portal or a one off script. Policy deny stops the obvious cases, monitoring catches the rest.
Best practices
- Default to private. Treat public network access as something you justify, not something you disable later. New namespaces should ship with it off.
- Use Azure AD over SAS tokens. Managed identities and role based access control remove long lived connection strings from the equation, which is the most common way Event Hub credentials leak.
- Enable trusted service access deliberately. If you need services like Azure Monitor or Stream Analytics to reach a locked down namespace, turn on the trusted services bypass rather than reopening public access.
- Audit network rule sets, not just the toggle. A namespace with public access enabled but a default deny rule and zero allow entries is effectively closed. The check on its own does not see that nuance, so review the full rule set.
- Log and alert on access patterns. Send Event Hubs diagnostic logs to a workspace and alert on authentication failures, which often precede a credential stuffing attempt.
- Right size your namespaces. Fewer, well secured namespaces are easier to lock down and monitor than a sprawl of one off ones.
Disabling public access is a small change with a large payoff. It shrinks your attack surface, makes leaked credentials far less dangerous, and removes a recurring audit finding, all without touching your application code. Get it into policy once and you stop fighting the same fire every quarter.

