Skip to main content

Entra ID Audit via Event Hubs

An Azure event hub is the pipe Microsoft provides for handing logs to a SIEM. Microsoft Entra ID and Azure Monitor do not wait to be asked: a diagnostic setting pushes each record into an event hub as it is written, and Fluency reads the hub with a connection string that can do nothing but listen.

TemplateCollectsWritten into the hub bySteps
Azure Directory Audit (Event Hub)Microsoft Entra ID activity logs — the directory audit, sign-ins and provisioningA Microsoft Entra diagnostic settingThis page
Azure Event HubsAny other Azure log: the subscription Activity Log, and resource logs from Key Vault, Azure Firewall, SQL, Storage and the restAzure Monitor diagnostic settingsAzure Event Hubs

Azure Directory Audit (Event Hub) is how Fluency collects the Entra ID audit log. It replaces Azure Directory Audit, which polls Microsoft Graph and is now a legacy template. Compared with the Event Hub route, on that page, sets the two side by side.

The setup has three parts, and they often belong to three different people:

  1. In Azure — someone with Contributor on an Azure subscription creates an Event Hubs namespace, an event hub, and a Listen-only policy on that hub. This produces one value, the policy's Primary connection string.
  2. In Microsoft Entra ID — a Security Administrator adds a diagnostic setting that streams the Entra logs into the hub.
  3. In Fluency — install the Azure Directory Audit (Event Hub) template with the connection string.

Nothing is granted to Fluency inside your directory: there is no application to consent to and no Microsoft Graph permission. The only credential that leaves Azure is the connection string, and it reaches one event hub and can only read from it.

What arrives​

Microsoft Entra ID logs​

The diagnostic setting decides which categories go into the hub. The choice is made in Entra ID, not on the install form, and it can be changed later without touching Fluency. The template keeps the first six below and drops the rest — see Where it is filed.

CategoryContentsLicence
AuditLogsDirectory changes: users, groups, applications, role assignments, licences, password resets, consent grants. The record of what changed in your identity system and who changed it.Any tier
SignInLogsInteractive user sign-ins — a user entering a password or passing an MFA challenge — with client IP, device, application, Conditional Access result and risk.P1 or P2
NonInteractiveUserSignInLogsSign-ins a client performs on a user's behalf with a token or code, such as token refreshes.P1 or P2
ServicePrincipalSignInLogsApplications signing in as themselves with a certificate or client secret.P1 or P2
ManagedIdentitySignInLogsManaged identities signing in, where Azure holds the secret.P1 or P2
ProvisioningLogsUser and group provisioning to and from connected applications such as Workday or ServiceNow.P1 or P2
RiskyUsers, UserRiskEvents, RiskyServicePrincipals, ServicePrincipalRiskEventsMicrosoft Entra ID Protection's risk state and risk detections. Dropped by this template.P2
MicrosoftGraphActivityLogsEvery HTTP request made to your tenant through Microsoft Graph. Dropped by this template.P1 or P2

The list in your tenant can be longer. ADFSSignInLogs is populated only for AD FS applications, the NetworkAccess…, RemoteNetworkHealthLogs and EnrichedOffice365AuditLogs categories only for Global Secure Access customers, and Microsoft describes MicrosoftServicePrincipalSignInLogs, its first-party service-to-service sign-ins, as "not necessary for most customers as they are complex and generate a high volume of data". Leave that one off.

Microsoft lists audit logs as available on every tier, including Free. For sign-ins, the diagnostic-setting screen itself warns that exporting sign-in data requires a P1 or P2 licence, so on a Free tenant select AuditLogs and expect nothing from the sign-in categories.

Sign-in volume is the cost driver

Microsoft's own estimate: "the non-interactive user sign-ins and service principal sign-ins can be 5 to 10 times larger than the interactive user sign-ins." They are also where token theft and abused application credentials show up, so they are worth collecting — but size the namespace for them (see Troubleshooting for what throttling looks like), and leave MicrosoftGraphActivityLogs off: it records every Graph call in the tenant, and this template drops it.

Three Microsoft feeds carry Entra activity, and they are not the same records

