Back to blog
AzureBest PracticesCloud SecurityIdentity & AccessServerless

Disable Local Authentication on Azure Event Hubs Namespaces

Learn why SAS key authentication on Azure Event Hubs is risky, how to disable local auth and switch to Entra ID, and how to enforce it with policy.

TL;DR

This check flags Azure Event Hubs namespaces that still accept SAS key authentication. Shared keys are long-lived, easy to leak, and hard to audit, so disable local auth and force Microsoft Entra ID (Azure AD) by setting disableLocalAuth to true.

Event Hubs is the firehose at the center of a lot of Azure architectures. Telemetry, application logs, IoT streams, and clickstream data all flow through it before landing in Stream Analytics, Functions, or a data lake. Because it sits on that critical path, the way clients authenticate to it matters a great deal. This check looks at one specific setting: whether a namespace still permits local SAS key authentication.


What this check detects

The check inspects each Event Hubs namespace and reports a failure when local authentication is enabled. In the namespace properties this maps to the disableLocalAuth field. When that field is false (the default), clients can connect using Shared Access Signature (SAS) keys derived from namespace or entity level authorization rules.

SAS authentication relies on a pre-shared secret. Anyone holding a valid connection string with the right claims can publish to or read from the hub, no identity required. The alternative is Microsoft Entra ID authentication, where access is granted through role assignments tied to a user, group, or managed identity.

Note: Disabling local auth does not delete your authorization rules or their keys. It simply tells the namespace to reject any connection attempt that presents a SAS token, while continuing to honor Entra ID tokens. The rules sit dormant and can be re-enabled later if needed.


Why it matters

SAS keys are convenient, which is exactly why they show up in places they should not. A few patterns repeat across real incidents:

  • Long-lived secrets in source control. Connection strings get pasted into appsettings.json, committed, and pushed to a repo that later becomes public or gets cloned by a contractor.
  • No identity, no audit trail. A SAS token tells you a key was used, not who used it. If a key leaks, your sign-in logs cannot distinguish a legitimate service from an attacker replaying the same secret.
  • Keys that never rotate. Rotating a SAS key means coordinating every consumer that holds it. Teams avoid the pain, so keys live for years.
  • Over-broad authorization rules. The default RootManageSharedAccessKey grants Manage, Send, and Listen. Hand that connection string to a producer and it can also read every event and reconfigure the namespace.

Put those together and a single leaked string can give an attacker the ability to inject fake telemetry, exfiltrate event data, or quietly tamper with the stream feeding your downstream analytics. With Entra ID, that same compromise would require a valid token from a managed identity, which is short-lived, scoped, and fully logged.

Warning: Before you disable local auth, inventory every client connecting to the namespace. SDKs older than a few major versions, some Logic Apps connectors, and older Stream Analytics configurations may still rely on connection strings. Flipping the switch without migrating those first will break ingestion immediately.


How to fix it

The fix is to disable local authentication once all clients use Entra ID. Do the migration in two stages: grant the right roles, then disable SAS.

Step 1: Assign Entra ID roles to your clients

Event Hubs has three built-in data plane roles. Assign the least privileged one each client needs:

  • Azure Event Hubs Data Sender for producers
  • Azure Event Hubs Data Receiver for consumers
  • Azure Event Hubs Data Owner only where full management is genuinely required
# Grant a managed identity send access to a single Event Hub
az role assignment create \
  --assignee "" \
  --role "Azure Event Hubs Data Sender" \
  --scope "/subscriptions//resourceGroups//providers/Microsoft.EventHub/namespaces//eventhubs/"

Update your application code to use DefaultAzureCredential instead of a connection string. In .NET, for example:

var producer = new EventHubProducerClient(
    "your-namespace.servicebus.windows.net",
    "your-hub-name",
    new DefaultAzureCredential());

Step 2: Disable local authentication

Danger: This command immediately rejects all SAS-based connections to the namespace. Any client still using a connection string will fail to send or receive. Confirm your role assignments are working in a non-production environment first.

az eventhubs namespace update \
  --resource-group  \
  --name  \
  --disable-local-auth true

In the Azure portal, open the namespace, go to Settings > Networking is not it, instead go to the namespace overview and select Configuration, then set Local Authentication to Disabled and save.

If you manage infrastructure as code, set the property directly. Terraform:

resource "azurerm_eventhub_namespace" "this" {
  name                = "my-namespace"
  resource_group_name = azurerm_resource_group.this.name
  location            = azurerm_resource_group.this.location
  sku                 = "Standard"
  local_authentication_enabled = false
}

Bicep:

resource namespace 'Microsoft.EventHub/namespaces@2024-01-01' = {
  name: 'my-namespace'
  location: location
  sku: {
    name: 'Standard'
  }
  properties: {
    disableLocalAuth: true
  }
}

How to prevent it from happening again

One remediation does not stop the next namespace from being created with the default. Bake the requirement into your platform.

Use Azure Policy

There is a built-in policy named Azure Event Hub namespaces should have local authentication methods disabled. Assign it with a Deny effect so non-compliant namespaces are blocked at creation time:

az policy assignment create \
  --name "deny-eventhub-local-auth" \
  --policy "5d4e3c2b-..." \
  --scope "/subscriptions/" \
  --params '{"effect":{"value":"Deny"}}'

Tip: Start with the Audit effect across existing subscriptions to find every namespace that would break, fix those, then switch to Deny. This avoids surprising teams who have not migrated yet.

Gate it in CI/CD

If you deploy through Terraform or Bicep, fail the pipeline when disableLocalAuth is missing or set to false. A simple Conftest policy against a Terraform plan:

package main

deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "azurerm_eventhub_namespace"
  resource.change.after.local_authentication_enabled == true
  msg := sprintf("Event Hub namespace %s must disable local auth", [resource.address])
}

Best practices

  • Treat Entra ID as the default, SAS as the exception. If a workload truly needs a SAS key, document why and scope the rule to the single entity, never the namespace root.
  • Never use RootManageSharedAccessKey for applications. It exists for administration. Create purpose-specific rules with only Send or Listen claims where SAS is unavoidable.
  • Prefer managed identities over service principals with secrets. A managed identity has no credential you can leak, and Azure rotates it for you.
  • Pair this with network controls. Disabling local auth handles identity. Combine it with private endpoints or IP firewall rules so the namespace is not reachable from the open internet.
  • Monitor sign-in logs. Once everything uses Entra ID, you get per-identity activity in the logs. Alert on unexpected principals accessing the namespace.

Disabling local authentication is one of the lower-effort, higher-impact hardening steps available for Event Hubs. It removes an entire class of leaked-secret risk and replaces it with auditable, rotatable, least-privilege access. The only real work is the migration, and once that is done the setting tends to stay quietly correct for the life of the namespace.