The diagnostic-setting records collected here, the Microsoft Graph records the legacy Azure Directory Audit template polls, and the Audit.AzureActiveDirectory content type in the Office 365 unified audit log (Office 365 Activity API) describe overlapping events in different shapes, with different fields and different retention. Running this alongside the unified audit log is duplicate coverage, not duplicate data.

Where it is filed​

Each record is kept twice. As Microsoft exported it — the Azure Monitor envelope, with the Entra record under properties — it goes to the index named on the install form, MSEntra by default. That is the index the Default-EntraID_AuditLogs and Default-EntraID_SignIn search facets are set on, and the Entra ID detection rules match the same records; both select them by @eventType, which holds the category. MSEntra is this template's own index: the legacy Azure Directory Audit template and Office365-Audit write their Microsoft Graph records to AzureAudit by default, so the event hub and Graph shapes are not mixed in one index. The sign-in and audit categories are also rewritten into the columns of the matching Log Analytics table, so a query written against Microsoft's table runs unchanged, and each goes to an index of its own:

CategoryMSEntraTable index
AuditLogsYesAzureAuditLogs
SignInLogsYesAzureSigninLogs
NonInteractiveUserSignInLogsYesAADNonInteractiveUserSignInLogs
ServicePrincipalSignInLogsYesAADServicePrincipalSignInLogs
ManagedIdentitySignInLogsYesAADManagedIdentitySignInLogs
ProvisioningLogsYes—

The table indexes are fixed by the template, not parameters, and they are the same five that the legacy Azure Directory Audit and Office365-Audit templates fill from Microsoft Graph. Every other category is dropped — the ID Protection risk categories, MicrosoftGraphActivityLogs, ADFSSignInLogs and the Global Secure Access categories among them — so selecting one costs namespace throughput and collects nothing. To keep them, send them with a second diagnostic setting to a hub of their own, read by the Azure Event Hubs template.

Retention: the hub's, not Entra's​

A diagnostic setting streams records as Entra writes them. It does not send anything older than the setting itself, and it does not re-send a record that has already gone into the hub. So once a record is in the hub, the hub's retention is how long Fluency has to read it:

Event Hubs tierMaximum retentionConsumer groups
Basic1 day$Default only
Standard7 daysUp to 20

That retention is the length of Fluency-side outage the integration survives. Entra keeps its own copy for its own retention period — seven days on Free, 30 on P1 or P2 — but nothing feeds that copy back into the hub. Use Standard and set the hub's retention to the full seven days.

Before you begin​

An Azure subscription in the same tenant, and Contributor on it. The namespace and hub are Azure resources, so creating them needs Azure RBAC — Contributor or Owner on the subscription, or Contributor on an existing resource group — rather than an Entra directory role. Microsoft requires that "The subscription and Event Hubs namespace must both be associated with the Microsoft Entra tenant from where you're streaming the logs."

The namespace is billed for as long as it exists, per throughput unit per hour plus ingress, whether or not anything reads it. One Standard throughput unit is the starting point.

A Security Administrator in Microsoft Entra ID, for the diagnostic setting. Microsoft names it "the least privileged role required to configure diagnostic settings". That person also needs to read the keys of a policy on the namespace — Azure Monitor's rule is that "you must have the ListKey permission on that Event Hubs authorization rule" — which is an Azure permission, not an Entra one. Either one person holds both, or the Security Administrator is given Contributor on the namespace for the step.

Compared with the legacy Azure Directory Audit template, no Global Administrator or Privileged Role Administrator is involved, and no Fluency application is added to your tenant.

A P1 or P2 licence for sign-ins and provisioning logs. The directory audit needs neither.

Access to the Fluency portal with permission to install applications.

Part 1 — Azure​

Performed in the Azure portal by someone with Contributor on the subscription.

1. Create the namespace​

Search for Event Hubs and choose + Create. On the Basics tab:

  • Subscription and Resource group — the subscription in your Entra tenant; Create new, under the resource group list, makes a resource group for the integration.
  • Namespace name — globally unique; it becomes <name>.servicebus.windows.net.
  • Region — any region. Entra ID is a global service, so the region does not have to match anything for Entra logs.
  • Pricing tier — Standard. The capture below shows Basic, whose one-day retention and single consumer group are too little for this.
  • Throughput Units — 1.

Create Namespace Basics tab with the default subscription, a new fluency-azure-audit resource group and namespace name, the East US region, the Basic pricing tier and one throughput unit

Choose Review + create, then Create once the banner reads Validation succeeded. When the deployment page reads Your deployment is complete, choose Go to resource.

Deployment overview reading Your deployment is complete, with the Go to resource button under Next steps

2. Create the event hub​

In the namespace, go to Entities → Event Hubs, and choose + Event Hub.

Event Hubs page of the fluency-azure-audit namespace, under Entities, with the + Event Hub button and no event hubs yet

On the Basics tab:

  • Name — for example entra-logs. Give Entra ID a hub of its own; other Azure logs go into a different hub, read by the Azure Event Hubs template.
  • Partition count — 2 is enough for most tenants. It cannot be changed after creation on Basic or Standard.
  • Cleanup policy — Delete, the default.
  • Retention time (hrs) — the maximum the tier allows: 168, seven days, on Standard. The allowed range is printed under the field; the capture is from a Basic namespace, where it stops at 24.

Leave the Capture tab as it is, then choose Review + create and Create.

Create Event Hub Basics tab with the name fluency-azure-audit, a partition count of 1, the Delete cleanup policy and a retention time of 24 hours

3. Create a Listen-only policy on the event hub​

Open the new hub from the Event Hubs list.

Event Hubs page of the namespace listing the fluency-azure-audit hub, Active, with 24 hours of message retention

In the hub, go to Settings → Shared access policies and choose + Add.

Shared access policies page of the fluency-azure-audit event hub, headed Event Hubs Instance, with no policies set up yet

Name the policy — fluency-listen, say — tick Listen and nothing else, and choose Create.

Add SAS Policy panel with the policy name fluency-azure-audit, only Listen ticked, and the Create button

On the event hub, not the namespace

The namespace has a Shared access policies page too, and the two look almost identical. The sub-heading under the page title tells them apart: Event Hubs Instance is the hub, which is where this policy belongs; Event Hubs Namespace is the wrong page. A namespace policy's connection string lacks ;EntityPath=<hub name>, reaches every hub in the namespace, and — if it is the built-in RootManageSharedAccessKey — carries Manage rights over all of them.

Shared access policies page headed Event Hubs Instance, listing the fluency-azure-audit policy with the Listen claim

4. Copy the connection string​

Select the policy. The SAS Policy panel opens with the policy's claims and five values under them — Primary key, Secondary key, Primary connection string, Secondary connection string and SAS policy ARM ID.

SAS Policy panel for fluency-azure-audit with only Listen ticked, the masked Primary key, Secondary key, Primary connection string and Secondary connection string, and the SAS policy ARM ID

Four of the five are credentials, and only one of them goes into Fluency: the Primary connection string. The two keys are bare secrets, without the namespace, policy name and hub that Fluency also needs, and the Secondary connection string is held back for rotating the key.

The five SAS Policy values with Primary connection string boxed in red and revealed, starting Endpoint=sb://fluency-azure-audit.servicebus.windows.net/;SharedAccessKeyN and cut off by the field&#39;s width; the two keys and the Secondary connection string are masked

Copy it with the copy button at the end of its field. The field is too narrow to show the whole string, so selecting the visible text gets only the start of it. Leave Show AMQP connection strings unticked.

Copy the whole string, exactly as Azure gives it

Fluency takes the connection string as one value, unedited. It is a single line of four name=value pairs separated by semicolons, starting with Endpoint=sb:// and ending with ;EntityPath= and the hub's name:

Endpoint=sb://<namespace>.servicebus.windows.net/;SharedAccessKeyName=<policy name>;SharedAccessKey=<key>;EntityPath=<hub name>

Do not cut it down to the SharedAccessKey value, drop the EntityPath, or add quotes, spaces or line breaks. A string with no ;EntityPath= came from a namespace policy, not the hub's — go back to step 3.

ValueWhere it came from
Primary connection stringThe Listen policy on the event hub, step 3

The string carries the policy's key, so treat it as a credential. Unlike most secrets, though, it is not shown once: it can be read again from Shared access policies at any time, and replaced by regenerating the key.

Automated alternative — Azure CLI​

Steps 1 to 4 as Azure CLI commands. Run them signed in to the right subscription (az account show names it), and replace the namespace name with one of your own.

RG=fluency-eventhub-rg
NS=<globally-unique-namespace-name>
HUB=entra-logs

az group create --name "$RG" --location eastus

az eventhubs namespace create --resource-group "$RG" --name "$NS" \
--location eastus --sku Standard --capacity 1

az eventhubs eventhub create --resource-group "$RG" --namespace-name "$NS" \
--name "$HUB" --partition-count 2 --cleanup-policy Delete --retention-time-in-hours 168

az eventhubs eventhub authorization-rule create --resource-group "$RG" \
--namespace-name "$NS" --eventhub-name "$HUB" --name fluency-listen --rights Listen

# The Primary connection string
az eventhubs eventhub authorization-rule keys list --resource-group "$RG" \
--namespace-name "$NS" --eventhub-name "$HUB" --name fluency-listen \
--query primaryConnectionString -o tsv

Older Azure CLI releases do not accept --cleanup-policy and --retention-time-in-hours; on those, use --message-retention 7 instead. A subscription that has never used Event Hubs may need az provider register --namespace Microsoft.EventHub --wait first.

Part 2 — Microsoft Entra ID​

Performed by a Security Administrator who can also read the namespace's keys — see Before you begin.

5. Add a diagnostic setting​

  1. Sign in to the Microsoft Entra admin center and browse to Entra ID → Monitoring & health → Diagnostic settings. The export settings link on the Audit logs and Sign-in logs pages leads to the same place.

    Diagnostic settings page in the Microsoft Entra admin center, reached from Monitoring &amp; health, with its General and Custom security attributes tabs

  2. On the General tab, choose + Add diagnostic setting.

  3. Enter a Diagnostic setting name, such as fluency. It cannot be changed later.

  4. Under Logs → Categories, select the categories to send — at least AuditLogs, and the four sign-in categories and ProvisioningLogs if the tenant has P1 or P2. The template drops anything else; see Where it is filed.

  5. Under Destination details, tick Stream to an event hub and fill in its fields:

    FieldValue
    SubscriptionThe subscription from step 1.
    Event hub namespaceThe namespace from step 1.
    Event hub name (optional)The hub from step 2. Optional to Azure, not to this integration: left empty, Azure creates hubs of its own in the namespace, named insights-logs-…, which the connection string from step 4 does not reach.
    Event hub policy nameRootManageSharedAccessKey, or another namespace-level policy with Manage, Send and Listen — Azure Monitor requires all three to stream. This is Entra's write credential. It is separate from Fluency's Listen-only one and never leaves Azure.
  6. Choose Save. A Successfully updated diagnostics notice confirms it.

Saved diagnostic setting fluency-azure-audit with AuditLogs, the four sign-in categories and ProvisioningLogs ticked, Stream to an event hub selected with the fluency-azure-audit namespace and hub and the RootManageSharedAccessKey policy, and the Successfully updated diagnostics notice

Custom security attribute logs are a separate setting

Audit records for custom security attributes are configured under the Custom security attributes tab of Diagnostic settings, and need the Attribute Log Administrator role as well as Security Administrator. Microsoft recommends sending them to a different destination from the directory audit, "so that attribute assignments are not revealed inadvertently."

6. Check that the hub is receiving​

Open the event hub's Overview page in the Azure portal and watch the Messages chart. Incoming Messages above zero means Entra is writing.

Event hub overview with the Requests and Messages charts, showing a non-zero Incoming Messages count

The first records take a while. Azure Monitor's guidance is that "data should start flowing to your selected destinations within 90 minutes", and Entra's documentation allows that "It might take up to three days for the logs to start appearing in the destination." To have something definite to look for, make a harmless change in Entra — create a group, then delete it — once the setting is saved.

Part 3 — Fluency​

Install the Application​

Go to Platform → Applications → Install Application From Template and choose Azure Directory Audit (Event Hub) from the Office Software (SaaS) and IAM category — not the Azure Directory Audit tile beside it, which is the legacy Microsoft Graph template.

Office Software (SaaS) and IAM category of the template catalog, with the Azure Directory Audit (Event Hub) tile next to Azure Directory Audit

ParameterNotes
Event Hub connection string (Listen policy, including EntityPath)The Primary connection string from step 4, whole and unedited — Endpoint=sb://…;EntityPath=<hub name>.
consumer group this datasource reads with (create a dedicated one if anything else already reads this hub)Pre-filled $Default. Keep it while Fluency is the hub's only reader; a Basic hub has no other. A name that does not exist on the hub collects nothing.
DescriptionOptional. An editable parameter, distinct from the read-only Description shown in the form's Application section.
datalakePre-filled managed.
datalake index namePre-filled MSEntra — the index of as-exported records. Keep it: the Entra ID search facets are set on MSEntra by name. Two applications writing to the same index name in the same lake will collide, and the second one aborts.

The last two sit in the collapsed Advanced Configurations row below the parameters — expand it to reach them.

Setup New Azure Directory Audit (Event Hub) Application panel

Check the connection string before you press Install

The Event Hub connection string field takes the Primary connection string exactly as you copied it in step 4 — one line, starting with Endpoint=sb:// and ending with ;EntityPath= and the hub's name:

Endpoint=sb://<namespace>.servicebus.windows.net/;SharedAccessKeyName=<policy name>;SharedAccessKey=<key>;EntityPath=<hub name>

Not the Primary key on its own, and not a namespace policy's string, which has no EntityPath. Template parameters are read-only after install, so a wrong value means uninstalling the application and installing it again.

Press Install. The application then appears in the Installed Applications view as Azure Directory Audit (Event Hub): Default, with a Pending badge that turns to Running once the pipeline is up.

Confirm it is running​

The application's card draws its pipeline: the event hub data source, the router, the five table indexes listed under Where it is filed, and the management queue that carries the as-exported records into MSEntra.

Installed Applications card for Azure Directory Audit (Event Hub): Default, marked Running, with the AzureAuditEventHub-default plugin data source and router, five Data Lake indexes from AADManagedIdentitySignInLogs to AzureSigninLogs, and a management queue

Running reports the pipeline, not the stream. Confirm on both sides:

  1. In Azure, on the hub's Overview page, Outgoing Messages starts rising alongside Incoming Messages once Fluency is reading. Between them, the two lines localise most problems:

    IncomingOutgoingMeaning
    ZeroZeroNothing is writing to this hub. Go back to step 5.
    RisingZeroEntra is writing and nothing is reading. Check the connection string and the application.
    RisingRisingFluency is reading.
  2. In Fluency, search the MSEntra index — managed-MSEntra in the Search index selector — for @eventType:AuditLogs and the group you created in step 6. See Confirm data is arriving.

An empty index on a quiet tenant proves nothing

The directory audit only records changes, so a stable tenant can be quiet for hours. A change you made yourself, found in the index minutes later, distinguishes "nothing has happened" from "nothing is arriving". With sign-ins collected, signing in to the Microsoft Entra admin center does the same job.

Maintenance​

Rotating the key​

Every shared access policy has two keys, which makes an overlap possible: reinstall the application with the policy's Secondary connection string, and once data is flowing again, regenerate the primary key in Azure. Template parameters are read-only after install, so a new value means uninstall and reinstall. Keep the gap shorter than the hub's retention and nothing is lost. Rotating the Key has the full procedure.

Changing what is streamed​

Edit the diagnostic setting in Entra ID — Edit setting on its row — to add or remove categories. Nothing changes on the Fluency side, and only records written after the change are affected.

Removing the integration​

  1. Uninstall the application in Fluency, with the red Uninstall button at the foot of its details panel.
  2. Delete the diagnostic setting in Entra ID → Monitoring & health → Diagnostic settings. Left in place, Entra keeps writing into a hub nobody reads.
  3. Delete the namespace, or the whole resource group, to stop the hourly charge.

Troubleshooting​

SymptomLikely causeFix
Incoming Messages stays at zeroThe diagnostic setting points at a different hub — usually because Event hub name was left empty and Azure created insights-logs-… hubs of its ownEdit the setting and choose the hub from step 2. The namespace's Event Hubs list shows any hubs Azure created; delete them once nothing writes to them.
Incoming Messages stays at zero for a new setting, and it points at the right hubToo early, or a quiet tenantMicrosoft allows up to three days. Make a change in Entra to give it something to send.
Incoming rises, Outgoing stays at zeroFluency is not readingCheck that the connection string ends in ;EntityPath= and this hub's name, that any consumer group named on the form exists on the hub, and that the application is Running.
The connection string has no EntityPathThe policy was created on the namespaceCreate a Listen-only policy on the event hub — step 3 — and reinstall with its string.
The diagnostic setting's namespace list is empty, or Save fails with an authorization errorThe person creating it cannot list the namespace's keys, or the subscription belongs to another tenantGive them Contributor on the namespace, or use a subscription associated with this Entra tenant.
Diagnostic settings is read-only, or Add diagnostic setting is unavailableThe signed-in account is not a Security AdministratorSign in with an account that holds the role.
AuditLogs arrive, sign-ins never doThe tenant has no Entra ID P1 or P2 licence, or the sign-in categories were not selectedExpected on Free. Otherwise, edit the setting and select them.
Risk, Graph activity or other categories are selected and never appearThis template keeps only the sign-in, audit and provisioning categoriesSend them with a second diagnostic setting to a hub read by the Azure Event Hubs template.
Provisioning records are not in any table indexProvisioningLogs has no table indexSearch MSEntra for @eventType:ProvisioningLogs. Provisioning logs need P1 or P2, and a tenant that provisions nothing has none.
Throttled requests on the hub's Overview, and collection falls behindThe namespace has too few throughput units for the volume — usually the non-interactive and service principal sign-insAdd throughput units, or enable Auto-inflate on a Standard namespace.
The namespace's Networking restricts public accessAzure Monitor cannot write and Fluency cannot readAzure Monitor requires Allow trusted Microsoft services to bypass the firewall; Fluency also has to be able to reach the namespace.
A gap after a Fluency-side outageThe outage outlasted the hub's retentionUnrecoverable through the hub. Standard retains up to seven days; Basic one.

Under the hood​

Engineering reference — record shape, the template and the reader

What Azure writes​

Azure Monitor and Entra diagnostic settings write JSON batches of the form {"records": [ … ]} to the hub. Each record carries time, category, operationName, resourceId and properties at least; for Entra categories, properties holds the audit or sign-in record itself. Records are written as they are produced and partitioned without a key, so their order across partitions is not guaranteed — sort on time, not on arrival.

The Azure Directory Audit (Event Hub) template​

The application reads the hub through an Azure EventHubs plugin data source, AzureAuditEventHub-<name>, which feeds a router of the same name. Two pipes run on the router:

  1. AzureAuditEventHub_Transform rewrites each sign-in and directory audit record into the columns of its Log Analytics table, writes it to that table's index, and passes the original record on. Where Graph's object has no value for a column, the Azure Monitor envelope fills it: AADTenantId, Level, ResultType and ResultDescription, and for audits OperationName, OperationVersion, ResultSignature, Identity and DurationMs.
  2. AzureAuditEventHub_Adjustments drops every category but the sign-ins, the directory audit and provisioning, and writes the rest, unchanged, to the form's index through the management queue, also named AzureAuditEventHub-<name>. It adds only @ metadata: @timestamp from the record's own time (createdDateTime for sign-ins, activityDateTime for audit and provisioning, the envelope's time otherwise), @eventType set to the category, @tenantId, @sender (azureAudit) and @source (AzureEventHub). On UserManagement audits it also geolocates the initiating user's IP address, under @normalized.

The form's index is created with the MSEntra schema, listed on Data Lake → Schemas. It is dynamic: each record is held whole as JSON in a doc column, beside timestamp, size and labels. The legacy template's AzureAudit schema has the same layout, but the records in it are Microsoft Graph's, not the Azure Monitor envelope.

Consumer groups and checkpoints​

The application reads through the consumer group named on the form. Unlike the Azure Event Hubs template, it has no checkpoint-storage parameter. Another application reading the same hub needs a different consumer group. Event Streams covers both.

References​

Microsoft

Fluency