From 4b212e2322c71c3611f85d6e6e80869fb58bf935 Mon Sep 17 00:00:00 2001 From: Hou Chi Chan Date: Tue, 13 Oct 2026 11:10:42 -0700 Subject: [PATCH 1/8] docs: add Microsoft Entra sign-in monitoring guide Document tenant log export, scoped KQL, workbooks, scheduled alerts, safe validation and investigation limits. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f1451aca-6f84-41e6-9baf-cec42e36da6e --- README.md | 1 + docs/APPLICATION-INSIGHTS.md | 4 + docs/MONITORING.md | 5 + docs/ONBOARDING.md | 4 + docs/SIGN-IN-MONITORING.md | 477 +++++++++++++++++++++++++++++++++++ 5 files changed, 491 insertions(+) create mode 100644 docs/SIGN-IN-MONITORING.md diff --git a/README.md b/README.md index 8ab0042..186cc74 100644 --- a/README.md +++ b/README.md @@ -246,6 +246,7 @@ Deleting Azure resources does not undo an authentication policy change. | Find IDs, add provider credentials, or run acceptance checks | [Customer configuration and validation](docs/ONBOARDING.md) | | Resolve a setup or delivery problem | [Troubleshooting](setup/docs/Troubleshooting.md) | | Find logs and set up alerts | [Monitoring](docs/MONITORING.md) and [Application Insights](docs/APPLICATION-INSIGHTS.md) | +| Monitor authentication outcomes and potential abuse | [Microsoft Entra sign-in monitoring](docs/SIGN-IN-MONITORING.md); configured separately from endpoint telemetry | | Understand the architecture, settings, or packages | [Technical reference](TECHNICAL.md) and [HTTP contract](docs/CONTRACT.md) | | Explore multiple Azure regions | [Manual Front Door guide](docs/FRONTDOOR.md); not included in guided setup | | Build a custom implementation | [JavaScript](javascript/README.md), [C#](dotnet/README.md), or [Python](python/README.md) | diff --git a/docs/APPLICATION-INSIGHTS.md b/docs/APPLICATION-INSIGHTS.md index a983d4f..514fb77 100644 --- a/docs/APPLICATION-INSIGHTS.md +++ b/docs/APPLICATION-INSIGHTS.md @@ -6,6 +6,10 @@ reported along the way. It does **not** confirm that an SMS or voice call reache **Looking for your logs?** Start with the [monitoring guide](MONITORING.md). It shows how to find the resources from your deployment summary, run queries, and create alerts. +For user authentication outcomes, see [Microsoft Entra sign-in monitoring](SIGN-IN-MONITORING.md). +It uses a separate tenant log-export pipeline, not Function telemetry; neither source alone +proves phone delivery. + This reference explains how collection works for **JavaScript, .NET isolated, and Python**, what each signal means, and why data may be missing. Start with [single-region configuration](#single-region-configuration) to check a guided deployment; diff --git a/docs/MONITORING.md b/docs/MONITORING.md index 742f53f..5f85575 100644 --- a/docs/MONITORING.md +++ b/docs/MONITORING.md @@ -3,6 +3,11 @@ Use this guide to find your endpoint's logs and set up alerts. Guided setup creates Application Insights and a Log Analytics workspace, but **you still need to configure and test notifications**. +For **tenant authentication outcomes and potential abuse signals**, use the separate +[Microsoft Entra sign-in monitoring guide](SIGN-IN-MONITORING.md). Entra log export and +sign-in alerts are not configured by endpoint setup; sign-in failures are not automatically +provider failures or evidence of OTP delivery. + For your first single-region deployment: 1. [Find the monitoring resources and confirm data is arriving](#1-record-the-deployment-and-confirm-telemetry) diff --git a/docs/ONBOARDING.md b/docs/ONBOARDING.md index 7e3c4fa..d63ebd6 100644 --- a/docs/ONBOARDING.md +++ b/docs/ONBOARDING.md @@ -12,6 +12,10 @@ the [values worksheet](#values-and-ownership), or the [setup reference](../setup [Local development and manual deployment](#optional-local-development-and-manual-deployment) are separate, optional paths. +For operational handover, use [Function monitoring](MONITORING.md) and, separately, +[Microsoft Entra sign-in monitoring](SIGN-IN-MONITORING.md) for authentication outcomes +and potential abuse investigations. Endpoint setup does not enable tenant log export or alerts. + ## Before purchasing or deploying Open [Microsoft Security Store](https://securitystore.microsoft.com/private-solutions) and review diff --git a/docs/SIGN-IN-MONITORING.md b/docs/SIGN-IN-MONITORING.md new file mode 100644 index 0000000..24068f1 --- /dev/null +++ b/docs/SIGN-IN-MONITORING.md @@ -0,0 +1,477 @@ +# Monitor Microsoft Entra sign-ins + +Use Microsoft Entra sign-in logs to investigate authentication failures, understand traffic, +and notify operators about unusual activity. This is **tenant identity monitoring**, separate +from the [Function monitoring guide](MONITORING.md) and [Application Insights](APPLICATION-INSIGHTS.md). +Guided EPP setup does **not** export Entra logs or create the Workbooks, action groups, or alerts +described here. These instructions are customer configuration guidance, not a deployed monitor. + +Start by [choosing the tenant and permissions](#1-choose-the-tenant-and-permissions), then +[exporting logs](#2-export-the-required-log-categories), [checking actual records](#3-confirm-arrival-and-schema), +and [creating alerts](#5-create-actionable-log-search-alerts). A +[Workbook](#6-build-a-sign-in-workbook) provides a shared investigation view. + +## What these logs can and cannot tell you + +Sign-in logs describe authentication to an application: result codes, authentication steps, +Conditional Access outcomes, and available identity/network context. They do **not** provide a +guaranteed CYOT/EPP provider identifier, delivery mode, provider billing total, or a reliable +count of SMS or voice sends. Do not infer provider usage from an authentication method named `SMS` or `Voice`, +or from `AuthenticationRequirement == "multiFactorAuthentication"`. + +A failed sign-in can mean an invalid password, an interrupted challenge, user cancellation, +a policy rejection, or another authentication failure. It does not by itself identify a phone +provider outage. A successful sign-in does not prove the EPP Function was called, which provider +was used, or that an OTP reached a recipient; an existing token claim can satisfy authentication. +Several records can describe one authentication sequence, including successive MFA outcomes. +The queries below count **stored log rows**, not unique customers, completed sessions, or sends. + +Use Function request/log telemetry for endpoint execution and provider acceptance; use the +provider's approved delivery reports and billing controls for delivery, send volume, and costs. +Evaluation and live EPP requests can both return HTTP 200. `SigninLogs` has no EPP `evaluation` +field, and an endpoint evaluation is not guaranteed to produce a user sign-in row. + +## 1. Choose the tenant and permissions + +Identify the tenant where the **user authentication** occurs, not merely the tenant/subscription +hosting the Function. Record its tenant ID, tenant type, intended customer-facing application's +client ID(s), destination workspace resource ID, and monitoring/security owners privately. +The application's `SigninLogs.AppId` is **not necessarily** the dedicated endpoint application's +`applicationId` in the EPP deployment summary. Confirm it against a real sign-in record. + +There are different setup paths: + +- **Workforce tenant**, including B2B guests: follow the + [global Entra-to-Azure Monitor integration](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-integrate-activity-logs-with-azure-monitor-logs). + Configure general diagnostic settings as at least **Security Administrator**, with an Azure + subscription, a Log Analytics workspace, and the necessary Azure permissions on the destination. +- **External tenant** for consumer/business-customer apps: follow + [Azure Monitor in external tenants](https://learn.microsoft.com/en-us/entra/external-id/customers/how-to-azure-monitor). + An external tenant cannot have an associated Azure subscription. Its setup wizard authenticates + the subscription in a **workforce tenant** and configures the Azure Lighthouse access path. + The documented prerequisites include Azure RBAC **Owner** on that subscription and + **Security Administrator or Application Administrator** in the external tenant. + Users selected to configure diagnostic settings still need at least **Security Administrator**. + Review the wizard's delegation, selected users/groups, workspace, region, and costs before + approving it; do not move the EPP subscription or change tenant/policy settings to imitate + the workforce instructions. + +Entra roles and Azure RBAC are separate. **Reports Reader** is the least privileged Entra role +for reading activity logs in the admin center; it does not grant workspace access. Grant +investigators appropriately scoped log-query access, such as **Log Analytics Reader**, using +[workspace/table access controls](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/manage-access). +Saving or sharing a Workbook does not grant access to its underlying logs. + +Current [monitoring licensing guidance](https://learn.microsoft.com/en-us/entra/fundamentals/licensing#microsoft-entra-monitoring-and-health) +lists sign-in and audit logs for Entra ID Free as well as P1/P2. Do not confuse that with +premium report, Graph API, risk, or Workbook-template entitlements; confirm requirements for +each feature and tenant type before purchasing or enabling it. Azure ingestion, retention, +querying, alert evaluation, and notifications can incur separate charges. + +**Risk is optional and tenant-dependent.** The current +[external-tenant feature comparison](https://learn.microsoft.com/en-us/entra/external-id/customers/concept-supported-features-customers) +lists **Microsoft Entra ID Protection as unavailable in external tenants**. Do not apply +workforce P2 risk-detection promises to that tenant. In supported workforce tenants, full +[ID Protection](https://learn.microsoft.com/en-us/entra/id-protection/overview-identity-protection) +risk capabilities require P2 (or an applicable entitlement). The `SigninLogs` schema documents +`RiskLevelDuringSignIn`, `RiskLevelAggregated`, `RiskState`, and `RiskDetail`, but some values are +`hidden` without the required entitlement. Empty, `none`, or `hidden` is not a clearance of fraud. +Check current product availability and actual records before using risk fields. + +## 2. Export the required log categories + +For a workforce tenant, or after completing the external-tenant monitoring wizard: + +1. In the **Microsoft Entra admin center**, switch to the tenant being monitored. +2. Open **Entra ID > Monitoring & health > Diagnostic settings**. Review existing settings + first to avoid unintended duplicate destinations or changing someone else's integration. +3. Select **Add diagnostic setting** (or deliberately edit the approved setting) and name it. +4. Select the **SignInLogs** category for interactive user sign-ins. Add **AuditLogs** if you + also need directory-change investigations. Select only additional categories justified by + your operational needs and available in this tenant. +5. Under **Destination details**, select **Send to Log Analytics workspace**, then choose + the approved subscription/workspace. In an external tenant, use the workspace/access path + established by the external-tenant instructions. +6. Select **Save**, then read back the categories and destination. Record the owner and date. + +The [streaming category reference](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-diagnostic-settings-logs-options) +distinguishes these sources; category labels and workspace table names are not identical: + +| Selected log category | Workspace table | Intended use | +| --- | --- | --- | +| SignInLogs | [SigninLogs](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/signinlogs) | Interactive user authentication; primary source for the examples below. | +| Non-interactive user sign-ins | [AADNonInteractiveUserSignInLogs](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/aadnoninteractiveusersigninlogs) | Token/client activity on behalf of users; keep its baseline separate. | +| Service principal sign-ins | [AADServicePrincipalSignInLogs](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/aadserviceprincipalsigninlogs) | Application/workload authentication, not end-user OTP outcomes. | +| Managed identity sign-ins | [AADManagedIdentitySignInLogs](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/aadmanagedidentitysigninlogs) | Managed identity authentication, not end-user OTP outcomes. | +| AuditLogs | [AuditLogs](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/auditlogs) | Directory changes; not a replacement for sign-in outcomes. | + +The external-tenant [Microsoft samples](https://github.com/microsoft/external-id-azure-monitor) +also query `SigninLogs` for authentication reporting. That is not a guarantee every workforce +category, premium report, or populated field exists in an external tenant. Check the category +picker and the workspace's actual tables; do not union unavailable tables or substitute +`AuditLogs` for a missing `SigninLogs` feed. Provider-side OAuth logs may be in the provider's +tenant and require its administrator's assistance. + +The Function's diagnostic setting is a **different setting on a different resource**. +Creating Application Insights or enabling Function logs does not export Entra activity. +Export is not a backfill of all historical portal logs. + +## 3. Confirm arrival and schema + +Open **Azure portal > Log Analytics workspaces > your destination > Logs**, then use **KQL mode**. +Choose an appropriate time range and confirm `SigninLogs` in the table browser. Do not run +these examples from the Application Insights application-table context (`requests`, `traces`). + +Initial arrival is not immediate: Microsoft's external-tenant samples describe about 45 minutes, +while the [general diagnostic-setting guidance](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-configure-diagnostic-settings) +allows up to three days for initial logs. These are setup allowances, not a steady-state latency +SLA. After initial arrival, measure normal delays before enabling paging alerts. + +Run these two queries separately: + +```kusto +SigninLogs +| getschema +``` + +```kusto +SigninLogs +| where TimeGenerated >= ago(24h) +| summarize StoredRows = count(), LatestLogTime = max(TimeGenerated) + by AADTenantId, AppId, AppDisplayName, IsInteractive, Category +| order by LatestLogTime desc +``` + +If the table is unresolved, fix collection/destination/access first; do not mask it with an +empty fallback. If it exists but returns no rows, compare the correct tenant's **Monitoring +& health > Sign-in logs** with the workspace, export start time, selected category, time range, +and expected application traffic. An empty result is not evidence that authentication is healthy. +Inspect any collection transformations that could remove needed rows or columns. + +The remaining queries require the verified +[SigninLogs schema](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/signinlogs). +Replace `` with the observed `AADTenantId` and `` +with the observed application's **client ID**, not an Object ID, display name, or provider API ID. +Use one app per initial alert rule; add further app IDs only after validating each scope. +`AADTenantId` identifies the source directory; do not substitute the workspace's tenant. + +Inspect a bounded set of records without returning user names, phone/sign-in identifiers, +IP addresses, or the entire authentication details payload: + +```kusto +SigninLogs +| where TimeGenerated >= ago(24h) +| where AADTenantId =~ "" and AppId =~ "" +| project TimeGenerated, CreatedDateTime, Id, CorrelationId, ResultType, + AuthenticationRequirement, ConditionalAccessStatus +| top 20 by TimeGenerated desc +``` + +`ResultType` is a **string**: `"0"` is success; populated nonzero values are sign-in +error/result codes, not Function or provider HTTP statuses. Keep empty codes as unknown. +Review individual codes with the +[sign-in troubleshooting guidance](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-troubleshoot-sign-in-errors) +and the portal's Basic info and Authentication Details tabs. Do not label every nonzero code +as an incorrect OTP or a provider failure. + +`CreatedDateTime` is the sign-in initiation time (UTC); `TimeGenerated` is the log timestamp +used by these workspace queries; `ingestion_time()` estimates when the record reached the +workspace. They are not interchangeable. Updates/multiple MFA records and late arrival can +change counts. `CorrelationId` is client-influenced and is not guaranteed to be accurate or unique. + +Measure log-to-ingestion delay before choosing an alert buffer: + +```kusto +SigninLogs +| where TimeGenerated >= ago(24h) +| where AADTenantId =~ "" and AppId =~ "" +| extend IngestedAt = ingestion_time() +| extend LogToIngestMinutes = datetime_diff("second", IngestedAt, TimeGenerated) / 60.0 +| summarize StoredRows = count(), MissingIngestionTime = countif(isnull(IngestedAt)), + P95LogToIngestMinutes = percentile(LogToIngestMinutes, 95), + LatestIngestedAt = max(IngestedAt) +``` + +This measures the timestamps present in stored rows, not a delivery or authentication latency +SLA. Investigate missing or negative timing values and compare with sign-in initiation time; +do not assume the example ten-minute buffer covers every delay. + +### Inspect authentication steps safely + +`AuthenticationDetails` is documented as a **string** containing step details. Parse it before +expanding; the same pattern also accepts an already-dynamic array. Check coverage first: + +```kusto +SigninLogs +| where TimeGenerated >= ago(24h) +| where AADTenantId =~ "" and AppId =~ "" +| extend Steps = parse_json(tostring(AuthenticationDetails)) +| summarize StoredRows = count(), + RowsWithStepArray = countif(gettype(Steps) == "array"), + RowsWithoutStepArray = countif(gettype(Steps) != "array") +``` + +For rows with arrays, summarize the observed methods and nullable step outcomes: + +```kusto +SigninLogs +| where TimeGenerated >= ago(24h) +| where AADTenantId =~ "" and AppId =~ "" +| extend Steps = parse_json(tostring(AuthenticationDetails)) +| where gettype(Steps) == "array" +| mv-expand Step = Steps +| extend Method = tostring(Step.authenticationMethod), + Requirement = tostring(Step.authenticationStepRequirement), + StepSucceeded = tobool(Step.succeeded) +| summarize AuthenticationStepRows = count() by Method, Requirement, StepSucceeded +| order by AuthenticationStepRows desc +``` + +Missing/invalid JSON, empty arrays, and missing step properties do not establish success or +failure. Array expansion counts steps, not sign-ins. Confirm property names and population in +your actual records (the [authentication detail reference](https://learn.microsoft.com/en-us/graph/api/resources/authenticationdetail?view=graph-rest-beta) +describes the nested shape; this guide does not call the beta API). The +[sign-in activity details](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-in-log-activity-details) +explain that token claims can satisfy a step without a new challenge. Do not project +`authenticationMethodDetail` in a shared report: it can contain personal information. +Method/step success is neither provider attribution nor delivery confirmation. + +## 4. Establish the baseline + +Use at least a representative business cycle, including peaks, releases, and planned tests. +This seven-day exploration query is **not an alert query**: + +```kusto +SigninLogs +| where TimeGenerated >= ago(7d) +| where AADTenantId =~ "" and AppId =~ "" +| summarize StoredRows = count(), + Successful = countif(ResultType == "0"), + NonSuccess = countif(isnotempty(ResultType) and ResultType != "0"), + Unknown = countif(isempty(ResultType)) + by bin(TimeGenerated, 20m) +| extend NonSuccessPct = 100.0 * NonSuccess / StoredRows +| order by TimeGenerated asc +``` + +Empty buckets are no data, not a measured zero or 100% availability. Separate normal +interrupt/challenge codes from final failures during investigation; a broad non-success +baseline is useful for changes but not an authentication completion SLA. Review the result-code +distribution before adding any exclusions; document exclusions and monitor them separately. + +## 5. Create actionable log search alerts + +Use **scheduled log search alerts**, not Azure Activity Log alerts, for these queries. +Start with an **Analytics-plan** table; other table plans have different query/alert capabilities. +The following thresholds are illustrations, not recommended fraud limits or service commitments. +Tune them from the scoped baseline and begin with notification-only, low-severity rules. + +### A. Elevated non-success rate + +This returns one qualifying app row only when at least 50 stored rows, at least 20 non-success +rows, and at least 20% non-success occur in a **20-minute log-time window ending 10 minutes ago**: + +```kusto +SigninLogs +| where TimeGenerated >= ago(30m) and TimeGenerated < ago(10m) +| where AADTenantId =~ "" and AppId =~ "" +| summarize StoredRows = count(), + NonSuccess = countif(isnotempty(ResultType) and ResultType != "0"), + Unknown = countif(isempty(ResultType)) by AppId +| extend NonSuccessPct = 100.0 * NonSuccess / StoredRows +| where StoredRows >= 50 and NonSuccess >= 20 and NonSuccessPct >= 20.0 +| project AppId, StoredRows, NonSuccess, Unknown, NonSuccessPct +``` + +The buffer allows some ingestion delay; it does not guarantee complete data. Events delayed +beyond the lookback can be missed. Overlapping evaluations can observe the same event repeatedly. +Adjust both buffer and lookback together if measured delay requires it. + +### B. Unusual sign-in volume + +Using the same lagged window, return an app row at **200 or more stored rows**: + +```kusto +SigninLogs +| where TimeGenerated >= ago(30m) and TimeGenerated < ago(10m) +| where AADTenantId =~ "" and AppId =~ "" +| summarize StoredRows = count() by AppId +| where StoredRows >= 200 +``` + +A spike is a reason to investigate: campaigns, a release, retries, or a shared client can also +increase traffic. This is not an OTP-send, SMS-pumping, or provider-spend detector. + +### C. Potential abuse from a source IP + +For restricted security triage, find **30 or more non-success rows across approximately five +or more known user IDs** from one source IP in that same window: + +```kusto +SigninLogs +| where TimeGenerated >= ago(30m) and TimeGenerated < ago(10m) +| where AADTenantId =~ "" and AppId =~ "" +| where isnotempty(ResultType) and ResultType != "0" +| where isnotempty(IPAddress) and isnotempty(UserId) +| summarize NonSuccess = count(), + KnownUsersApprox = dcount(UserId) by AppId, IPAddress +| where NonSuccess >= 30 and KnownUsersApprox >= 5 +``` + +Only rows with known user IDs are counted here. This heuristic can miss unknown-user attacks +and distributed attacks; `dcount` is approximate. +NAT, VPNs, mobile networks, and shared proxies can produce false positives. IP geolocation is +not proof of a person's physical location. Restrict IP-bearing results and notifications to +the security team. Do not automate blocking, disable an account/provider, or change +authentication policy solely on this heuristic. + +Where workforce ID Protection is supported and licensed, separately review populated +`RiskLevelDuringSignIn`/`RiskLevelAggregated` and `RiskState` in the official risk reports. +Risk findings can arrive asynchronously. `RiskyUsers` and `UserRiskEvents` are separate export +categories, not automatically enabled by selecting `SignInLogs`. Do not reinterpret a volume +threshold as a Microsoft risk detection or a confirmed fraud report. + +### Configure the rule in the portal + +Follow the [log search alert rule reference](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule): + +1. In **Azure portal > Monitor > Alerts > Create > Alert rule**, select the **destination + Log Analytics workspace** as Scope, not the Function or customer app registration. +2. On **Condition**, choose **Custom log search**, paste one complete query above with real + scope values, and select **Run**. Review the results/preview, then continue editing the alert. +3. Explicitly set **Measure: Table rows**, **Aggregation type: Total**, and **Aggregation + granularity (window size): 30 minutes**. These queries already apply numeric thresholds + in KQL: a returned row means the condition qualifies. Set a **Static** threshold, + **Operator: Greater than**, **Threshold value: 0**, and **Frequency of evaluation: + 5 minutes**. Under Advanced options, set **Override query time range: 30 minutes**; + use a single violating evaluation to trigger. Do not count the one summary row as + 50 sign-ins or set the portal row threshold to 50/200. +4. Leave **Split by dimensions** unset initially. With one scoped app, this raises a + workspace-level incident if any row qualifies. Include app/scope and a restricted query + link in the runbook. Splitting by IP/user/correlation ID can create high-cardinality + alert instances, costs, and personal data in notifications. +5. On **Actions**, select or create an **action group** for the responsible operators + (a separate restricted group for security triage). Configure approved email/push or incident + routing and any required recipient verification. See + [action group configuration](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/action-groups). + Use the action group's **Test** facility and verify receipt; that tests + notification routing, not this query, ingestion, or a live sign-in. +6. On **Details**, choose the subscription/resource group, a recognizable rule name, + initial severity such as **Sev 3**, and a description containing tenant/app scope, + thresholds, owner, and runbook. Configure **Automatically resolve alerts** for a stateful + rule to limit repeated notifications while a condition persists; resolution is not immediate. +7. Choose an approved evaluation identity. A system-assigned managed identity starts with + no access: after creating the rule **disabled**, grant its identity log-reader access at + this workspace, allow propagation, then enable after validation. If using no managed + identity, permissions follow the last editor; review this dependency explicitly. +8. **Review + create** only after reviewing access and costs. Inspect rule health/query + errors and **Alerts** after enabling. A successful interactive query under your identity + does not establish access under the rule's identity. + +Rule creation requires read access to the target, write access to the rule's resource group, +and read access to the selected action group; creating that group or assigning roles needs +separate appropriate Azure permissions. Cross-tenant operators should create/manage the rule +in the subscription-owning workforce tenant with approved Azure RBAC, not assume the +external-tenant delegation grants every alert/role-assignment permission. + +### Monitor ingestion separately + +Failure/volume rules can appear quiet when collection is broken. For a scope that is expected +to have regular user sign-ins, this query returns a row if nothing has been ingested in an hour, +including when the selected scope has no rows in the last day: + +```kusto +SigninLogs +| where TimeGenerated >= ago(24h) +| where AADTenantId =~ "" and AppId =~ "" +| summarize LastIngested = max(ingestion_time()), StoredRows = count() +| where StoredRows == 0 or isnull(LastIngested) or LastIngested < ago(60m) +| project Monitor = "Sign-in feed needs investigation", LastIngested, StoredRows +``` + +Use a separate rule with **Table rows / Total > 0**, **30-minute granularity**, +**15-minute evaluation frequency**, and **Override query time range: 24 hours**. The one-hour +staleness threshold is in KQL. Do not shorten that override to the aggregation window. +Avoid one-minute frequency: `ingestion_time()` is not supported by that frequency's optimization. +An unresolved table/query or access failure is a rule-health problem, not a stale-data row. +No sign-ins during quiet hours and broken ingestion look alike; enable this only with a +documented traffic expectation and maintenance schedule. Null ingestion time is also +investigative, not proof of an outage. Compare with portal sign-ins, diagnostic settings, +workspace access, transformations, service health, and ingestion limits. + +### Validate without generating provider sends + +First validate scopes and counts against existing approved records; allow for ingestion delay. +Review healthy/empty windows as well as qualifying windows. For a temporary **nonproduction** +rule, select a known existing window **within the rule's query lookback** and lower the KQL +threshold so its existing rows qualify. If testing an older window, change the query's time +filter and portal query-time override together (log search alerts scan at most 48 hours); +keep the test action group restricted. Verify the scheduled evaluation, notification, +incident context, and later resolution, then restore/delete the temporary rule and restore +production thresholds. Do not leave a test override active. + +If there are no suitable records, use the organization's approved **non-phone** test sign-in +flow in a test tenant/app and record its UTC time/IDs. Do not induce repeated wrong OTPs, +change production policy, bypass Easy Auth, or send live OTPs to populate a chart. +An EPP evaluation can validate parts of Function telemetry but cannot validate provider +delivery or guarantee a `SigninLogs` row. No query here has been executed against a customer +tenant by this documentation; operators must confirm live schema, data, and rule behavior. + +## 6. Build a sign-in Workbook + +In **Azure portal > Monitor > Workbooks**, select **New**, enter **Edit** mode, and **Add query**. +Choose **Logs (Analytics)** as the data source and the verified destination workspace. +Add the baseline query as a time chart and separate result-code/step summaries as grids. +Label counts as stored sign-in/step rows and include collection freshness and unknown-code +coverage so an empty chart is not read as healthy. + +Save to an approved subscription/resource group, naming the monitored tenant/app scope. +If introducing workspace, tenant, app, or time-range parameters, bind them into every query +and test their effects; these examples have explicit literals/time filters, so a UI time +selector does not automatically change all query lookbacks. Keep IP/user-level investigation +views restricted. See [Workbook authoring](https://learn.microsoft.com/en-us/azure/azure-monitor/visualize/workbooks-create-workbook). + +The [Microsoft External ID workbook samples](https://github.com/microsoft/external-id-azure-monitor) +provide authentication, MFA, user-behavior, and risk-oriented starting points. Review their +source, deployment/access changes, queries, tenant feature requirements, and privacy before +importing any template; a sample named "risk detection" does not make ID Protection available +in an external tenant. This repository does not deploy those templates. A Workbook visualizes +data; it does not create the scheduled alert rules above. + +## 7. Triage, privacy, retention, and costs + +On an alert, the owner should confirm workspace/rule health, tenant/app scope, UTC window, +and result-code distribution first. Inspect the relevant sign-in's **Basic info**, +**Authentication Details**, and applicable policy results in the Entra admin center. +Separate user mistakes/interruptions and policy changes from infrastructure failures or +potential abuse; escalate suspected compromise to the organization's security response process. + +If phone delivery is implicated, follow the runtime-specific +[Function log discovery](MONITORING.md#runtime-specific-log-discovery). Compare timestamp, +verified request context, failure stage, and provider outcome with the provider's restricted +records. The sample logs sanitized envelope/header correlation identifiers, but +`SigninLogs.CorrelationId`, Function `OperationId`, request IDs, and provider references are +**not guaranteed equal**. Prove any association in an approved trace before using a join; +absence of a match is not proof that the Function/provider was never called. Fallback can +complete authentication through another path. Neither a sign-in success nor provider +acceptance establishes handset receipt. + +Logs can contain user IDs, names, IP addresses, locations, device information, and phone +identifiers. Use minimum necessary fields, scoped Azure RBAC/table access, restricted +Workbooks/action groups, and approved residency/retention. Do not export full records to public +issues or put tokens, OTPs, message bodies, or credentials in alerts. Diagnostic export +normally selects categories, **not app IDs**: query filters restrict analysis but do not +reduce all tenant-wide ingestion or establish an access boundary. + +Review [retention configuration](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/data-retention-configure) +and [log costs](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/cost-logs) separately +from Entra portal retention and provider billing. Confirm the effective table plan, analytics +retention, longer-term retention, ingestion/query volumes, alert frequency/dimensions, and +notification charges. Daily caps or transformations can remove the evidence an alert needs; +monitor those gaps rather than interpreting them as reduced abuse. App IDs and aggregate +counts are preferable to high-cardinality personal dimensions. + +Handover is complete only after the customer verifies export arrival, scoped queries, +rule-identity access, alert/action-group behavior, freshness checks, and named operational, +security, privacy, retention, and cost owners. Keep validation evidence privately. These +heuristics support human investigation; they do not authorize automated blocking or policy changes. From a948ae9ee163da90e46e58135d0a43570d0a259c Mon Sep 17 00:00:00 2001 From: Hou Chi Chan Date: Tue, 13 Oct 2026 12:06:29 -0700 Subject: [PATCH 2/8] docs: turn sign-in monitoring guide into linked portal steps Replace inline KQL and example thresholds with official query sources, illustrated portal references, detailed numbered customer steps and completion checks. Clarify query adaptation, alert measurement and MFA audit template scope. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f1451aca-6f84-41e6-9baf-cec42e36da6e --- docs/SIGN-IN-MONITORING.md | 926 ++++++++++++++++++++----------------- 1 file changed, 496 insertions(+), 430 deletions(-) diff --git a/docs/SIGN-IN-MONITORING.md b/docs/SIGN-IN-MONITORING.md index 24068f1..83fd7db 100644 --- a/docs/SIGN-IN-MONITORING.md +++ b/docs/SIGN-IN-MONITORING.md @@ -1,477 +1,543 @@ # Monitor Microsoft Entra sign-ins -Use Microsoft Entra sign-in logs to investigate authentication failures, understand traffic, -and notify operators about unusual activity. This is **tenant identity monitoring**, separate -from the [Function monitoring guide](MONITORING.md) and [Application Insights](APPLICATION-INSIGHTS.md). -Guided EPP setup does **not** export Entra logs or create the Workbooks, action groups, or alerts -described here. These instructions are customer configuration guidance, not a deployed monitor. - -Start by [choosing the tenant and permissions](#1-choose-the-tenant-and-permissions), then -[exporting logs](#2-export-the-required-log-categories), [checking actual records](#3-confirm-arrival-and-schema), -and [creating alerts](#5-create-actionable-log-search-alerts). A -[Workbook](#6-build-a-sign-in-workbook) provides a shared investigation view. +Follow these steps to export Microsoft Entra sign-in logs, inspect authentication outcomes, +and configure customer-owned notifications. This is **tenant identity monitoring**, separate +from [Function monitoring](MONITORING.md) and [Application Insights](APPLICATION-INSIGHTS.md). +EPP setup does **not** configure tenant log export, Workbooks, action groups, or sign-in alerts. +This guide does not deploy anything or change authentication policy. + +Use the linked Microsoft queries and illustrated portal instructions at the step where you +need them; no query snippets or fixed sample thresholds are duplicated here. Portal labels +can vary. The official screenshots show the controls, not resources or IDs to copy. + +1. Complete [tenant and access checks](#1-choose-the-tenant-and-permissions). +2. [Configure export](#2-export-the-required-log-categories) and + [confirm actual records](#3-confirm-arrival-and-schema). +3. [Choose a query and measure your baseline](#4-establish-the-baseline) before + [configuring notifications](#5-create-actionable-log-search-alerts). +4. [Create the investigation Workbook](#6-build-a-sign-in-workbook) and complete + [triage and handover checks](#7-triage-privacy-retention-and-costs). ## What these logs can and cannot tell you -Sign-in logs describe authentication to an application: result codes, authentication steps, -Conditional Access outcomes, and available identity/network context. They do **not** provide a -guaranteed CYOT/EPP provider identifier, delivery mode, provider billing total, or a reliable -count of SMS or voice sends. Do not infer provider usage from an authentication method named `SMS` or `Voice`, -or from `AuthenticationRequirement == "multiFactorAuthentication"`. - -A failed sign-in can mean an invalid password, an interrupted challenge, user cancellation, -a policy rejection, or another authentication failure. It does not by itself identify a phone -provider outage. A successful sign-in does not prove the EPP Function was called, which provider -was used, or that an OTP reached a recipient; an existing token claim can satisfy authentication. -Several records can describe one authentication sequence, including successive MFA outcomes. -The queries below count **stored log rows**, not unique customers, completed sessions, or sends. - -Use Function request/log telemetry for endpoint execution and provider acceptance; use the -provider's approved delivery reports and billing controls for delivery, send volume, and costs. -Evaluation and live EPP requests can both return HTTP 200. `SigninLogs` has no EPP `evaluation` -field, and an endpoint evaluation is not guaranteed to produce a user sign-in row. +1. Use sign-in logs to investigate authentication to an application: result codes, + authentication steps, available policy outcomes, and identity/network context. + Treat counts as **stored sign-in records**, not unique customers, completed sessions, + provider sends, or delivery receipts. Several records can describe one authentication + sequence, including successive MFA outcomes. +2. Do not attribute every failed sign-in to a phone provider. Invalid passwords, + interrupted challenges, user cancellation, and policy rejection can all produce + non-success results. A successful sign-in can use an existing token claim without a new + phone challenge. Neither an SMS/Voice method label nor an MFA requirement proves EPP use. +3. Use the [Function monitoring queries](MONITORING.md#2-single-region-function-queries) + for endpoint execution and the + [runtime-specific log discovery](MONITORING.md#runtime-specific-log-discovery) for + available request context and provider acceptance. Use the provider's approved delivery + and billing reports for recipient delivery, send volumes, and charges. +4. Keep evaluation and live evidence separate. Both EPP request modes can return HTTP 200. + `SigninLogs` has no guaranteed EPP delivery-mode, provider-attribution, phone-delivery, + or provider-cost field. An endpoint evaluation is not guaranteed to create a user + sign-in record. Do not interpret a sign-in chart as a delivery test. ## 1. Choose the tenant and permissions -Identify the tenant where the **user authentication** occurs, not merely the tenant/subscription -hosting the Function. Record its tenant ID, tenant type, intended customer-facing application's -client ID(s), destination workspace resource ID, and monitoring/security owners privately. -The application's `SigninLogs.AppId` is **not necessarily** the dedicated endpoint application's -`applicationId` in the EPP deployment summary. Confirm it against a real sign-in record. - -There are different setup paths: - -- **Workforce tenant**, including B2B guests: follow the - [global Entra-to-Azure Monitor integration](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-integrate-activity-logs-with-azure-monitor-logs). - Configure general diagnostic settings as at least **Security Administrator**, with an Azure - subscription, a Log Analytics workspace, and the necessary Azure permissions on the destination. -- **External tenant** for consumer/business-customer apps: follow - [Azure Monitor in external tenants](https://learn.microsoft.com/en-us/entra/external-id/customers/how-to-azure-monitor). - An external tenant cannot have an associated Azure subscription. Its setup wizard authenticates - the subscription in a **workforce tenant** and configures the Azure Lighthouse access path. - The documented prerequisites include Azure RBAC **Owner** on that subscription and - **Security Administrator or Application Administrator** in the external tenant. - Users selected to configure diagnostic settings still need at least **Security Administrator**. - Review the wizard's delegation, selected users/groups, workspace, region, and costs before - approving it; do not move the EPP subscription or change tenant/policy settings to imitate - the workforce instructions. - -Entra roles and Azure RBAC are separate. **Reports Reader** is the least privileged Entra role -for reading activity logs in the admin center; it does not grant workspace access. Grant -investigators appropriately scoped log-query access, such as **Log Analytics Reader**, using -[workspace/table access controls](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/manage-access). -Saving or sharing a Workbook does not grant access to its underlying logs. - -Current [monitoring licensing guidance](https://learn.microsoft.com/en-us/entra/fundamentals/licensing#microsoft-entra-monitoring-and-health) -lists sign-in and audit logs for Entra ID Free as well as P1/P2. Do not confuse that with -premium report, Graph API, risk, or Workbook-template entitlements; confirm requirements for -each feature and tenant type before purchasing or enabling it. Azure ingestion, retention, -querying, alert evaluation, and notifications can incur separate charges. - -**Risk is optional and tenant-dependent.** The current -[external-tenant feature comparison](https://learn.microsoft.com/en-us/entra/external-id/customers/concept-supported-features-customers) -lists **Microsoft Entra ID Protection as unavailable in external tenants**. Do not apply -workforce P2 risk-detection promises to that tenant. In supported workforce tenants, full -[ID Protection](https://learn.microsoft.com/en-us/entra/id-protection/overview-identity-protection) -risk capabilities require P2 (or an applicable entitlement). The `SigninLogs` schema documents -`RiskLevelDuringSignIn`, `RiskLevelAggregated`, `RiskState`, and `RiskDetail`, but some values are -`hidden` without the required entitlement. Empty, `none`, or `hidden` is not a clearance of fraud. -Check current product availability and actual records before using risk fields. +1. Identify the tenant where **user authentication** takes place. In the + [Microsoft Entra admin center](https://entra.microsoft.com), use **Settings > + Directories + subscriptions** to select it, then open its **Overview** and record the + **Tenant ID** privately. Do not assume this is the Function-hosting tenant. +2. Confirm whether this is a **workforce tenant**, including B2B guests, or an **external + tenant** for consumer/business-customer apps. Use the + [tenant feature comparison](https://learn.microsoft.com/en-us/entra/external-id/customers/concept-supported-features-customers) + with your tenant administrator. The export setup and feature availability differ. +3. Open **Entra ID > Monitoring & health > Sign-in logs** and select an existing, + approved sign-in for the application you intend to monitor. In **Basic info**, check + **Application**, **Application ID**, **Resource**, the outcome, and time. The + [illustrated activity-details guide](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-in-log-activity-details#basic-info) + explains these fields. Record the application's **client ID**, not its Object ID. + It is not necessarily the endpoint `applicationId` in the EPP deployment summary. + Record the displayed time zone and convert investigation times to UTC when comparing sources. +4. Choose the destination **subscription, resource group, workspace, and region** with + the Azure operator and privacy/cost owners. Check for an existing approved destination + before requesting another one. Keeping Entra logs with Function telemetry is an + operator decision, not an automatic consequence of guided EPP setup. +5. For a **workforce tenant**, check the + [integration prerequisites](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-integrate-activity-logs-with-azure-monitor-logs#prerequisites). + General diagnostic settings require at least **Security Administrator** in the Entra + tenant, an Azure subscription, a prepared Log Analytics workspace, and appropriate + Azure access to the destination. If no workspace is approved yet, have the Azure operator + follow the [workspace creation instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/quick-create-workspace). +6. For an **external tenant**, open the + [illustrated external-tenant setup guide](https://learn.microsoft.com/en-us/entra/external-id/customers/how-to-azure-monitor#prerequisites). + An external tenant cannot have an associated Azure subscription. The documented setup + uses the subscription in a **workforce tenant** and an Azure Lighthouse access path. + Arrange Azure RBAC **Owner** on that subscription and **Security Administrator or + Application Administrator** in the external tenant for the wizard. Users who configure + diagnostic settings still need at least **Security Administrator**. Do not move the + EPP subscription or change policy to imitate workforce setup. +7. Arrange read access separately. **Reports Reader** is the least privileged Entra role + for activity-log access in the admin center; see + [access requirements](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-access-activity-logs#prerequisites). + It does not grant Azure log access. Have the access owner review + [workspace/table permissions](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/manage-access) + and grant appropriately scoped query access, such as **Log Analytics Reader**. + Confirm the investigator can open the chosen workspace's **Logs** without an access error. +8. Verify licensing before selecting premium reports. Current + [monitoring licensing guidance](https://learn.microsoft.com/en-us/entra/fundamentals/licensing#microsoft-entra-monitoring-and-health) + lists sign-in and audit logs for Entra ID Free as well as P1/P2. That does not imply + entitlement to every Graph API, risk report, or Workbook feature. Azure collection, + retention, queries, alert evaluation, and notifications can incur separate charges. +9. Confirm whether risk reporting is actually available. The current + [external-tenant comparison](https://learn.microsoft.com/en-us/entra/external-id/customers/concept-supported-features-customers#general-feature-comparison) + lists **Microsoft Entra ID Protection as unavailable in external tenants**. In supported + workforce tenants, full [ID Protection capabilities](https://learn.microsoft.com/en-us/entra/id-protection/overview-identity-protection#license-requirements) + require P2 or an applicable entitlement. Do not purchase workforce P2 expecting it to + enable external-tenant risk detections, or read empty/hidden risk values as fraud clearance. +10. Confirm this step is complete: the private inventory identifies the **source tenant + and type, customer app client ID, destination workspace resource ID, access owners, + query operator, alert operator, and security responder**. Stop before export if the + scope, destination approval, or required access is unresolved. ## 2. Export the required log categories -For a workforce tenant, or after completing the external-tenant monitoring wizard: - -1. In the **Microsoft Entra admin center**, switch to the tenant being monitored. -2. Open **Entra ID > Monitoring & health > Diagnostic settings**. Review existing settings - first to avoid unintended duplicate destinations or changing someone else's integration. -3. Select **Add diagnostic setting** (or deliberately edit the approved setting) and name it. -4. Select the **SignInLogs** category for interactive user sign-ins. Add **AuditLogs** if you - also need directory-change investigations. Select only additional categories justified by - your operational needs and available in this tenant. +### Prepare the external-tenant access path + +1. If monitoring a **workforce tenant**, skip this subsection. If an external tenant is + already integrated, review its existing destination/access with the owner rather than + rerunning setup. Otherwise, open **Entra ID > Monitoring & health > Diagnostic settings** + in the external tenant and select **Start set up**. +2. Follow the official + [wizard screenshots and instructions](https://learn.microsoft.com/en-us/entra/external-id/customers/how-to-azure-monitor#set-up-the-azure-lighthouse-configuration-in-the-wizard). + Sign in to the **workforce tenant** for the approved subscription. Select the subscription + and resource group, specify the workspace name and region, and select **Next**. +3. In **Select user access**, choose only approved external-tenant users/groups and their + documented Azure roles. Review the delegation and permissions with the access owner. + The wizard's roles are not a grant of all alert-management or role-assignment permissions. +4. At **Review and create**, confirm destination, region, users/groups, roles, and charges. + Select **Create** only after approval. Wait for confirmation, select **Done**, and + proceed to diagnostic settings. Retain the destination identifiers privately. + +### Select and save the export + +1. In the **source tenant's** Entra admin center, open **Entra ID > Monitoring & health > + Diagnostic settings**. For the matching illustrated screen, use + [access diagnostic settings](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-configure-diagnostic-settings#how-to-access-diagnostic-settings). + Review existing settings and their owners before adding or editing an integration. +2. Select **Add diagnostic setting**, or deliberately edit the owner-approved setting. + Enter a recognizable name for a new setting. Select **SignInLogs** for interactive + user authentication. Add **AuditLogs** only if directory-change investigation is also + required; audit events are not sign-in outcomes. +3. Use the [category descriptions](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-diagnostic-settings-logs-options) + to choose any further sources. Non-interactive user, service-principal, and managed-identity + sign-ins are separate categories and populations. They use `AADNonInteractiveUserSignInLogs`, + `AADServicePrincipalSignInLogs`, and `AADManagedIdentitySignInLogs`, respectively. + Keep their baselines separate from interactive `SigninLogs`. Do not select every category + just to make a chart populate. +4. Check the category picker in **your tenant**. A category description or workforce feature + is not a promise of data in an external tenant. Selecting **SignInLogs** does not enable + the separate **RiskyUsers** or **UserRiskEvents** categories. Provider-side OAuth evidence + can reside in the provider's tenant and require its administrator's assistance. 5. Under **Destination details**, select **Send to Log Analytics workspace**, then choose - the approved subscription/workspace. In an external tenant, use the workspace/access path - established by the external-tenant instructions. -6. Select **Save**, then read back the categories and destination. Record the owner and date. - -The [streaming category reference](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-diagnostic-settings-logs-options) -distinguishes these sources; category labels and workspace table names are not identical: - -| Selected log category | Workspace table | Intended use | -| --- | --- | --- | -| SignInLogs | [SigninLogs](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/signinlogs) | Interactive user authentication; primary source for the examples below. | -| Non-interactive user sign-ins | [AADNonInteractiveUserSignInLogs](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/aadnoninteractiveusersigninlogs) | Token/client activity on behalf of users; keep its baseline separate. | -| Service principal sign-ins | [AADServicePrincipalSignInLogs](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/aadserviceprincipalsigninlogs) | Application/workload authentication, not end-user OTP outcomes. | -| Managed identity sign-ins | [AADManagedIdentitySignInLogs](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/aadmanagedidentitysigninlogs) | Managed identity authentication, not end-user OTP outcomes. | -| AuditLogs | [AuditLogs](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/auditlogs) | Directory changes; not a replacement for sign-in outcomes. | - -The external-tenant [Microsoft samples](https://github.com/microsoft/external-id-azure-monitor) -also query `SigninLogs` for authentication reporting. That is not a guarantee every workforce -category, premium report, or populated field exists in an external tenant. Check the category -picker and the workspace's actual tables; do not union unavailable tables or substitute -`AuditLogs` for a missing `SigninLogs` feed. Provider-side OAuth logs may be in the provider's -tenant and require its administrator's assistance. - -The Function's diagnostic setting is a **different setting on a different resource**. -Creating Application Insights or enabling Function logs does not export Entra activity. -Export is not a backfill of all historical portal logs. + the approved **Subscription** and **Log Analytics workspace**. For an external tenant, + use the access path established above. Compare the selection with your private inventory. + The [illustrated export instructions](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-integrate-activity-logs-with-azure-monitor-logs#send-logs-to-azure-monitor) + show the category and destination controls. +6. Select **Save**, reopen the setting, and confirm its **selected categories and destination**. + Record the export start time and configuration owner. This setting belongs to Entra, + not the Function App; Function diagnostic settings/Application Insights do not perform + this export. Do not expect a backfill of all historical portal sign-ins. +7. Confirm this step is complete: the saved setting points to the intended workspace + and includes the intended sign-in category, with no unintended changes to another + integration. Continue to record verification rather than assuming that Save proves arrival. ## 3. Confirm arrival and schema -Open **Azure portal > Log Analytics workspaces > your destination > Logs**, then use **KQL mode**. -Choose an appropriate time range and confirm `SigninLogs` in the table browser. Do not run -these examples from the Application Insights application-table context (`requests`, `traces`). - -Initial arrival is not immediate: Microsoft's external-tenant samples describe about 45 minutes, -while the [general diagnostic-setting guidance](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-configure-diagnostic-settings) -allows up to three days for initial logs. These are setup allowances, not a steady-state latency -SLA. After initial arrival, measure normal delays before enabling paging alerts. - -Run these two queries separately: - -```kusto -SigninLogs -| getschema -``` - -```kusto -SigninLogs -| where TimeGenerated >= ago(24h) -| summarize StoredRows = count(), LatestLogTime = max(TimeGenerated) - by AADTenantId, AppId, AppDisplayName, IsInteractive, Category -| order by LatestLogTime desc -``` - -If the table is unresolved, fix collection/destination/access first; do not mask it with an -empty fallback. If it exists but returns no rows, compare the correct tenant's **Monitoring -& health > Sign-in logs** with the workspace, export start time, selected category, time range, -and expected application traffic. An empty result is not evidence that authentication is healthy. -Inspect any collection transformations that could remove needed rows or columns. - -The remaining queries require the verified -[SigninLogs schema](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/signinlogs). -Replace `` with the observed `AADTenantId` and `` -with the observed application's **client ID**, not an Object ID, display name, or provider API ID. -Use one app per initial alert rule; add further app IDs only after validating each scope. -`AADTenantId` identifies the source directory; do not substitute the workspace's tenant. - -Inspect a bounded set of records without returning user names, phone/sign-in identifiers, -IP addresses, or the entire authentication details payload: - -```kusto -SigninLogs -| where TimeGenerated >= ago(24h) -| where AADTenantId =~ "" and AppId =~ "" -| project TimeGenerated, CreatedDateTime, Id, CorrelationId, ResultType, - AuthenticationRequirement, ConditionalAccessStatus -| top 20 by TimeGenerated desc -``` - -`ResultType` is a **string**: `"0"` is success; populated nonzero values are sign-in -error/result codes, not Function or provider HTTP statuses. Keep empty codes as unknown. -Review individual codes with the -[sign-in troubleshooting guidance](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-troubleshoot-sign-in-errors) -and the portal's Basic info and Authentication Details tabs. Do not label every nonzero code -as an incorrect OTP or a provider failure. - -`CreatedDateTime` is the sign-in initiation time (UTC); `TimeGenerated` is the log timestamp -used by these workspace queries; `ingestion_time()` estimates when the record reached the -workspace. They are not interchangeable. Updates/multiple MFA records and late arrival can -change counts. `CorrelationId` is client-influenced and is not guaranteed to be accurate or unique. - -Measure log-to-ingestion delay before choosing an alert buffer: - -```kusto -SigninLogs -| where TimeGenerated >= ago(24h) -| where AADTenantId =~ "" and AppId =~ "" -| extend IngestedAt = ingestion_time() -| extend LogToIngestMinutes = datetime_diff("second", IngestedAt, TimeGenerated) / 60.0 -| summarize StoredRows = count(), MissingIngestionTime = countif(isnull(IngestedAt)), - P95LogToIngestMinutes = percentile(LogToIngestMinutes, 95), - LatestIngestedAt = max(IngestedAt) -``` - -This measures the timestamps present in stored rows, not a delivery or authentication latency -SLA. Investigate missing or negative timing values and compare with sign-in initiation time; -do not assume the example ten-minute buffer covers every delay. +1. Open **Azure portal > Log Analytics workspaces > the recorded destination > Logs**. + For an external tenant's workforce-hosted workspace, switch to the subscription-owning + directory as necessary. Check the workspace name/query scope before running anything. + Use the [illustrated Logs scope tutorial](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#open-log-analytics). + Its demo environment is for learning controls, **not** verification of your tenant's data. +2. Select **Tables** in the left pane and find **SigninLogs**. Expand the table to inspect + its columns and types, following + [View table information](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#view-table-information). + That tutorial illustrates `AppRequests`; select **SigninLogs** in your workspace instead. + Compare the actual columns with the official + [SigninLogs schema](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/signinlogs#columns). +3. In the table's controls, use **Run** to preview records, or select it through + [Simple mode > Select a table](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-simple-mode#get-started-in-simple-mode). + Choose a **Time range** that covers activity after export was saved. Limit the displayed + records and inspect them only within the approved access boundary; a preview can contain + personal data. Do not use the Application Insights `requests`/`traces` context for Entra logs. +4. Allow for initial export delay. The + [Microsoft External ID monitoring repository](https://github.com/microsoft/external-id-azure-monitor) + describes about 45 minutes after setup, while the + [general diagnostic-setting guidance](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-configure-diagnostic-settings#basic-process) + allows up to three days for initial arrival. These are setup allowances, not a steady-state + latency SLA. If no table/records appear, compare export start time, source tenant, destination, + category, access, and expected portal sign-ins before escalating. +5. Expand a returned row using its **chevron**, as shown in + [Expand and sort records](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#expand-and-sort-records). + Check `AADTenantId` and `AppId` against the source tenant and application's client ID. + Do not substitute the app's Object ID, provider API ID, or workspace ID. + The standard `TenantId` column is the **workspace ID**, not the source Entra tenant ID. +6. To narrow exploration without writing a new query, use **Simple mode > Add > column filter** + for `AADTenantId` and `AppId`, then enter/select your verified IDs. See the illustrated + [column-filter instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-simple-mode#filter-by-column). + Apply source/app filters **before aggregation**. Switch to **KQL mode** and confirm the + generated query contains them; a Results-grid search or column-header filter is not an + enduring query/alert filter. +7. Check `ResultType`, `ResultDescription`, `CreatedDateTime`, and `TimeGenerated`. + The schema defines `ResultType` as a **string**: zero indicates success, populated nonzero + values are sign-in error/result codes, and missing/empty values need investigation. + These are not provider/Function HTTP statuses. Review the corresponding portal record's + **Basic info** with the + [sign-in error troubleshooting instructions](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-troubleshoot-sign-in-errors). +8. Check time semantics before selecting alert windows. `CreatedDateTime` is sign-in + initiation time in UTC; `TimeGenerated` is the log timestamp used for workspace time filters. + Have the query operator use the existing + [ingestion-latency reference](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/data-ingestion-time) + and [standard-column timing guidance](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-standard-columns#_timereceived-column) + to measure arrival delay against **SigninLogs**, with your tenant/app scope. Those references + are generic, not a ready-made Entra latency monitor. Record the measured delay and any + missing timestamps; do not confuse ingestion time with authentication or delivery latency. +9. Confirm this step is complete: actual records identify the intended source tenant/app, + their fields/types match the reference, and the operator knows their time range and arrival + delay. An unresolved table is a collection/access problem, not a healthy empty result. + If a table exists but the scope is empty, compare with **Entra > Sign-in logs**, inspect + collection transformations and ingestion limits with the owner, and resolve the gap first. ### Inspect authentication steps safely -`AuthenticationDetails` is documented as a **string** containing step details. Parse it before -expanding; the same pattern also accepts an already-dynamic array. Check coverage first: - -```kusto -SigninLogs -| where TimeGenerated >= ago(24h) -| where AADTenantId =~ "" and AppId =~ "" -| extend Steps = parse_json(tostring(AuthenticationDetails)) -| summarize StoredRows = count(), - RowsWithStepArray = countif(gettype(Steps) == "array"), - RowsWithoutStepArray = countif(gettype(Steps) != "array") -``` - -For rows with arrays, summarize the observed methods and nullable step outcomes: - -```kusto -SigninLogs -| where TimeGenerated >= ago(24h) -| where AADTenantId =~ "" and AppId =~ "" -| extend Steps = parse_json(tostring(AuthenticationDetails)) -| where gettype(Steps) == "array" -| mv-expand Step = Steps -| extend Method = tostring(Step.authenticationMethod), - Requirement = tostring(Step.authenticationStepRequirement), - StepSucceeded = tobool(Step.succeeded) -| summarize AuthenticationStepRows = count() by Method, Requirement, StepSucceeded -| order by AuthenticationStepRows desc -``` - -Missing/invalid JSON, empty arrays, and missing step properties do not establish success or -failure. Array expansion counts steps, not sign-ins. Confirm property names and population in -your actual records (the [authentication detail reference](https://learn.microsoft.com/en-us/graph/api/resources/authenticationdetail?view=graph-rest-beta) -describes the nested shape; this guide does not call the beta API). The -[sign-in activity details](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-in-log-activity-details) -explain that token claims can satisfy a step without a new challenge. Do not project -`authenticationMethodDetail` in a shared report: it can contain personal information. -Method/step success is neither provider attribution nor delivery confirmation. +1. For an existing relevant sign-in, open **Entra ID > Monitoring & health > Sign-in logs > + selected record > Authentication Details**. Use the official + [Authentication Details screenshot and explanation](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-in-log-activity-details#authentication-details) + to read the step sequence, method, outcome, and policy context. +2. Check whether the step was satisfied by an existing token claim or a previous + authentication. A method named SMS/Voice is not a provider ID or delivery receipt. + Keep the sign-in's overall outcome separate from an individual step's outcome. +3. For an existing shared method report, review the official + [MFA Workbook template](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/mfaWorkbookDeployment.json) + with the query operator. Its current queries use **AuditLogs**, not `SigninLogs` + authentication-step arrays. They need the corresponding export and recorded audit activity; + do not replace the table name or treat that report as the full sign-in step sequence. + For a `SigninLogs` step report, have the operator review the actual `AuthenticationDetails` + column separately: it is documented as a string containing step data, not a top-level + dynamic object. An adapted query must handle the parsed array shape, empty/invalid/missing + data, and nullable step outcomes explicitly. +4. Check the adapted report for coverage gaps and labels. Expanding an array counts + **authentication steps**, not sign-ins. Missing steps do not establish success or failure. + Keep `authenticationMethodDetail` and full raw payloads out of shared reports; they can + include phone identifiers or other personal data. +5. Confirm this check is complete only after a report's displayed methods/outcomes agree + with selected portal records, without claiming provider attribution or recipient delivery. ## 4. Establish the baseline -Use at least a representative business cycle, including peaks, releases, and planned tests. -This seven-day exploration query is **not an alert query**: - -```kusto -SigninLogs -| where TimeGenerated >= ago(7d) -| where AADTenantId =~ "" and AppId =~ "" -| summarize StoredRows = count(), - Successful = countif(ResultType == "0"), - NonSuccess = countif(isnotempty(ResultType) and ResultType != "0"), - Unknown = countif(isempty(ResultType)) - by bin(TimeGenerated, 20m) -| extend NonSuccessPct = 100.0 * NonSuccess / StoredRows -| order by TimeGenerated asc -``` - -Empty buckets are no data, not a measured zero or 100% availability. Separate normal -interrupt/challenge codes from final failures during investigation; a broad non-success -baseline is useful for changes but not an authentication completion SLA. Review the result-code -distribution before adding any exclusions; document exclusions and monitor them separately. +1. Open the official [SigninLogs query collection](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/queries/signinlogs). + Choose the relevant named query rather than copying an unrelated tutorial's table: + **Failed Signin reasons** for result-code distribution, **Failed login Count** for + failure counts by resource, or **Signin Locations** for successful/failed counts by location. + The customer-facing app, source tenant, time window, and thresholds are **not preconfigured** + for your deployment in these examples. +2. In your workspace's **Logs**, switch to **KQL mode**. Copy the selected query from its + official source into the editor. Alternatively, use the **Queries** pane if that query + is available there. Add your verified `AADTenantId`/`AppId` scope **before summarizing**, + following the [filtering tutorial](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#apply-multiple-query-filters). + Have the query operator review edits if unfamiliar with KQL; do not run tenant-wide + results as if they describe one customer app. +3. Compare the query with the **actual string type of `ResultType`**. The official collection + includes examples with numeric-looking comparisons; the operator must ensure the chosen + comparison matches the documented type and separately handles empty/missing codes. + Read nonzero result codes in their authentication context, not as incorrect OTPs by default. + The catalog also includes user names/identifiers in some outputs and a **Failed MFA challenge** + query limited to one code. Review purpose and privacy: it is not a complete MFA/CYOT failure + detector. Remove unnecessary personal fields before sharing a saved report. +4. Choose a representative business cycle using **Time range** and any query time filter. + Include peak/quiet hours, releases, and approved tests. Use the illustrated + [time-range controls](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#set-the-query-time-range). + Confirm the effective range on rerun, not just the picker label. +5. Select **Run**. Inspect **Results** and, where helpful, **Chart**. Identify the output's + numeric count column and grouping; do not confuse the number of summary rows displayed + with the number of sign-in records counted. The **Show** limit can cap displayed results. + Avoid treating a truncated preview or browser-side grouping as a complete baseline. +6. Record privately the chosen source query, scoped saved version, output column/grouping, + usual volumes, non-success codes, unknown-data coverage, peak conditions, and observed + ingestion delay. Distinct-user, record-count, and authentication-step measures are different; + several log records can belong to one authentication sequence. +7. Agree with the response owner which change should notify someone and what they will + investigate. Choose thresholds from the measured baseline, with appropriate minimum + traffic for rate rules and quiet-hour/maintenance expectations. **No universal threshold + or prebuilt fraud verdict is supplied here.** Do not assume the official count queries + calculate a failure percentage, detect source-IP abuse, or implement a freshness check. +8. Select **Save > Save as query**, following + [saving Azure Monitor queries](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/save-query). + Enter the name and select the approved subscription/query pack; review the proposed default + pack rather than silently creating a new resource. The documented save permission is + **Log Analytics Contributor**; an authorized saver may need to perform this step for a + read-only investigator. Record its approved location and who can read it. + Confirm a second authorized operator + can reopen it and obtain the same scope and output shape before using it in a rule. ## 5. Create actionable log search alerts -Use **scheduled log search alerts**, not Azure Activity Log alerts, for these queries. -Start with an **Analytics-plan** table; other table plans have different query/alert capabilities. -The following thresholds are illustrations, not recommended fraud limits or service commitments. -Tune them from the scoped baseline and begin with notification-only, low-severity rules. - ### A. Elevated non-success rate -This returns one qualifying app row only when at least 50 stored rows, at least 20 non-success -rows, and at least 20% non-success occur in a **20-minute log-time window ending 10 minutes ago**: - -```kusto -SigninLogs -| where TimeGenerated >= ago(30m) and TimeGenerated < ago(10m) -| where AADTenantId =~ "" and AppId =~ "" -| summarize StoredRows = count(), - NonSuccess = countif(isnotempty(ResultType) and ResultType != "0"), - Unknown = countif(isempty(ResultType)) by AppId -| extend NonSuccessPct = 100.0 * NonSuccess / StoredRows -| where StoredRows >= 50 and NonSuccess >= 20 and NonSuccessPct >= 20.0 -| project AppId, StoredRows, NonSuccess, Unknown, NonSuccessPct -``` - -The buffer allows some ingestion delay; it does not guarantee complete data. Events delayed -beyond the lookback can be missed. Overlapping evaluations can observe the same event repeatedly. -Adjust both buffer and lookback together if measured delay requires it. +1. Begin with [Failed Signin reasons](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/queries/signinlogs#failed-signin-reasons) + to review **which result codes changed**. Use a reviewed failure-count rule first if that + meets the requirement; this official query is not a complete failure-rate alert. +2. If a **rate** rule is needed, have the query operator adapt a saved query to return + failures and the corresponding total for the **same tenant, app, population, and window**, + with agreed handling of unknown codes and minimum traffic. Review healthy/empty windows + and denominator coverage before choosing the alert's numeric percentage column. +3. Document exclusions and monitor them separately. Non-success results can include + interruptions, cancellation, and policy rejection. Assign authentication-support triage, + not automatic phone-provider outage classification. ### B. Unusual sign-in volume -Using the same lagged window, return an app row at **200 or more stored rows**: - -```kusto -SigninLogs -| where TimeGenerated >= ago(30m) and TimeGenerated < ago(10m) -| where AADTenantId =~ "" and AppId =~ "" -| summarize StoredRows = count() by AppId -| where StoredRows >= 200 -``` - -A spike is a reason to investigate: campaigns, a release, retries, or a shared client can also -increase traffic. This is not an OTP-send, SMS-pumping, or provider-spend detector. +1. Review the [authentication Workbook template](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/authenticationsWorkbookDeployment.json) + for existing sign-in traffic visualizations and query definitions. Treat it as source to + review, **not** an instruction to deploy the entire template. +2. Have the query operator select/adapt the relevant traffic query and verify the output is + a record count for the intended `SigninLogs` tenant/app/time window. The official + **User count per Application** query counts distinct users, not total sign-in records; + do not substitute that measure without changing the monitoring objective. +3. Set a volume limit from the agreed baseline and routing capacity. Investigate campaigns, + releases, clients, retries, and collection changes as possible causes. Sign-in volume is + **not OTP-send volume, SMS-pumping evidence, or provider spend**. ### C. Potential abuse from a source IP -For restricted security triage, find **30 or more non-success rows across approximately five -or more known user IDs** from one source IP in that same window: - -```kusto -SigninLogs -| where TimeGenerated >= ago(30m) and TimeGenerated < ago(10m) -| where AADTenantId =~ "" and AppId =~ "" -| where isnotempty(ResultType) and ResultType != "0" -| where isnotempty(IPAddress) and isnotempty(UserId) -| summarize NonSuccess = count(), - KnownUsersApprox = dcount(UserId) by AppId, IPAddress -| where NonSuccess >= 30 and KnownUsersApprox >= 5 -``` - -Only rows with known user IDs are counted here. This heuristic can miss unknown-user attacks -and distributed attacks; `dcount` is approximate. -NAT, VPNs, mobile networks, and shared proxies can produce false positives. IP geolocation is -not proof of a person's physical location. Restrict IP-bearing results and notifications to -the security team. Do not automate blocking, disable an account/provider, or change -authentication policy solely on this heuristic. - -Where workforce ID Protection is supported and licensed, separately review populated -`RiskLevelDuringSignIn`/`RiskLevelAggregated` and `RiskState` in the official risk reports. -Risk findings can arrive asynchronously. `RiskyUsers` and `UserRiskEvents` are separate export -categories, not automatically enabled by selecting `SignInLogs`. Do not reinterpret a volume -threshold as a Microsoft risk detection or a confirmed fraud report. +1. Use [Signin Locations](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/queries/signinlogs#signin-locations) + and the [user-behavior Workbook template](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/userBehaviourWorkbookDeployment.json) + as investigation starting points. Neither is a ready-made source-IP fraud alert for EPP. +2. If a restricted IP-based rule is justified, have the security/query owner review actual + `IPAddress`, `UserId`, and `ResultType` population and design the grouped query/threshold + for the approved tenant/app. Check unknown users, absent IPs, approximate distinct counts, + distributed attempts, and expected shared-network activity before publishing it. +3. Restrict IP-bearing results and notifications to the security team. NAT, VPNs, mobile + networks, and proxies can cause false positives; IP geolocation does not prove a person's + location. Do not automate blocking, disable a provider/account, or change authentication + policy solely on a volume/IP heuristic. +4. Where licensed workforce ID Protection is supported, use its + [risk investigation instructions](https://learn.microsoft.com/en-us/entra/id-protection/howto-identity-protection-investigate-risk) + with the security owner. Check actual `RiskLevelDuringSignIn`, `RiskLevelAggregated`, + `RiskState`, and `RiskDetail` where available. Findings can arrive asynchronously; + empty, none, or hidden values do not clear fraud. Do not promise these detections + in an external tenant because a template is named "risk detection." ### Configure the rule in the portal -Follow the [log search alert rule reference](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule): - -1. In **Azure portal > Monitor > Alerts > Create > Alert rule**, select the **destination - Log Analytics workspace** as Scope, not the Function or customer app registration. -2. On **Condition**, choose **Custom log search**, paste one complete query above with real - scope values, and select **Run**. Review the results/preview, then continue editing the alert. -3. Explicitly set **Measure: Table rows**, **Aggregation type: Total**, and **Aggregation - granularity (window size): 30 minutes**. These queries already apply numeric thresholds - in KQL: a returned row means the condition qualifies. Set a **Static** threshold, - **Operator: Greater than**, **Threshold value: 0**, and **Frequency of evaluation: - 5 minutes**. Under Advanced options, set **Override query time range: 30 minutes**; - use a single violating evaluation to trigger. Do not count the one summary row as - 50 sign-ins or set the portal row threshold to 50/200. -4. Leave **Split by dimensions** unset initially. With one scoped app, this raises a - workspace-level incident if any row qualifies. Include app/scope and a restricted query - link in the runbook. Splitting by IP/user/correlation ID can create high-cardinality - alert instances, costs, and personal data in notifications. -5. On **Actions**, select or create an **action group** for the responsible operators - (a separate restricted group for security triage). Configure approved email/push or incident - routing and any required recipient verification. See - [action group configuration](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/action-groups). - Use the action group's **Test** facility and verify receipt; that tests - notification routing, not this query, ingestion, or a live sign-in. -6. On **Details**, choose the subscription/resource group, a recognizable rule name, - initial severity such as **Sev 3**, and a description containing tenant/app scope, - thresholds, owner, and runbook. Configure **Automatically resolve alerts** for a stateful - rule to limit repeated notifications while a condition persists; resolution is not immediate. -7. Choose an approved evaluation identity. A system-assigned managed identity starts with - no access: after creating the rule **disabled**, grant its identity log-reader access at - this workspace, allow propagation, then enable after validation. If using no managed - identity, permissions follow the last editor; review this dependency explicitly. -8. **Review + create** only after reviewing access and costs. Inspect rule health/query - errors and **Alerts** after enabling. A successful interactive query under your identity - does not establish access under the rule's identity. - -Rule creation requires read access to the target, write access to the rule's resource group, -and read access to the selected action group; creating that group or assigning roles needs -separate appropriate Azure permissions. Cross-tenant operators should create/manage the rule -in the subscription-owning workforce tenant with approved Azure RBAC, not assume the -external-tenant delegation grants every alert/role-assignment permission. +1. Have the alert operator confirm **read access to the workspace**, **write access to + the rule's resource group**, and **read access to the action group**, using the + [official alert prerequisites](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#prerequisites). + Creating an action group or assigning roles needs separate permissions. + External-tenant operators must use approved Azure RBAC in the subscription-owning + workforce tenant; Entra roles or Lighthouse delegation alone do not grant every operation. +2. Open **Azure portal > Monitor > Alerts > Create > Alert rule**. On **Scope**, choose + the verified **Log Analytics workspace** and select **Apply**, not the Function App or + app registration. Compare with the + [illustrated scope screen](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#configure-the-scope-of-the-alert-rule). +3. On **Condition**, select **Custom log search**. Paste the approved **scoped saved query** + selected above. Select **Run**, inspect **Preview**, then **Continue Editing Alert**. + Use the [illustrated condition/measurement instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#configure-alert-rule-conditions). + Use a scheduled **log search alert**, not an Azure Activity Log alert. Check the workspace's + **Tables** settings for the table plan; confirm the selected plan supports the query/rule. +4. Set **Measurement** to match the verified output. For unsummarized matching event rows, + use **Table rows** with **Total** to count those rows. For an official summarized query + such as **Failed Signin reasons**, use **Calculation of a numeric column**, select its + verified count column (`Count` in that source query), and choose the aggregation/grouping + that matches your objective. + Summing count groups is different from taking the maximum group; agree which is intended. + A rate query requires the reviewed numeric rate column. Do not count summary rows + as failures or assume the wizard's automatically detected measurement is correct. +5. On **Alert logic**, select **Static** for an initial baseline-derived rule. Enter the + approved **Operator** and **Threshold value**, checking units against the query output. + Only use a returned-row/greater-than-zero condition when the approved query itself + deliberately returns **qualifying incidents**, not an unconditional summary. Do not + apply that setting blindly to Microsoft's count examples. +6. Set **Aggregation granularity (window size)** and **Frequency of evaluation** from the + recorded observation window, normal ingestion delay, response needs, and budget. + Record the actual selected values with the rule. A frequent evaluation is not proof of + fresh data; overlapping windows can observe the same records repeatedly. +7. In **Advanced options**, review **Override query time range** and any query time filter + together. Ensure the rule scans the data required by its approved calculation, including + any deliberately delayed observation window. Alert queries scan at most **48 hours**; + a longer baseline query is not automatically a valid scheduled rule. One-minute evaluation + has extra query restrictions, including `ingestion_time()`; consult the official reference + before selecting it. A time picker used during exploration is not a stored rule setting. +8. Decide **Number of violations to trigger the alert** with the owner. If using several + violating evaluations, check the query's required datetime output and evaluation period + against the official instructions. Inspect the **Preview** for healthy and qualifying + periods. Do not assume missing data is a healthy evaluation. +9. Leave **Split by dimensions** unset unless separate incidents are required and reviewed. + Adding app/IP/user dimensions changes grouping, incident count, cost, and exposed data. + Avoid volatile/high-cardinality request, correlation, and user identifiers. A workspace-scoped + alert without dimensions is a workspace incident; document the app/scope in its runbook. +10. On **Actions**, select an approved action group or select **Create action group**. + Follow the [illustrated action-group creation instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/action-groups#create-in-the-azure-portal). + Confirm subscription/resource group, name, processing region, and notification recipients. + For a new group, complete **Basics**, then **Notifications** with the approved type, + recipient, and applicable **Common alert schema** setting. Review any **Actions**, then + select **Review + create > Create** and return to the rule to select the saved group. + Use approved email/push or incident routing, complete required recipient verification, + and keep security results on a restricted route. Do not attach an automated policy-change + action to an unvalidated heuristic. +11. On **Details**, select the **Subscription**, **Resource group**, **Region**, and agreed + **Severity**. Enter an **Alert rule name** and **Description** identifying source tenant, + app, measure/units, threshold rationale, window, owner, and runbook. Use + [the illustrated Details and Identity screen](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#configure-alert-rule-details). +12. Select the approved **Identity** for query evaluation. A **system-assigned managed + identity** has no permissions initially: create the rule with **Enable upon creation** + cleared, then have the access owner grant its identity reader/query access to the + workspace through **Workspace > Access control (IAM)**. Allow role propagation before + enabling it. If using a **user-assigned identity**, authorize it before selection. + For **None**, record that query permissions follow the last editor. Check linked-storage + policy requirements and identity restrictions in the official reference before choosing. +13. Review **Automatically resolve alerts** for stateful behavior and **Mute actions** + where appropriate. Resolution timing depends on evaluation frequency; it is not immediate. + Confirm the owner understands when repeated notifications will be suppressed. +14. Select **Review + create** only after checking scope, query, measured units, time settings, + permissions, actions, and costs. Keep the initial rule disabled until its identity and + [validation checks](#validate-without-generating-provider-sends) are ready. To change it, + use **Monitor > Alerts > Alert rules > selected rule > Edit**. ### Monitor ingestion separately -Failure/volume rules can appear quiet when collection is broken. For a scope that is expected -to have regular user sign-ins, this query returns a row if nothing has been ingested in an hour, -including when the selected scope has no rows in the last day: - -```kusto -SigninLogs -| where TimeGenerated >= ago(24h) -| where AADTenantId =~ "" and AppId =~ "" -| summarize LastIngested = max(ingestion_time()), StoredRows = count() -| where StoredRows == 0 or isnull(LastIngested) or LastIngested < ago(60m) -| project Monitor = "Sign-in feed needs investigation", LastIngested, StoredRows -``` - -Use a separate rule with **Table rows / Total > 0**, **30-minute granularity**, -**15-minute evaluation frequency**, and **Override query time range: 24 hours**. The one-hour -staleness threshold is in KQL. Do not shorten that override to the aggregation window. -Avoid one-minute frequency: `ingestion_time()` is not supported by that frequency's optimization. -An unresolved table/query or access failure is a rule-health problem, not a stale-data row. -No sign-ins during quiet hours and broken ingestion look alike; enable this only with a -documented traffic expectation and maintenance schedule. Null ingestion time is also -investigative, not proof of an outage. Compare with portal sign-ins, diagnostic settings, -workspace access, transformations, service health, and ingestion limits. +1. Assign a collection owner independently of the failure/volume responder. Quiet alerts + can mean broken export, not healthy authentication. Review the + [log-alert guidance on missing data](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-types#log-alerts) + before designing a freshness rule. +2. Record whether the source app should have regular traffic, including quiet hours and + maintenance. Compare **Entra > Sign-in logs** with the workspace after the measured delay. + No user activity and stopped collection can look identical; do not enable staleness paging + for an idle app without a documented expectation. +3. Have the query operator adapt the official + [ingestion-time/latency guidance](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/data-ingestion-time) + into a separate scoped freshness check. Require explicit handling of **no matching rows, + missing ingestion time, and stale latest arrival**, and verify each case. The linked + reference is not a preconfigured Entra no-data alert. Do not hide an unresolved table or + query error behind an empty-success fallback. +4. Create a separate rule using the same portal workflow, with its own freshness measure, + threshold, lookback, frequency, action group, and owner. Match its **Override query time + range** to the freshness calculation, not blindly to the aggregation window. Confirm + frequency supports the query; ingestion-time functions are restricted at one-minute frequency. +5. Check **Monitor > Alerts > Alert rules**, the selected rule's health/errors and associated + alerts, and the workspace's collection settings. Permission/query failures must be resolved + separately from a stale-data incident. Inspect transformations, ingestion limits, and service + health with the owner; do not infer reduced abuse from missing evidence. ### Validate without generating provider sends -First validate scopes and counts against existing approved records; allow for ingestion delay. -Review healthy/empty windows as well as qualifying windows. For a temporary **nonproduction** -rule, select a known existing window **within the rule's query lookback** and lower the KQL -threshold so its existing rows qualify. If testing an older window, change the query's time -filter and portal query-time override together (log search alerts scan at most 48 hours); -keep the test action group restricted. Verify the scheduled evaluation, notification, -incident context, and later resolution, then restore/delete the temporary rule and restore -production thresholds. Do not leave a test override active. - -If there are no suitable records, use the organization's approved **non-phone** test sign-in -flow in a test tenant/app and record its UTC time/IDs. Do not induce repeated wrong OTPs, -change production policy, bypass Easy Auth, or send live OTPs to populate a chart. -An EPP evaluation can validate parts of Function telemetry but cannot validate provider -delivery or guarantee a `SigninLogs` row. No query here has been executed against a customer -tenant by this documentation; operators must confirm live schema, data, and rule behavior. +1. Open the selected action group and use **Test**, following the official + [action-group testing instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/action-groups#test-an-action-group-in-the-azure-portal). + Save the group first. Choose the test's alert type and approved notification/action + receivers, then select **Test** and keep the test page open until **Success** or **Failed** + appears. On failure, use **View details**, resolve the error, save, and retest. + Confirm the intended recipients actually receive it, including verification and + spam-filter checks; access to read a group alone does not grant test permission. + This tests notification routing, not log export or query evaluation. +2. Run the saved scoped query against existing approved records and compare it with the + associated Entra sign-ins. Check a healthy window, a qualifying window, an empty scope, + and known ingestion delay. Confirm output shape/units agree with the rule's Measurement. +3. For an end-to-end check, create a **temporary nonproduction rule** with a restricted + test action group. Use existing records within its lookback and an approved temporary + condition that they satisfy. If changing the query time filter, update the rule's + **Override query time range** consistently and stay within the alert scan limit. + Do not lower a production threshold or route a test to production incident automation. +4. Authorize the test rule's evaluation identity and enable it. Observe a scheduled + evaluation and notification in **Monitor > Alerts**; record rule name, UTC time, measured + value, recipients, and investigation context. A successful interactive query under your + own identity does not prove the rule identity can read the workspace. +5. Verify resolution when the test condition clears, allowing for stateful resolution timing. + Disable/delete the temporary rule and remove temporary overrides. Reopen the intended + rule to confirm its approved query, threshold, time settings, recipients, and enablement. +6. If records are insufficient, use only an approved **non-phone test sign-in flow** in a + test tenant/app. Do not induce repeated wrong OTPs, alter production policy, bypass Easy Auth, + or send live OTPs just to populate a report. An EPP evaluation does not validate delivery + and is not guaranteed to create `SigninLogs` records. +7. Confirm validation is complete only after customer operators verify actual collection, + saved-query behavior, scheduled identity access, notification receipt, and cleanup. + This documentation has not executed Azure/Kusto queries or created/tested a customer's rule. ## 6. Build a sign-in Workbook -In **Azure portal > Monitor > Workbooks**, select **New**, enter **Edit** mode, and **Add query**. -Choose **Logs (Analytics)** as the data source and the verified destination workspace. -Add the baseline query as a time chart and separate result-code/step summaries as grids. -Label counts as stored sign-in/step rows and include collection freshness and unknown-code -coverage so an empty chart is not read as healthy. - -Save to an approved subscription/resource group, naming the monitored tenant/app scope. -If introducing workspace, tenant, app, or time-range parameters, bind them into every query -and test their effects; these examples have explicit literals/time filters, so a UI time -selector does not automatically change all query lookbacks. Keep IP/user-level investigation -views restricted. See [Workbook authoring](https://learn.microsoft.com/en-us/azure/azure-monitor/visualize/workbooks-create-workbook). - -The [Microsoft External ID workbook samples](https://github.com/microsoft/external-id-azure-monitor) -provide authentication, MFA, user-behavior, and risk-oriented starting points. Review their -source, deployment/access changes, queries, tenant feature requirements, and privacy before -importing any template; a sample named "risk detection" does not make ID Protection available -in an external tenant. This repository does not deploy those templates. A Workbook visualizes -data; it does not create the scheduled alert rules above. +1. Open the [Microsoft External ID monitoring repository](https://github.com/microsoft/external-id-azure-monitor) + and review its setup instructions. Inspect the relevant + [authentication](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/authenticationsWorkbookDeployment.json), + [MFA](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/mfaWorkbookDeployment.json), + or [user-behavior](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/userBehaviourWorkbookDeployment.json) + template for existing queries and visualizations. Do not select **Deploy to Azure** + just to view a query; templates can create resources/delegation and require separate approval. + In the GitHub file view, inspect the workbook's **serializedData** and its query definitions + with the query operator. These files are ARM deployment templates, not text to paste in full + into Logs; extract/review only the needed query or use an already-approved deployed Workbook. +2. Check each chosen query's tables, tenant features, workspace/app filters, time settings, + personal-data fields, and units against your actual records. A template named + [risk detection](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/riskDetectionWorkbookDeployment.json) + does not make ID Protection available in an external tenant. +3. In **Azure portal > Monitor > Workbooks**, select **New** or an empty template and enter + **Edit** mode. Follow the + [illustrated Workbook authoring guide](https://learn.microsoft.com/en-us/azure/azure-monitor/visualize/workbooks-create-workbook). + Select **Add > Add query**, choose **Logs (Analytics)** and the verified workspace, + then use the approved saved/query-source content. +4. Select a **Visualization** matching the output, then **Run Query**. Use counts/result-code + grids for breakdowns and a time chart only for a query with the appropriate time-series + output. Check actual scope/time/units before selecting **Done editing**; the + [Add queries instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/visualize/workbooks-create-workbook#add-queries) + show the relevant controls. +5. Add text identifying source tenant/app, intended measure, arrival-delay expectations, + unknown/missing-data interpretation, and response owner. Label stored sign-in records + and authentication steps distinctly; an empty chart is not a healthy result. + Include the separately reviewed freshness view. +6. If adding app/workspace/time parameters, bind them into **every relevant query** and + verify that changing them changes the data as intended. A Workbook selector does not + override a hard-coded filter automatically. Keep detailed IP/user-level views restricted. +7. Select **Save** and choose the approved subscription, resource group, location, and name. + Have another authorized operator open it and verify access and scope. Sharing a Workbook + does not grant access to the underlying logs. Workbooks visualize data; they do **not** + create the scheduled alerts above or prove those alerts are enabled. ## 7. Triage, privacy, retention, and costs -On an alert, the owner should confirm workspace/rule health, tenant/app scope, UTC window, -and result-code distribution first. Inspect the relevant sign-in's **Basic info**, -**Authentication Details**, and applicable policy results in the Entra admin center. -Separate user mistakes/interruptions and policy changes from infrastructure failures or -potential abuse; escalate suspected compromise to the organization's security response process. - -If phone delivery is implicated, follow the runtime-specific -[Function log discovery](MONITORING.md#runtime-specific-log-discovery). Compare timestamp, -verified request context, failure stage, and provider outcome with the provider's restricted -records. The sample logs sanitized envelope/header correlation identifiers, but -`SigninLogs.CorrelationId`, Function `OperationId`, request IDs, and provider references are -**not guaranteed equal**. Prove any association in an approved trace before using a join; -absence of a match is not proof that the Function/provider was never called. Fallback can -complete authentication through another path. Neither a sign-in success nor provider -acceptance establishes handset receipt. - -Logs can contain user IDs, names, IP addresses, locations, device information, and phone -identifiers. Use minimum necessary fields, scoped Azure RBAC/table access, restricted -Workbooks/action groups, and approved residency/retention. Do not export full records to public -issues or put tokens, OTPs, message bodies, or credentials in alerts. Diagnostic export -normally selects categories, **not app IDs**: query filters restrict analysis but do not -reduce all tenant-wide ingestion or establish an access boundary. - -Review [retention configuration](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/data-retention-configure) -and [log costs](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/cost-logs) separately -from Entra portal retention and provider billing. Confirm the effective table plan, analytics -retention, longer-term retention, ingestion/query volumes, alert frequency/dimensions, and -notification charges. Daily caps or transformations can remove the evidence an alert needs; -monitor those gaps rather than interpreting them as reduced abuse. App IDs and aggregate -counts are preferable to high-cardinality personal dimensions. - -Handover is complete only after the customer verifies export arrival, scoped queries, -rule-identity access, alert/action-group behavior, freshness checks, and named operational, -security, privacy, retention, and cost owners. Keep validation evidence privately. These -heuristics support human investigation; they do not authorize automated blocking or policy changes. +1. When notified, open **Monitor > Alerts > selected alert** and confirm rule name, + workspace, tenant/app scope, UTC window, measured value, and rule/collection health. + Open the approved saved query for that period, then inspect the related Entra sign-in's + **Basic info**, **Authentication Details**, and applicable policy results. +2. Review changed result codes with the identity-support owner. Separate user + mistakes/interruptions, application releases, and policy changes from infrastructure + failures or potential abuse. Escalate suspected compromise through the organization's + security response process; a heuristic notification is not a confirmed fraud verdict. +3. If phone delivery is implicated, follow the existing + [runtime-specific Function queries](MONITORING.md#runtime-specific-log-discovery). + Compare UTC time, verified request context, failure stage, and provider outcome with + restricted provider records. `SigninLogs.CorrelationId`, Function `OperationId`, + request IDs, and provider references are **not guaranteed equal**. Prove any association + in an approved trace before using a join. An absent match does not prove no Function call; + fallback can also complete authentication through another path. +4. Keep personal data in approved systems. User IDs/names, IP/location/device details, + sign-in identifiers, and authentication details can be sensitive. Review workspace/table + access, Workbook sharing, and action-group recipients. Do not export raw records to public + issues or put OTPs, message bodies, tokens, or credentials in alerts. Query filters are + **not an access-control boundary**. +5. In **Log Analytics workspace > Tables**, select the relevant table and review its + table plan, **analytics retention**, and **total retention** with the privacy/retention + owner. Follow [retention configuration](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/data-retention-configure). + Confirm the setting actually saved and allows the required investigation period. + Entra portal retention and workspace retention are different. +6. Review **workspace Usage and estimated costs** and **Azure Cost Management > Cost analysis** + for the approved subscription/resource scope, using the + [log-cost guidance](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/cost-logs). + Diagnostic export selects categories, not an app-specific stream: app query filters + do not remove tenant-wide ingestion charges. Include retention, queries, alert frequency, + dimension count, notifications, and any separately enabled services in budget review. +7. Inspect caps and transformations with the collection owner. They can remove evidence + needed by a rule. Verify changes do not silently remove required fields/populations and + update collection-health checks. Provider sending/billing remains a separate cost source. +8. Complete a restricted handover record with source tenant/app, workspace/export setting, + saved queries, measured baseline/delay, Workbook, alert rule/identity, action group, + thresholds/time settings, validation evidence, and collection/identity/security owners. + Assign privacy, retention, and cost-review owners plus escalation/maintenance procedures. +9. Have the receiving operator confirm they can reopen the queries and Workbook, inspect + rule health, receive an approved notification, and follow triage without generating + provider sends or changing policy. Leave no temporary test overrides active. Handover + is complete only after these **customer-side checks**, not merely publication of this guide. From b70fcaf4c96bc8b32500f465d8794af63bdbd754 Mon Sep 17 00:00:00 2001 From: Hou Chi Chan Date: Tue, 13 Oct 2026 13:16:30 -0700 Subject: [PATCH 3/8] docs: illustrate Entra monitoring with permitted Microsoft screenshots Add two whole unaltered official screenshots beside diagnostic-settings and Authentication Details steps, with example-only captions, pinned provenance, explicit screenshot permission and source license notice. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f1451aca-6f84-41e6-9baf-cec42e36da6e --- docs/SIGN-IN-MONITORING.md | 21 ++++++ docs/images/sign-in-monitoring/NOTICE.txt | 67 ++++++++++++++++++ .../diagnostic-settings-start.png | Bin 0 -> 91954 bytes ...ign-in-activity-details-authentication.png | Bin 0 -> 24665 bytes 4 files changed, 88 insertions(+) create mode 100644 docs/images/sign-in-monitoring/NOTICE.txt create mode 100644 docs/images/sign-in-monitoring/diagnostic-settings-start.png create mode 100644 docs/images/sign-in-monitoring/sign-in-activity-details-authentication.png diff --git a/docs/SIGN-IN-MONITORING.md b/docs/SIGN-IN-MONITORING.md index 83fd7db..f05fbea 100644 --- a/docs/SIGN-IN-MONITORING.md +++ b/docs/SIGN-IN-MONITORING.md @@ -9,6 +9,9 @@ This guide does not deploy anything or change authentication policy. Use the linked Microsoft queries and illustrated portal instructions at the step where you need them; no query snippets or fixed sample thresholds are duplicated here. Portal labels can vary. The official screenshots show the controls, not resources or IDs to copy. +The two Microsoft screenshots below are unaltered public documentation examples, not your +tenant or evidence of a configured EPP integration. Used with permission from Microsoft. +Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompany the files. 1. Complete [tenant and access checks](#1-choose-the-tenant-and-permissions). 2. [Configure export](#2-export-the-required-log-categories) and @@ -122,6 +125,15 @@ can vary. The official screenshots show the controls, not resources or IDs to co Diagnostic settings**. For the matching illustrated screen, use [access diagnostic settings](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-configure-diagnostic-settings#how-to-access-diagnostic-settings). Review existing settings and their owners before adding or editing an integration. + + ![Microsoft Entra admin center showing Monitoring and health, Diagnostic settings, and Add diagnostic setting highlighted](images/sign-in-monitoring/diagnostic-settings-start.png) + + *Official Microsoft Entra admin center example from + [Microsoft's diagnostic-settings instructions](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-configure-diagnostic-settings#how-to-access-diagnostic-settings). + Used with permission from Microsoft. This is not your tenant; menus and categories vary. + Follow the numbered navigation above, not the example's breadcrumb. Visible risk categories + do not establish that those features are available or licensed in an external tenant.* + 2. Select **Add diagnostic setting**, or deliberately edit the owner-approved setting. Enter a recognizable name for a new setting. Select **SignInLogs** for interactive user authentication. Add **AuditLogs** only if directory-change investigation is also @@ -211,6 +223,15 @@ can vary. The official screenshots show the controls, not resources or IDs to co selected record > Authentication Details**. Use the official [Authentication Details screenshot and explanation](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-in-log-activity-details#authentication-details) to read the step sequence, method, outcome, and policy context. + + ![Microsoft Entra ID sign-in Activity Details with Authentication Details selected and two Previously satisfied steps marked true](images/sign-in-monitoring/sign-in-activity-details-authentication.png) + + *Official Microsoft Entra ID example from + [Microsoft's sign-in activity-details instructions](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-in-log-activity-details#authentication-details). + Used with permission from Microsoft. This is not your sign-in or a delivery test. + The example's Previously satisfied outcomes do not prove a new phone challenge or + provider send. Your methods, policy results, timestamps, and portal layout can differ.* + 2. Check whether the step was satisfied by an existing token claim or a previous authentication. A method named SMS/Voice is not a provider ID or delivery receipt. Keep the sign-in's overall outcome separate from an individual step's outcome. diff --git a/docs/images/sign-in-monitoring/NOTICE.txt b/docs/images/sign-in-monitoring/NOTICE.txt new file mode 100644 index 0000000..2aaae8a --- /dev/null +++ b/docs/images/sign-in-monitoring/NOTICE.txt @@ -0,0 +1,67 @@ +Microsoft Entra monitoring screenshots + +Copyright (c) Microsoft Corporation. +Used with permission from Microsoft. + +These two files are unaltered copies of public Microsoft documentation screenshots. +They illustrate Microsoft Entra admin center and Microsoft Entra ID controls, not a +customer's tenant, deployed External Phone Provider configuration, or delivery result. +No Microsoft endorsement is implied. Product names and trademarks remain their owners'. + +Source repository: https://github.com/MicrosoftDocs/entra-docs +Source commit: 927efa819a6f89a40b39b178d702b30f49b63f00 +Retrieved and visually reviewed: 2026-10-13 + +diagnostic-settings-start.png +Source: +https://github.com/MicrosoftDocs/entra-docs/blob/927efa819a6f89a40b39b178d702b30f49b63f00/docs/identity/monitoring-health/media/howto-configure-diagnostic-settings/diagnostic-settings-start.png +Microsoft Learn context: +https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-configure-diagnostic-settings#how-to-access-diagnostic-settings +SHA-256: ed04ba296e34e9031e9b37e757d2c613ffc9a48f5cf790e4b96d8c9b2d4f66a3 + +sign-in-activity-details-authentication.png +Source: +https://github.com/MicrosoftDocs/entra-docs/blob/927efa819a6f89a40b39b178d702b30f49b63f00/docs/identity/monitoring-health/media/concept-sign-in-log-activity-details/sign-in-activity-details-authentication.png +Microsoft Learn context: +https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-in-log-activity-details#authentication-details +SHA-256: f9acf702fe5e6d7547260d5d7f2c402d2dd7ab4558d174680c8c718e32916e41 + +Reuse permission: +https://www.microsoft.com/en-us/legal/intellectualproperty/copyright/permissions +The Screenshots section expressly permits Microsoft product screenshots in +documentation and on websites under its stated conditions. These copies retain +the entire original images without modification. The required permission +statement appears above and in the guide's captions. +This specific screenshot-use permission is the primary reuse basis, not an +assumption that all Microsoft Learn media share one open-content license. + +Repository license: +https://github.com/MicrosoftDocs/entra-docs/blob/927efa819a6f89a40b39b178d702b30f49b63f00/LICENSE +The exact source repository's root LICENSE is the MIT License reproduced below, +including associated documentation files. No nested license/notice override was +found for these image paths. The source ThirdPartyNotices.md also refers to +CC-BY documentation licensing, inconsistently with that root LICENSE; these +copies do not rely on a general CC-BY license for Microsoft Learn media. +Microsoft's explicit screenshot permission is independently verified above. + +MIT License + +Copyright (c) Microsoft Corporation. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/docs/images/sign-in-monitoring/diagnostic-settings-start.png b/docs/images/sign-in-monitoring/diagnostic-settings-start.png new file mode 100644 index 0000000000000000000000000000000000000000..2b18a767a50947c4756d00e020053b75d2a188f0 GIT binary patch literal 91954 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

0(!2>%3I58pJ@U+Ko!^hcR0 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 |h>dP53h<=63 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 literal 0 HcmV?d00001 From 183d66f136d575fb3bd2aabd8f69ec6d21ff135b Mon Sep 17 00:00:00 2001 From: Hou Chi Chan Date: Tue, 13 Oct 2026 13:30:31 -0700 Subject: [PATCH 4/8] docs: make sign-in monitoring guidance more conversational Lighten repetitive checkpoints and administrator wording while preserving numbered portal steps, technical limits, source links and permitted screenshot attribution. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f1451aca-6f84-41e6-9baf-cec42e36da6e --- docs/SIGN-IN-MONITORING.md | 239 ++++++++++++++++++------------------- 1 file changed, 119 insertions(+), 120 deletions(-) diff --git a/docs/SIGN-IN-MONITORING.md b/docs/SIGN-IN-MONITORING.md index f05fbea..d34d8e8 100644 --- a/docs/SIGN-IN-MONITORING.md +++ b/docs/SIGN-IN-MONITORING.md @@ -1,25 +1,25 @@ # Monitor Microsoft Entra sign-ins -Follow these steps to export Microsoft Entra sign-in logs, inspect authentication outcomes, -and configure customer-owned notifications. This is **tenant identity monitoring**, separate +Use this guide to find out why sign-ins fail, spot changes in traffic, and notify your team +when something needs attention. It covers **tenant identity monitoring**, separate from [Function monitoring](MONITORING.md) and [Application Insights](APPLICATION-INSIGHTS.md). EPP setup does **not** configure tenant log export, Workbooks, action groups, or sign-in alerts. This guide does not deploy anything or change authentication policy. -Use the linked Microsoft queries and illustrated portal instructions at the step where you -need them; no query snippets or fixed sample thresholds are duplicated here. Portal labels -can vary. The official screenshots show the controls, not resources or IDs to copy. +Each section links to Microsoft's existing queries and portal instructions, so you can +start there and adapt them to your tenant rather than copy another set of examples. +Choose alert thresholds from your own traffic. Portal labels can vary. The two Microsoft screenshots below are unaltered public documentation examples, not your tenant or evidence of a configured EPP integration. Used with permission from Microsoft. Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompany the files. -1. Complete [tenant and access checks](#1-choose-the-tenant-and-permissions). +1. Start with [the right tenant and access](#1-choose-the-tenant-and-permissions). 2. [Configure export](#2-export-the-required-log-categories) and [confirm actual records](#3-confirm-arrival-and-schema). 3. [Choose a query and measure your baseline](#4-establish-the-baseline) before [configuring notifications](#5-create-actionable-log-search-alerts). -4. [Create the investigation Workbook](#6-build-a-sign-in-workbook) and complete - [triage and handover checks](#7-triage-privacy-retention-and-costs). +4. [Build a Workbook for your team](#6-build-a-sign-in-workbook), then + [plan investigation and handover](#7-triage-privacy-retention-and-costs). ## What these logs can and cannot tell you @@ -52,23 +52,23 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa tenant** for consumer/business-customer apps. Use the [tenant feature comparison](https://learn.microsoft.com/en-us/entra/external-id/customers/concept-supported-features-customers) with your tenant administrator. The export setup and feature availability differ. -3. Open **Entra ID > Monitoring & health > Sign-in logs** and select an existing, - approved sign-in for the application you intend to monitor. In **Basic info**, check +3. Open **Entra ID > Monitoring & health > Sign-in logs** and select an existing sign-in + you're authorized to inspect for the application you want to monitor. In **Basic info**, check **Application**, **Application ID**, **Resource**, the outcome, and time. The [illustrated activity-details guide](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-in-log-activity-details#basic-info) explains these fields. Record the application's **client ID**, not its Object ID. It is not necessarily the endpoint `applicationId` in the EPP deployment summary. - Record the displayed time zone and convert investigation times to UTC when comparing sources. + Note the displayed time zone; use UTC when comparing it with other logs. 4. Choose the destination **subscription, resource group, workspace, and region** with - the Azure operator and privacy/cost owners. Check for an existing approved destination - before requesting another one. Keeping Entra logs with Function telemetry is an - operator decision, not an automatic consequence of guided EPP setup. + your Azure administrator and the people responsible for privacy and costs. An existing + workspace may be suitable; check before creating another one. You can choose to keep + Entra and Function logs together, but EPP setup does not make that connection for you. 5. For a **workforce tenant**, check the [integration prerequisites](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-integrate-activity-logs-with-azure-monitor-logs#prerequisites). General diagnostic settings require at least **Security Administrator** in the Entra tenant, an Azure subscription, a prepared Log Analytics workspace, and appropriate - Azure access to the destination. If no workspace is approved yet, have the Azure operator - follow the [workspace creation instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/quick-create-workspace). + Azure access to the destination. If you still need a workspace, ask your Azure administrator + to follow the [workspace creation instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/quick-create-workspace). 6. For an **external tenant**, open the [illustrated external-tenant setup guide](https://learn.microsoft.com/en-us/entra/external-id/customers/how-to-azure-monitor#prerequisites). An external tenant cannot have an associated Azure subscription. The documented setup @@ -80,10 +80,10 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa 7. Arrange read access separately. **Reports Reader** is the least privileged Entra role for activity-log access in the admin center; see [access requirements](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-access-activity-logs#prerequisites). - It does not grant Azure log access. Have the access owner review + It does not grant Azure log access. Ask your Azure administrator to review [workspace/table permissions](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/manage-access) and grant appropriately scoped query access, such as **Log Analytics Reader**. - Confirm the investigator can open the chosen workspace's **Logs** without an access error. + Try opening the workspace's **Logs** with the account you'll use to investigate sign-ins. 8. Verify licensing before selecting premium reports. Current [monitoring licensing guidance](https://learn.microsoft.com/en-us/entra/fundamentals/licensing#microsoft-entra-monitoring-and-health) lists sign-in and audit logs for Entra ID Free as well as P1/P2. That does not imply @@ -95,36 +95,35 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa workforce tenants, full [ID Protection capabilities](https://learn.microsoft.com/en-us/entra/id-protection/overview-identity-protection#license-requirements) require P2 or an applicable entitlement. Do not purchase workforce P2 expecting it to enable external-tenant risk detections, or read empty/hidden risk values as fraud clearance. -10. Confirm this step is complete: the private inventory identifies the **source tenant - and type, customer app client ID, destination workspace resource ID, access owners, - query operator, alert operator, and security responder**. Stop before export if the - scope, destination approval, or required access is unresolved. +10. Before continuing, keep a private note of the **tenant and type, app client ID, and + workspace resource ID**. Agree who will maintain queries, configure alerts, and respond + to security concerns. Resolve any missing access or workspace approval before exporting logs. ## 2. Export the required log categories ### Prepare the external-tenant access path 1. If monitoring a **workforce tenant**, skip this subsection. If an external tenant is - already integrated, review its existing destination/access with the owner rather than + already integrated, check its destination and access with the administrator rather than rerunning setup. Otherwise, open **Entra ID > Monitoring & health > Diagnostic settings** in the external tenant and select **Start set up**. 2. Follow the official [wizard screenshots and instructions](https://learn.microsoft.com/en-us/entra/external-id/customers/how-to-azure-monitor#set-up-the-azure-lighthouse-configuration-in-the-wizard). Sign in to the **workforce tenant** for the approved subscription. Select the subscription and resource group, specify the workspace name and region, and select **Next**. -3. In **Select user access**, choose only approved external-tenant users/groups and their - documented Azure roles. Review the delegation and permissions with the access owner. +3. In **Select user access**, choose the external-tenant users/groups who need access and + the documented Azure roles agreed with your administrator. Review the delegation carefully. The wizard's roles are not a grant of all alert-management or role-assignment permissions. 4. At **Review and create**, confirm destination, region, users/groups, roles, and charges. Select **Create** only after approval. Wait for confirmation, select **Done**, and - proceed to diagnostic settings. Retain the destination identifiers privately. + continue to diagnostic settings. Keep the destination identifiers with your setup notes. ### Select and save the export 1. In the **source tenant's** Entra admin center, open **Entra ID > Monitoring & health > - Diagnostic settings**. For the matching illustrated screen, use + Diagnostic settings**. If you need help finding the screen, see [access diagnostic settings](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-configure-diagnostic-settings#how-to-access-diagnostic-settings). - Review existing settings and their owners before adding or editing an integration. + Check existing settings first, and speak to whoever maintains them before making changes. ![Microsoft Entra admin center showing Monitoring and health, Diagnostic settings, and Add diagnostic setting highlighted](images/sign-in-monitoring/diagnostic-settings-start.png) @@ -134,7 +133,7 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa Follow the numbered navigation above, not the example's breadcrumb. Visible risk categories do not establish that those features are available or licensed in an external tenant.* -2. Select **Add diagnostic setting**, or deliberately edit the owner-approved setting. +2. Select **Add diagnostic setting**, or edit an existing setting if its maintainer has agreed. Enter a recognizable name for a new setting. Select **SignInLogs** for interactive user authentication. Add **AuditLogs** only if directory-change investigation is also required; audit events are not sign-in outcomes. @@ -150,20 +149,20 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa can reside in the provider's tenant and require its administrator's assistance. 5. Under **Destination details**, select **Send to Log Analytics workspace**, then choose the approved **Subscription** and **Log Analytics workspace**. For an external tenant, - use the access path established above. Compare the selection with your private inventory. + use the access set up above. Check the destination against your setup notes. The [illustrated export instructions](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-integrate-activity-logs-with-azure-monitor-logs#send-logs-to-azure-monitor) show the category and destination controls. 6. Select **Save**, reopen the setting, and confirm its **selected categories and destination**. - Record the export start time and configuration owner. This setting belongs to Entra, + Note when you enabled export and who maintains it. This setting belongs to Entra, not the Function App; Function diagnostic settings/Application Insights do not perform this export. Do not expect a backfill of all historical portal sign-ins. -7. Confirm this step is complete: the saved setting points to the intended workspace - and includes the intended sign-in category, with no unintended changes to another - integration. Continue to record verification rather than assuming that Save proves arrival. +7. Check that the setting still points to the right workspace and includes the sign-in + category you selected, without changing another integration. Next, check for records: + saving the setting alone doesn't tell you whether logs have arrived. ## 3. Confirm arrival and schema -1. Open **Azure portal > Log Analytics workspaces > the recorded destination > Logs**. +1. Open **Azure portal > Log Analytics workspaces > your destination workspace > Logs**. For an external tenant's workforce-hosted workspace, switch to the subscription-owning directory as necessary. Check the workspace name/query scope before running anything. Use the [illustrated Logs scope tutorial](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#open-log-analytics). @@ -177,7 +176,7 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa 3. In the table's controls, use **Run** to preview records, or select it through [Simple mode > Select a table](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-simple-mode#get-started-in-simple-mode). Choose a **Time range** that covers activity after export was saved. Limit the displayed - records and inspect them only within the approved access boundary; a preview can contain + records and use only an account authorized to read them; a preview can contain personal data. Do not use the Application Insights `requests`/`traces` context for Entra logs. 4. Allow for initial export delay. The [Microsoft External ID monitoring repository](https://github.com/microsoft/external-id-azure-monitor) @@ -192,7 +191,7 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa Do not substitute the app's Object ID, provider API ID, or workspace ID. The standard `TenantId` column is the **workspace ID**, not the source Entra tenant ID. 6. To narrow exploration without writing a new query, use **Simple mode > Add > column filter** - for `AADTenantId` and `AppId`, then enter/select your verified IDs. See the illustrated + for `AADTenantId` and `AppId`, then enter/select the IDs you checked above. See the illustrated [column-filter instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-simple-mode#filter-by-column). Apply source/app filters **before aggregation**. Switch to **KQL mode** and confirm the generated query contains them; a Results-grid search or column-header filter is not an @@ -203,19 +202,19 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa These are not provider/Function HTTP statuses. Review the corresponding portal record's **Basic info** with the [sign-in error troubleshooting instructions](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-troubleshoot-sign-in-errors). -8. Check time semantics before selecting alert windows. `CreatedDateTime` is sign-in - initiation time in UTC; `TimeGenerated` is the log timestamp used for workspace time filters. - Have the query operator use the existing +8. Check which timestamps you're comparing before choosing alert windows. `CreatedDateTime` + is sign-in initiation time in UTC; `TimeGenerated` is the timestamp used for workspace time filters. + Work with whoever maintains your queries to use the [ingestion-latency reference](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/data-ingestion-time) and [standard-column timing guidance](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-standard-columns#_timereceived-column) to measure arrival delay against **SigninLogs**, with your tenant/app scope. Those references - are generic, not a ready-made Entra latency monitor. Record the measured delay and any + are generic, not a ready-made Entra latency monitor. Note the measured delay and any missing timestamps; do not confuse ingestion time with authentication or delivery latency. -9. Confirm this step is complete: actual records identify the intended source tenant/app, - their fields/types match the reference, and the operator knows their time range and arrival - delay. An unresolved table is a collection/access problem, not a healthy empty result. - If a table exists but the scope is empty, compare with **Entra > Sign-in logs**, inspect - collection transformations and ingestion limits with the owner, and resolve the gap first. +9. You should now be able to find records for the right tenant and app, understand their + fields, and allow for arrival delay. If the table can't be found, investigate collection + and access rather than treating that as a healthy result. If the table exists but your + app has no records, compare with **Entra > Sign-in logs** and ask the workspace administrator + to check transformations and ingestion limits before you build alerts. ### Inspect authentication steps safely @@ -237,7 +236,7 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa Keep the sign-in's overall outcome separate from an individual step's outcome. 3. For an existing shared method report, review the official [MFA Workbook template](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/mfaWorkbookDeployment.json) - with the query operator. Its current queries use **AuditLogs**, not `SigninLogs` + with whoever maintains your queries. Its current queries use **AuditLogs**, not `SigninLogs` authentication-step arrays. They need the corresponding export and recorded audit activity; do not replace the table name or treat that report as the full sign-in step sequence. For a `SigninLogs` step report, have the operator review the actual `AuthenticationDetails` @@ -248,8 +247,8 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa **authentication steps**, not sign-ins. Missing steps do not establish success or failure. Keep `authenticationMethodDetail` and full raw payloads out of shared reports; they can include phone identifiers or other personal data. -5. Confirm this check is complete only after a report's displayed methods/outcomes agree - with selected portal records, without claiming provider attribution or recipient delivery. +5. Compare a few report entries with the corresponding portal records. The methods and + outcomes should agree; use the report to understand authentication, not to prove delivery. ## 4. Establish the baseline @@ -257,13 +256,12 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa Choose the relevant named query rather than copying an unrelated tutorial's table: **Failed Signin reasons** for result-code distribution, **Failed login Count** for failure counts by resource, or **Signin Locations** for successful/failed counts by location. - The customer-facing app, source tenant, time window, and thresholds are **not preconfigured** - for your deployment in these examples. + You'll need to set your app, tenant, time window, and alert thresholds in these examples. 2. In your workspace's **Logs**, switch to **KQL mode**. Copy the selected query from its official source into the editor. Alternatively, use the **Queries** pane if that query - is available there. Add your verified `AADTenantId`/`AppId` scope **before summarizing**, + is available there. Filter to your `AADTenantId` and `AppId` **before summarizing**, following the [filtering tutorial](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#apply-multiple-query-filters). - Have the query operator review edits if unfamiliar with KQL; do not run tenant-wide + If you're new to KQL, ask someone familiar with it to review the edits. Don't read tenant-wide results as if they describe one customer app. 3. Compare the query with the **actual string type of `ResultType`**. The official collection includes examples with numeric-looking comparisons; the operator must ensure the chosen @@ -280,23 +278,22 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa numeric count column and grouping; do not confuse the number of summary rows displayed with the number of sign-in records counted. The **Show** limit can cap displayed results. Avoid treating a truncated preview or browser-side grouping as a complete baseline. -6. Record privately the chosen source query, scoped saved version, output column/grouping, - usual volumes, non-success codes, unknown-data coverage, peak conditions, and observed - ingestion delay. Distinct-user, record-count, and authentication-step measures are different; - several log records can belong to one authentication sequence. -7. Agree with the response owner which change should notify someone and what they will - investigate. Choose thresholds from the measured baseline, with appropriate minimum - traffic for rate rules and quiet-hour/maintenance expectations. **No universal threshold - or prebuilt fraud verdict is supplied here.** Do not assume the official count queries - calculate a failure percentage, detect source-IP abuse, or implement a freshness check. +6. Keep the query and your findings together: what it counts, how it groups results, + normal and peak traffic, common non-success codes, missing data, and arrival delay. + Distinct users, sign-in records, and authentication steps are different measures; + several records can belong to one authentication sequence. +7. With the team receiving alerts, decide what change is worth a notification and what + they would investigate. Base thresholds on this traffic, including a minimum volume + for rate rules and allowances for quiet hours and maintenance. There isn't one useful + threshold for every app. The official count queries don't automatically calculate a + failure rate, detect source-IP abuse, or check collection freshness. 8. Select **Save > Save as query**, following [saving Azure Monitor queries](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/save-query). Enter the name and select the approved subscription/query pack; review the proposed default - pack rather than silently creating a new resource. The documented save permission is - **Log Analytics Contributor**; an authorized saver may need to perform this step for a - read-only investigator. Record its approved location and who can read it. - Confirm a second authorized operator - can reopen it and obtain the same scope and output shape before using it in a rule. + pack before creating a new resource. Saving requires **Log Analytics Contributor**; + if you only have read access, ask someone with that permission to save it. + Share its location with a teammate who has log access and check that they can reopen + it with the same filters and result columns before you use it in a rule. ## 5. Create actionable log search alerts @@ -305,20 +302,20 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa 1. Begin with [Failed Signin reasons](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/queries/signinlogs#failed-signin-reasons) to review **which result codes changed**. Use a reviewed failure-count rule first if that meets the requirement; this official query is not a complete failure-rate alert. -2. If a **rate** rule is needed, have the query operator adapt a saved query to return +2. If you need a **rate** rule, work with your query maintainer to return failures and the corresponding total for the **same tenant, app, population, and window**, with agreed handling of unknown codes and minimum traffic. Review healthy/empty windows and denominator coverage before choosing the alert's numeric percentage column. -3. Document exclusions and monitor them separately. Non-success results can include - interruptions, cancellation, and policy rejection. Assign authentication-support triage, - not automatic phone-provider outage classification. +3. Note any excluded codes and monitor them separately. Route these alerts to the team + troubleshooting authentication; a change in non-success rate alone doesn't identify + a phone-provider outage. ### B. Unusual sign-in volume 1. Review the [authentication Workbook template](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/authenticationsWorkbookDeployment.json) for existing sign-in traffic visualizations and query definitions. Treat it as source to review, **not** an instruction to deploy the entire template. -2. Have the query operator select/adapt the relevant traffic query and verify the output is +2. Choose a traffic query with your query maintainer and check that it returns a record count for the intended `SigninLogs` tenant/app/time window. The official **User count per Application** query counts distinct users, not total sign-in records; do not substitute that measure without changing the monitoring objective. @@ -331,9 +328,9 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa 1. Use [Signin Locations](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/queries/signinlogs#signin-locations) and the [user-behavior Workbook template](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/userBehaviourWorkbookDeployment.json) as investigation starting points. Neither is a ready-made source-IP fraud alert for EPP. -2. If a restricted IP-based rule is justified, have the security/query owner review actual - `IPAddress`, `UserId`, and `ResultType` population and design the grouped query/threshold - for the approved tenant/app. Check unknown users, absent IPs, approximate distinct counts, +2. If an IP-based rule would help, ask your security team to review which `IPAddress`, + `UserId`, and `ResultType` values are actually present and choose the grouping and + threshold for your tenant/app. Check unknown users, absent IPs, approximate distinct counts, distributed attempts, and expected shared-network activity before publishing it. 3. Restrict IP-bearing results and notifications to the security team. NAT, VPNs, mobile networks, and proxies can cause false positives; IP geolocation does not prove a person's @@ -348,37 +345,37 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa ### Configure the rule in the portal -1. Have the alert operator confirm **read access to the workspace**, **write access to - the rule's resource group**, and **read access to the action group**, using the +1. The person creating the rule needs **read access to the workspace**, **write access to + the rule's resource group**, and **read access to the action group**. Check the [official alert prerequisites](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#prerequisites). Creating an action group or assigning roles needs separate permissions. External-tenant operators must use approved Azure RBAC in the subscription-owning workforce tenant; Entra roles or Lighthouse delegation alone do not grant every operation. 2. Open **Azure portal > Monitor > Alerts > Create > Alert rule**. On **Scope**, choose - the verified **Log Analytics workspace** and select **Apply**, not the Function App or + your destination **Log Analytics workspace** and select **Apply**, not the Function App or app registration. Compare with the [illustrated scope screen](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#configure-the-scope-of-the-alert-rule). -3. On **Condition**, select **Custom log search**. Paste the approved **scoped saved query** +3. On **Condition**, select **Custom log search**. Paste the **saved, app-scoped query** selected above. Select **Run**, inspect **Preview**, then **Continue Editing Alert**. Use the [illustrated condition/measurement instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#configure-alert-rule-conditions). Use a scheduled **log search alert**, not an Azure Activity Log alert. Check the workspace's **Tables** settings for the table plan; confirm the selected plan supports the query/rule. -4. Set **Measurement** to match the verified output. For unsummarized matching event rows, +4. Set **Measurement** to match what the query returns. For unsummarized matching event rows, use **Table rows** with **Total** to count those rows. For an official summarized query such as **Failed Signin reasons**, use **Calculation of a numeric column**, select its - verified count column (`Count` in that source query), and choose the aggregation/grouping + count column (`Count` in that source query), and choose the aggregation/grouping that matches your objective. Summing count groups is different from taking the maximum group; agree which is intended. A rate query requires the reviewed numeric rate column. Do not count summary rows as failures or assume the wizard's automatically detected measurement is correct. -5. On **Alert logic**, select **Static** for an initial baseline-derived rule. Enter the - approved **Operator** and **Threshold value**, checking units against the query output. - Only use a returned-row/greater-than-zero condition when the approved query itself +5. On **Alert logic**, start with **Static** and the threshold you chose from your baseline. + Set the **Operator** and **Threshold value**, checking the units against the query output. + Only use a returned-row/greater-than-zero condition when the query itself deliberately returns **qualifying incidents**, not an unconditional summary. Do not apply that setting blindly to Microsoft's count examples. 6. Set **Aggregation granularity (window size)** and **Frequency of evaluation** from the - recorded observation window, normal ingestion delay, response needs, and budget. - Record the actual selected values with the rule. A frequent evaluation is not proof of + observation window, normal ingestion delay, response needs, and budget. + Keep these settings in your team's rule notes. A frequent evaluation is not proof of fresh data; overlapping windows can observe the same records repeatedly. 7. In **Advanced options**, review **Override query time range** and any query time filter together. Ensure the rule scans the data required by its approved calculation, including @@ -386,8 +383,8 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa a longer baseline query is not automatically a valid scheduled rule. One-minute evaluation has extra query restrictions, including `ingestion_time()`; consult the official reference before selecting it. A time picker used during exploration is not a stored rule setting. -8. Decide **Number of violations to trigger the alert** with the owner. If using several - violating evaluations, check the query's required datetime output and evaluation period +8. With your response team, set **Number of violations to trigger the alert**. If using + several violating evaluations, check the query's required datetime output and evaluation period against the official instructions. Inspect the **Preview** for healthy and qualifying periods. Do not assume missing data is a healthy evaluation. 9. Leave **Split by dimensions** unset unless separate incidents are required and reviewed. @@ -407,16 +404,16 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa **Severity**. Enter an **Alert rule name** and **Description** identifying source tenant, app, measure/units, threshold rationale, window, owner, and runbook. Use [the illustrated Details and Identity screen](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#configure-alert-rule-details). -12. Select the approved **Identity** for query evaluation. A **system-assigned managed +12. Choose the **Identity** that will run the query. A **system-assigned managed identity** has no permissions initially: create the rule with **Enable upon creation** - cleared, then have the access owner grant its identity reader/query access to the + cleared, then ask your Azure administrator to grant that identity reader/query access to the workspace through **Workspace > Access control (IAM)**. Allow role propagation before enabling it. If using a **user-assigned identity**, authorize it before selection. For **None**, record that query permissions follow the last editor. Check linked-storage policy requirements and identity restrictions in the official reference before choosing. 13. Review **Automatically resolve alerts** for stateful behavior and **Mute actions** where appropriate. Resolution timing depends on evaluation frequency; it is not immediate. - Confirm the owner understands when repeated notifications will be suppressed. + Make sure the receiving team knows when repeated notifications will be suppressed. 14. Select **Review + create** only after checking scope, query, measured units, time settings, permissions, actions, and costs. Keep the initial rule disabled until its identity and [validation checks](#validate-without-generating-provider-sends) are ready. To change it, @@ -424,18 +421,18 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa ### Monitor ingestion separately -1. Assign a collection owner independently of the failure/volume responder. Quiet alerts - can mean broken export, not healthy authentication. Review the +1. Decide who will check log collection as well as who responds to sign-in alerts. + Quiet alerts can mean broken export, not healthy authentication. Review the [log-alert guidance on missing data](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-types#log-alerts) before designing a freshness rule. -2. Record whether the source app should have regular traffic, including quiet hours and +2. Work out when the app normally has traffic, including quiet hours and maintenance. Compare **Entra > Sign-in logs** with the workspace after the measured delay. No user activity and stopped collection can look identical; do not enable staleness paging for an idle app without a documented expectation. -3. Have the query operator adapt the official +3. Work with your query maintainer to adapt the [ingestion-time/latency guidance](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/data-ingestion-time) - into a separate scoped freshness check. Require explicit handling of **no matching rows, - missing ingestion time, and stale latest arrival**, and verify each case. The linked + into a separate app-scoped freshness check. Test what happens with **no matching rows, + missing ingestion time, and stale latest arrival**. The linked reference is not a preconfigured Entra no-data alert. Do not hide an unresolved table or query error behind an empty-success fallback. 4. Create a separate rule using the same portal workflow, with its own freshness measure, @@ -445,7 +442,7 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa 5. Check **Monitor > Alerts > Alert rules**, the selected rule's health/errors and associated alerts, and the workspace's collection settings. Permission/query failures must be resolved separately from a stale-data incident. Inspect transformations, ingestion limits, and service - health with the owner; do not infer reduced abuse from missing evidence. + health with your workspace administrator; missing evidence doesn't mean less abuse. ### Validate without generating provider sends @@ -457,8 +454,8 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa Confirm the intended recipients actually receive it, including verification and spam-filter checks; access to read a group alone does not grant test permission. This tests notification routing, not log export or query evaluation. -2. Run the saved scoped query against existing approved records and compare it with the - associated Entra sign-ins. Check a healthy window, a qualifying window, an empty scope, +2. Run the saved, app-scoped query against existing records you're authorized to inspect. + Compare it with the associated Entra sign-ins. Check a healthy window, a qualifying window, an empty scope, and known ingestion delay. Confirm output shape/units agree with the rule's Measurement. 3. For an end-to-end check, create a **temporary nonproduction rule** with a restricted test action group. Use existing records within its lookback and an approved temporary @@ -466,9 +463,9 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa **Override query time range** consistently and stay within the alert scan limit. Do not lower a production threshold or route a test to production incident automation. 4. Authorize the test rule's evaluation identity and enable it. Observe a scheduled - evaluation and notification in **Monitor > Alerts**; record rule name, UTC time, measured - value, recipients, and investigation context. A successful interactive query under your - own identity does not prove the rule identity can read the workspace. + evaluation and notification in **Monitor > Alerts**. Keep the rule name, UTC time, + measured value, and recipients so your team can check the result. A successful query + under your own identity does not prove the rule identity can read the workspace. 5. Verify resolution when the test condition clears, allowing for stateful resolution timing. Disable/delete the temporary rule and remove temporary overrides. Reopen the intended rule to confirm its approved query, threshold, time settings, recipients, and enablement. @@ -476,9 +473,10 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa test tenant/app. Do not induce repeated wrong OTPs, alter production policy, bypass Easy Auth, or send live OTPs just to populate a report. An EPP evaluation does not validate delivery and is not guaranteed to create `SigninLogs` records. -7. Confirm validation is complete only after customer operators verify actual collection, - saved-query behavior, scheduled identity access, notification receipt, and cleanup. - This documentation has not executed Azure/Kusto queries or created/tested a customer's rule. +7. Before enabling production notifications, check that logs arrive, the saved query works, + the rule can read the workspace, and the right people receive the alert. Remove any + leftover test settings. These checks need to happen in your environment; this guide + hasn't run Azure/Kusto queries or created or tested your rules. ## 6. Build a sign-in Workbook @@ -490,7 +488,7 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa template for existing queries and visualizations. Do not select **Deploy to Azure** just to view a query; templates can create resources/delegation and require separate approval. In the GitHub file view, inspect the workbook's **serializedData** and its query definitions - with the query operator. These files are ARM deployment templates, not text to paste in full + with your query maintainer. These files are ARM deployment templates, not text to paste in full into Logs; extract/review only the needed query or use an already-approved deployed Workbook. 2. Check each chosen query's tables, tenant features, workspace/app filters, time settings, personal-data fields, and units against your actual records. A template named @@ -500,21 +498,21 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa **Edit** mode. Follow the [illustrated Workbook authoring guide](https://learn.microsoft.com/en-us/azure/azure-monitor/visualize/workbooks-create-workbook). Select **Add > Add query**, choose **Logs (Analytics)** and the verified workspace, - then use the approved saved/query-source content. + then use the query you reviewed and saved. 4. Select a **Visualization** matching the output, then **Run Query**. Use counts/result-code grids for breakdowns and a time chart only for a query with the appropriate time-series output. Check actual scope/time/units before selecting **Done editing**; the [Add queries instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/visualize/workbooks-create-workbook#add-queries) show the relevant controls. -5. Add text identifying source tenant/app, intended measure, arrival-delay expectations, - unknown/missing-data interpretation, and response owner. Label stored sign-in records +5. Add a short explanation of which tenant/app the view covers, what it counts, how long + logs take to arrive, what missing data means, and who to contact. Label sign-in records and authentication steps distinctly; an empty chart is not a healthy result. Include the separately reviewed freshness view. 6. If adding app/workspace/time parameters, bind them into **every relevant query** and verify that changing them changes the data as intended. A Workbook selector does not override a hard-coded filter automatically. Keep detailed IP/user-level views restricted. 7. Select **Save** and choose the approved subscription, resource group, location, and name. - Have another authorized operator open it and verify access and scope. Sharing a Workbook + Ask a teammate with log access to open it and check the filters. Sharing a Workbook does not grant access to the underlying logs. Workbooks visualize data; they do **not** create the scheduled alerts above or prove those alerts are enabled. @@ -524,7 +522,7 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa workspace, tenant/app scope, UTC window, measured value, and rule/collection health. Open the approved saved query for that period, then inspect the related Entra sign-in's **Basic info**, **Authentication Details**, and applicable policy results. -2. Review changed result codes with the identity-support owner. Separate user +2. Review changed result codes with your identity-support team. Separate user mistakes/interruptions, application releases, and policy changes from infrastructure failures or potential abuse. Escalate suspected compromise through the organization's security response process; a heuristic notification is not a confirmed fraud verdict. @@ -554,11 +552,12 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa 7. Inspect caps and transformations with the collection owner. They can remove evidence needed by a rule. Verify changes do not silently remove required fields/populations and update collection-health checks. Provider sending/billing remains a separate cost source. -8. Complete a restricted handover record with source tenant/app, workspace/export setting, - saved queries, measured baseline/delay, Workbook, alert rule/identity, action group, - thresholds/time settings, validation evidence, and collection/identity/security owners. - Assign privacy, retention, and cost-review owners plus escalation/maintenance procedures. -9. Have the receiving operator confirm they can reopen the queries and Workbook, inspect - rule health, receive an approved notification, and follow triage without generating - provider sends or changing policy. Leave no temporary test overrides active. Handover - is complete only after these **customer-side checks**, not merely publication of this guide. +8. Put the setup notes somewhere your team can find them without exposing them publicly. + Include the tenant/app, workspace and export setting, saved queries, normal traffic and + arrival delay, Workbook, alert identity/settings, action group, and test results. + Name the contacts for collection, identity support, security, privacy, retention, and costs, + along with escalation and maintenance arrangements. +9. Walk a teammate through opening the queries and Workbook, checking rule health, + receiving a test notification, and investigating an alert. They shouldn't need to send + an OTP or change authentication policy to do this. Remove any remaining temporary test + settings before handing over. From cced58d721a1df553b4c6a257f7974add98c06a6 Mon Sep 17 00:00:00 2001 From: Hou Chi Chan Date: Tue, 13 Oct 2026 13:38:02 -0700 Subject: [PATCH 5/8] docs: simplify Microsoft screenshot attribution Remove repeated permission wording and standalone Microsoft-only notice. Keep original screenshot source links and brief copyright attribution in captions; preserve root license and image bytes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f1451aca-6f84-41e6-9baf-cec42e36da6e --- docs/SIGN-IN-MONITORING.md | 9 ++- docs/images/sign-in-monitoring/NOTICE.txt | 67 ----------------------- 2 files changed, 4 insertions(+), 72 deletions(-) delete mode 100644 docs/images/sign-in-monitoring/NOTICE.txt diff --git a/docs/SIGN-IN-MONITORING.md b/docs/SIGN-IN-MONITORING.md index d34d8e8..6d57913 100644 --- a/docs/SIGN-IN-MONITORING.md +++ b/docs/SIGN-IN-MONITORING.md @@ -9,9 +9,6 @@ This guide does not deploy anything or change authentication policy. Each section links to Microsoft's existing queries and portal instructions, so you can start there and adapt them to your tenant rather than copy another set of examples. Choose alert thresholds from your own traffic. Portal labels can vary. -The two Microsoft screenshots below are unaltered public documentation examples, not your -tenant or evidence of a configured EPP integration. Used with permission from Microsoft. -Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompany the files. 1. Start with [the right tenant and access](#1-choose-the-tenant-and-permissions). 2. [Configure export](#2-export-the-required-log-categories) and @@ -129,7 +126,8 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa *Official Microsoft Entra admin center example from [Microsoft's diagnostic-settings instructions](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-configure-diagnostic-settings#how-to-access-diagnostic-settings). - Used with permission from Microsoft. This is not your tenant; menus and categories vary. + [Original screenshot](https://github.com/MicrosoftDocs/entra-docs/blob/927efa819a6f89a40b39b178d702b30f49b63f00/docs/identity/monitoring-health/media/howto-configure-diagnostic-settings/diagnostic-settings-start.png), + Copyright (c) Microsoft Corporation. This is not your tenant; menus and categories vary. Follow the numbered navigation above, not the example's breadcrumb. Visible risk categories do not establish that those features are available or licensed in an external tenant.* @@ -227,7 +225,8 @@ Their [source and license notices](images/sign-in-monitoring/NOTICE.txt) accompa *Official Microsoft Entra ID example from [Microsoft's sign-in activity-details instructions](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-in-log-activity-details#authentication-details). - Used with permission from Microsoft. This is not your sign-in or a delivery test. + [Original screenshot](https://github.com/MicrosoftDocs/entra-docs/blob/927efa819a6f89a40b39b178d702b30f49b63f00/docs/identity/monitoring-health/media/concept-sign-in-log-activity-details/sign-in-activity-details-authentication.png), + Copyright (c) Microsoft Corporation. This is not your sign-in or a delivery test. The example's Previously satisfied outcomes do not prove a new phone challenge or provider send. Your methods, policy results, timestamps, and portal layout can differ.* diff --git a/docs/images/sign-in-monitoring/NOTICE.txt b/docs/images/sign-in-monitoring/NOTICE.txt deleted file mode 100644 index 2aaae8a..0000000 --- a/docs/images/sign-in-monitoring/NOTICE.txt +++ /dev/null @@ -1,67 +0,0 @@ -Microsoft Entra monitoring screenshots - -Copyright (c) Microsoft Corporation. -Used with permission from Microsoft. - -These two files are unaltered copies of public Microsoft documentation screenshots. -They illustrate Microsoft Entra admin center and Microsoft Entra ID controls, not a -customer's tenant, deployed External Phone Provider configuration, or delivery result. -No Microsoft endorsement is implied. Product names and trademarks remain their owners'. - -Source repository: https://github.com/MicrosoftDocs/entra-docs -Source commit: 927efa819a6f89a40b39b178d702b30f49b63f00 -Retrieved and visually reviewed: 2026-10-13 - -diagnostic-settings-start.png -Source: -https://github.com/MicrosoftDocs/entra-docs/blob/927efa819a6f89a40b39b178d702b30f49b63f00/docs/identity/monitoring-health/media/howto-configure-diagnostic-settings/diagnostic-settings-start.png -Microsoft Learn context: -https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-configure-diagnostic-settings#how-to-access-diagnostic-settings -SHA-256: ed04ba296e34e9031e9b37e757d2c613ffc9a48f5cf790e4b96d8c9b2d4f66a3 - -sign-in-activity-details-authentication.png -Source: -https://github.com/MicrosoftDocs/entra-docs/blob/927efa819a6f89a40b39b178d702b30f49b63f00/docs/identity/monitoring-health/media/concept-sign-in-log-activity-details/sign-in-activity-details-authentication.png -Microsoft Learn context: -https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-in-log-activity-details#authentication-details -SHA-256: f9acf702fe5e6d7547260d5d7f2c402d2dd7ab4558d174680c8c718e32916e41 - -Reuse permission: -https://www.microsoft.com/en-us/legal/intellectualproperty/copyright/permissions -The Screenshots section expressly permits Microsoft product screenshots in -documentation and on websites under its stated conditions. These copies retain -the entire original images without modification. The required permission -statement appears above and in the guide's captions. -This specific screenshot-use permission is the primary reuse basis, not an -assumption that all Microsoft Learn media share one open-content license. - -Repository license: -https://github.com/MicrosoftDocs/entra-docs/blob/927efa819a6f89a40b39b178d702b30f49b63f00/LICENSE -The exact source repository's root LICENSE is the MIT License reproduced below, -including associated documentation files. No nested license/notice override was -found for these image paths. The source ThirdPartyNotices.md also refers to -CC-BY documentation licensing, inconsistently with that root LICENSE; these -copies do not rely on a general CC-BY license for Microsoft Learn media. -Microsoft's explicit screenshot permission is independently verified above. - -MIT License - -Copyright (c) Microsoft Corporation. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. From 9410a0edc2bea1e61f88c807d24016afc8a76ce1 Mon Sep 17 00:00:00 2001 From: Hou Chi Chan Date: Tue, 13 Oct 2026 13:54:32 -0700 Subject: [PATCH 6/8] docs: shorten sign-in monitoring to a six-step first-alert path Start with portal investigation and an early stopping point; move advanced setup, query, risk, collection, Workbook and data-management detail to optional reference sections. Preserve sources, anchor aliases, original screenshots and essential alert safety checks. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f1451aca-6f84-41e6-9baf-cec42e36da6e --- docs/SIGN-IN-MONITORING.md | 961 +++++++++++++++++-------------------- 1 file changed, 432 insertions(+), 529 deletions(-) diff --git a/docs/SIGN-IN-MONITORING.md b/docs/SIGN-IN-MONITORING.md index 6d57913..10a20a1 100644 --- a/docs/SIGN-IN-MONITORING.md +++ b/docs/SIGN-IN-MONITORING.md @@ -1,126 +1,75 @@ # Monitor Microsoft Entra sign-ins -Use this guide to find out why sign-ins fail, spot changes in traffic, and notify your team -when something needs attention. It covers **tenant identity monitoring**, separate -from [Function monitoring](MONITORING.md) and [Application Insights](APPLICATION-INSIGHTS.md). -EPP setup does **not** configure tenant log export, Workbooks, action groups, or sign-in alerts. -This guide does not deploy anything or change authentication policy. - -Each section links to Microsoft's existing queries and portal instructions, so you can -start there and adapt them to your tenant rather than copy another set of examples. -Choose alert thresholds from your own traffic. Portal labels can vary. - -1. Start with [the right tenant and access](#1-choose-the-tenant-and-permissions). -2. [Configure export](#2-export-the-required-log-categories) and - [confirm actual records](#3-confirm-arrival-and-schema). -3. [Choose a query and measure your baseline](#4-establish-the-baseline) before - [configuring notifications](#5-create-actionable-log-search-alerts). -4. [Build a Workbook for your team](#6-build-a-sign-in-workbook), then - [plan investigation and handover](#7-triage-privacy-retention-and-costs). - -## What these logs can and cannot tell you - -1. Use sign-in logs to investigate authentication to an application: result codes, - authentication steps, available policy outcomes, and identity/network context. - Treat counts as **stored sign-in records**, not unique customers, completed sessions, - provider sends, or delivery receipts. Several records can describe one authentication - sequence, including successive MFA outcomes. -2. Do not attribute every failed sign-in to a phone provider. Invalid passwords, - interrupted challenges, user cancellation, and policy rejection can all produce - non-success results. A successful sign-in can use an existing token claim without a new - phone challenge. Neither an SMS/Voice method label nor an MFA requirement proves EPP use. -3. Use the [Function monitoring queries](MONITORING.md#2-single-region-function-queries) - for endpoint execution and the - [runtime-specific log discovery](MONITORING.md#runtime-specific-log-discovery) for - available request context and provider acceptance. Use the provider's approved delivery - and billing reports for recipient delivery, send volumes, and charges. -4. Keep evaluation and live evidence separate. Both EPP request modes can return HTTP 200. - `SigninLogs` has no guaranteed EPP delivery-mode, provider-attribution, phone-delivery, - or provider-cost field. An endpoint evaluation is not guaranteed to create a user - sign-in record. Do not interpret a sign-in chart as a delivery test. - -## 1. Choose the tenant and permissions - -1. Identify the tenant where **user authentication** takes place. In the - [Microsoft Entra admin center](https://entra.microsoft.com), use **Settings > - Directories + subscriptions** to select it, then open its **Overview** and record the - **Tenant ID** privately. Do not assume this is the Function-hosting tenant. -2. Confirm whether this is a **workforce tenant**, including B2B guests, or an **external - tenant** for consumer/business-customer apps. Use the - [tenant feature comparison](https://learn.microsoft.com/en-us/entra/external-id/customers/concept-supported-features-customers) - with your tenant administrator. The export setup and feature availability differ. -3. Open **Entra ID > Monitoring & health > Sign-in logs** and select an existing sign-in - you're authorized to inspect for the application you want to monitor. In **Basic info**, check - **Application**, **Application ID**, **Resource**, the outcome, and time. The - [illustrated activity-details guide](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-in-log-activity-details#basic-info) - explains these fields. Record the application's **client ID**, not its Object ID. - It is not necessarily the endpoint `applicationId` in the EPP deployment summary. - Note the displayed time zone; use UTC when comparing it with other logs. -4. Choose the destination **subscription, resource group, workspace, and region** with - your Azure administrator and the people responsible for privacy and costs. An existing - workspace may be suitable; check before creating another one. You can choose to keep - Entra and Function logs together, but EPP setup does not make that connection for you. -5. For a **workforce tenant**, check the - [integration prerequisites](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-integrate-activity-logs-with-azure-monitor-logs#prerequisites). - General diagnostic settings require at least **Security Administrator** in the Entra - tenant, an Azure subscription, a prepared Log Analytics workspace, and appropriate - Azure access to the destination. If you still need a workspace, ask your Azure administrator - to follow the [workspace creation instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/quick-create-workspace). -6. For an **external tenant**, open the - [illustrated external-tenant setup guide](https://learn.microsoft.com/en-us/entra/external-id/customers/how-to-azure-monitor#prerequisites). - An external tenant cannot have an associated Azure subscription. The documented setup - uses the subscription in a **workforce tenant** and an Azure Lighthouse access path. - Arrange Azure RBAC **Owner** on that subscription and **Security Administrator or - Application Administrator** in the external tenant for the wizard. Users who configure - diagnostic settings still need at least **Security Administrator**. Do not move the - EPP subscription or change policy to imitate workforce setup. -7. Arrange read access separately. **Reports Reader** is the least privileged Entra role - for activity-log access in the admin center; see - [access requirements](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-access-activity-logs#prerequisites). - It does not grant Azure log access. Ask your Azure administrator to review - [workspace/table permissions](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/manage-access) - and grant appropriately scoped query access, such as **Log Analytics Reader**. - Try opening the workspace's **Logs** with the account you'll use to investigate sign-ins. -8. Verify licensing before selecting premium reports. Current - [monitoring licensing guidance](https://learn.microsoft.com/en-us/entra/fundamentals/licensing#microsoft-entra-monitoring-and-health) - lists sign-in and audit logs for Entra ID Free as well as P1/P2. That does not imply - entitlement to every Graph API, risk report, or Workbook feature. Azure collection, - retention, queries, alert evaluation, and notifications can incur separate charges. -9. Confirm whether risk reporting is actually available. The current - [external-tenant comparison](https://learn.microsoft.com/en-us/entra/external-id/customers/concept-supported-features-customers#general-feature-comparison) - lists **Microsoft Entra ID Protection as unavailable in external tenants**. In supported - workforce tenants, full [ID Protection capabilities](https://learn.microsoft.com/en-us/entra/id-protection/overview-identity-protection#license-requirements) - require P2 or an applicable entitlement. Do not purchase workforce P2 expecting it to - enable external-tenant risk detections, or read empty/hidden risk values as fraud clearance. -10. Before continuing, keep a private note of the **tenant and type, app client ID, and - workspace resource ID**. Agree who will maintain queries, configure alerts, and respond - to security concerns. Resolve any missing access or workspace approval before exporting logs. - -## 2. Export the required log categories +Start here to look up a failed sign-in. If you also want ongoing notifications, continue +through the six steps to create your first alert. The [optional reference](#optional-reference) +covers more advanced setup and investigation. + +**Sign-in logs show authentication outcomes, not OTP delivery.** A failed sign-in does not +automatically mean a phone-provider failure. Keep identity details private. EPP setup does +not export these logs or create alerts; the steps below are actions for your administrators, +not changes made by this guide. + +## 1. Choose your tenant and access + +1. Open the [Microsoft Entra admin center](https://entra.microsoft.com). In **Settings > + Directories + subscriptions**, select the tenant where your users sign in. It may differ + from the tenant hosting the Function. Note its **Tenant ID** from **Overview**. +2. Ask your tenant administrator for **Reports Reader**, the minimum role for viewing + activity logs. See Microsoft's [access requirements](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-access-activity-logs#prerequisites). + This role does not grant access to an Azure workspace. +3. Check whether you have a **workforce tenant** or an **external tenant** for customer apps. + If unsure, use the [tenant comparison](https://learn.microsoft.com/en-us/entra/external-id/customers/concept-supported-features-customers) + with your administrator. Both can use the portal investigation below, but external + tenants need a different export setup in Step 3. + +## 2. Find one sign-in + +1. Open **Entra ID > Monitoring & health > Sign-in logs**. Choose a date range and filter + to the application you're investigating. Open a record you're authorized to inspect. +2. In **Basic info**, check the **Application**, **Application ID**, **Resource**, outcome, + and time. Keep the application's **client ID**, not its Object ID, for later query filters. + This may not be the endpoint `applicationId` in your EPP deployment summary. + The [activity-details guide](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-in-log-activity-details#basic-info) + explains these fields. Note the displayed time zone; use UTC when comparing other logs. +3. Open **Authentication Details** to see the methods, step outcomes, and policy context. + Look for an interrupted challenge, policy rejection, or a step satisfied by a previous + authentication. Microsoft's [Authentication Details explanation](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-in-log-activity-details#authentication-details) + helps interpret the result. -### Prepare the external-tenant access path + ![Microsoft Entra ID sign-in Activity Details with Authentication Details selected and two Previously satisfied steps marked true](images/sign-in-monitoring/sign-in-activity-details-authentication.png) -1. If monitoring a **workforce tenant**, skip this subsection. If an external tenant is - already integrated, check its destination and access with the administrator rather than - rerunning setup. Otherwise, open **Entra ID > Monitoring & health > Diagnostic settings** - in the external tenant and select **Start set up**. -2. Follow the official - [wizard screenshots and instructions](https://learn.microsoft.com/en-us/entra/external-id/customers/how-to-azure-monitor#set-up-the-azure-lighthouse-configuration-in-the-wizard). - Sign in to the **workforce tenant** for the approved subscription. Select the subscription - and resource group, specify the workspace name and region, and select **Next**. -3. In **Select user access**, choose the external-tenant users/groups who need access and - the documented Azure roles agreed with your administrator. Review the delegation carefully. - The wizard's roles are not a grant of all alert-management or role-assignment permissions. -4. At **Review and create**, confirm destination, region, users/groups, roles, and charges. - Select **Create** only after approval. Wait for confirmation, select **Done**, and - continue to diagnostic settings. Keep the destination identifiers with your setup notes. - -### Select and save the export - -1. In the **source tenant's** Entra admin center, open **Entra ID > Monitoring & health > - Diagnostic settings**. If you need help finding the screen, see - [access diagnostic settings](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-configure-diagnostic-settings#how-to-access-diagnostic-settings). - Check existing settings first, and speak to whoever maintains them before making changes. + *Official Microsoft Entra ID example from + [Microsoft's activity-details instructions](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-in-log-activity-details#authentication-details). + [Original screenshot](https://github.com/MicrosoftDocs/entra-docs/blob/927efa819a6f89a40b39b178d702b30f49b63f00/docs/identity/monitoring-health/media/concept-sign-in-log-activity-details/sign-in-activity-details-authentication.png), + Copyright (c) Microsoft Corporation. This is not your sign-in or a delivery test. + Previously satisfied does not prove a new phone challenge or provider send. + Your methods, policy results, timestamps, and portal layout can differ.* + +4. Use the error code and reason with Microsoft's + [sign-in troubleshooting guidance](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-troubleshoot-sign-in-errors). + If the issue points to the endpoint or provider, follow the + [Function monitoring guide](MONITORING.md#runtime-specific-log-discovery) separately. + +**Only investigating one problem? You can stop here.** You don't need to export logs, create +a workspace, or incur additional Azure Monitor collection costs for this portal-only path. +Continue if your team wants ongoing alerts or longer-term analysis. + +## 3. Export logs for ongoing monitoring + +1. Agree on a workspace, region, budget, and person responsible for the alerts. + For a **workforce tenant**, follow the + [integration prerequisites](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-integrate-activity-logs-with-azure-monitor-logs#prerequisites): + at least **Security Administrator** in Entra, an Azure subscription, a prepared workspace, + and suitable Azure access. If needed, your Azure administrator can + [create a workspace](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/quick-create-workspace). +2. For an **external tenant**, first follow the + [external-tenant setup instructions](https://learn.microsoft.com/en-us/entra/external-id/customers/how-to-azure-monitor#prerequisites), + not the workforce setup above. They establish access to a workspace in a workforce + subscription. Return here once that access is ready; [extra setup detail](#prepare-the-external-tenant-access-path) + is available below. +3. In the **source tenant**, open **Entra ID > Monitoring & health > Diagnostic settings**. + Check existing settings before changing them. Select **Add diagnostic setting**, or + edit an existing setting with its maintainer's agreement. ![Microsoft Entra admin center showing Monitoring and health, Diagnostic settings, and Add diagnostic setting highlighted](images/sign-in-monitoring/diagnostic-settings-start.png) @@ -128,435 +77,389 @@ Choose alert thresholds from your own traffic. Portal labels can vary. [Microsoft's diagnostic-settings instructions](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-configure-diagnostic-settings#how-to-access-diagnostic-settings). [Original screenshot](https://github.com/MicrosoftDocs/entra-docs/blob/927efa819a6f89a40b39b178d702b30f49b63f00/docs/identity/monitoring-health/media/howto-configure-diagnostic-settings/diagnostic-settings-start.png), Copyright (c) Microsoft Corporation. This is not your tenant; menus and categories vary. - Follow the numbered navigation above, not the example's breadcrumb. Visible risk categories - do not establish that those features are available or licensed in an external tenant.* - -2. Select **Add diagnostic setting**, or edit an existing setting if its maintainer has agreed. - Enter a recognizable name for a new setting. Select **SignInLogs** for interactive - user authentication. Add **AuditLogs** only if directory-change investigation is also - required; audit events are not sign-in outcomes. -3. Use the [category descriptions](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-diagnostic-settings-logs-options) - to choose any further sources. Non-interactive user, service-principal, and managed-identity - sign-ins are separate categories and populations. They use `AADNonInteractiveUserSignInLogs`, - `AADServicePrincipalSignInLogs`, and `AADManagedIdentitySignInLogs`, respectively. - Keep their baselines separate from interactive `SigninLogs`. Do not select every category - just to make a chart populate. -4. Check the category picker in **your tenant**. A category description or workforce feature - is not a promise of data in an external tenant. Selecting **SignInLogs** does not enable - the separate **RiskyUsers** or **UserRiskEvents** categories. Provider-side OAuth evidence - can reside in the provider's tenant and require its administrator's assistance. -5. Under **Destination details**, select **Send to Log Analytics workspace**, then choose - the approved **Subscription** and **Log Analytics workspace**. For an external tenant, - use the access set up above. Check the destination against your setup notes. + Follow the navigation above, not the example's breadcrumb. Visible risk categories do + not establish availability or licensing in an external tenant.* + +4. Name the setting and select **SignInLogs** for interactive user sign-ins. Under + **Destination details**, select **Send to Log Analytics workspace** and choose your + subscription and workspace. Select **Save**, reopen the setting, and check the destination. The [illustrated export instructions](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-integrate-activity-logs-with-azure-monitor-logs#send-logs-to-azure-monitor) - show the category and destination controls. -6. Select **Save**, reopen the setting, and confirm its **selected categories and destination**. - Note when you enabled export and who maintains it. This setting belongs to Entra, - not the Function App; Function diagnostic settings/Application Insights do not perform - this export. Do not expect a backfill of all historical portal sign-ins. -7. Check that the setting still points to the right workspace and includes the sign-in - category you selected, without changing another integration. Next, check for records: - saving the setting alone doesn't tell you whether logs have arrived. - -## 3. Confirm arrival and schema - -1. Open **Azure portal > Log Analytics workspaces > your destination workspace > Logs**. - For an external tenant's workforce-hosted workspace, switch to the subscription-owning - directory as necessary. Check the workspace name/query scope before running anything. - Use the [illustrated Logs scope tutorial](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#open-log-analytics). - Its demo environment is for learning controls, **not** verification of your tenant's data. -2. Select **Tables** in the left pane and find **SigninLogs**. Expand the table to inspect - its columns and types, following - [View table information](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#view-table-information). - That tutorial illustrates `AppRequests`; select **SigninLogs** in your workspace instead. - Compare the actual columns with the official - [SigninLogs schema](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/signinlogs#columns). -3. In the table's controls, use **Run** to preview records, or select it through - [Simple mode > Select a table](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-simple-mode#get-started-in-simple-mode). - Choose a **Time range** that covers activity after export was saved. Limit the displayed - records and use only an account authorized to read them; a preview can contain - personal data. Do not use the Application Insights `requests`/`traces` context for Entra logs. -4. Allow for initial export delay. The - [Microsoft External ID monitoring repository](https://github.com/microsoft/external-id-azure-monitor) - describes about 45 minutes after setup, while the - [general diagnostic-setting guidance](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-configure-diagnostic-settings#basic-process) - allows up to three days for initial arrival. These are setup allowances, not a steady-state - latency SLA. If no table/records appear, compare export start time, source tenant, destination, - category, access, and expected portal sign-ins before escalating. -5. Expand a returned row using its **chevron**, as shown in - [Expand and sort records](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#expand-and-sort-records). - Check `AADTenantId` and `AppId` against the source tenant and application's client ID. - Do not substitute the app's Object ID, provider API ID, or workspace ID. - The standard `TenantId` column is the **workspace ID**, not the source Entra tenant ID. -6. To narrow exploration without writing a new query, use **Simple mode > Add > column filter** - for `AADTenantId` and `AppId`, then enter/select the IDs you checked above. See the illustrated - [column-filter instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-simple-mode#filter-by-column). - Apply source/app filters **before aggregation**. Switch to **KQL mode** and confirm the - generated query contains them; a Results-grid search or column-header filter is not an - enduring query/alert filter. -7. Check `ResultType`, `ResultDescription`, `CreatedDateTime`, and `TimeGenerated`. - The schema defines `ResultType` as a **string**: zero indicates success, populated nonzero - values are sign-in error/result codes, and missing/empty values need investigation. - These are not provider/Function HTTP statuses. Review the corresponding portal record's - **Basic info** with the - [sign-in error troubleshooting instructions](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-troubleshoot-sign-in-errors). -8. Check which timestamps you're comparing before choosing alert windows. `CreatedDateTime` - is sign-in initiation time in UTC; `TimeGenerated` is the timestamp used for workspace time filters. - Work with whoever maintains your queries to use the - [ingestion-latency reference](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/data-ingestion-time) - and [standard-column timing guidance](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-standard-columns#_timereceived-column) - to measure arrival delay against **SigninLogs**, with your tenant/app scope. Those references - are generic, not a ready-made Entra latency monitor. Note the measured delay and any - missing timestamps; do not confuse ingestion time with authentication or delivery latency. -9. You should now be able to find records for the right tenant and app, understand their - fields, and allow for arrival delay. If the table can't be found, investigate collection - and access rather than treating that as a healthy result. If the table exists but your - app has no records, compare with **Entra > Sign-in logs** and ask the workspace administrator - to check transformations and ingestion limits before you build alerts. + show these controls. +5. Allow time for records to arrive. Initial export is not immediate and does not backfill + all portal history. Microsoft describes about 45 minutes in its + [External ID monitoring repository](https://github.com/microsoft/external-id-azure-monitor) + and allows up to three days in the + [general setup guidance](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-configure-diagnostic-settings#basic-process). + These are initial setup allowances, not an ongoing latency SLA. + +## 4. Check your data and choose a query + +1. Open **Azure portal > Log Analytics workspaces > your workspace > Logs** with an account + that has workspace query access, such as **Log Analytics Reader**. In **Tables**, find + **SigninLogs**, expand its columns, and preview recent records. The + [Logs tutorial](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#view-table-information) + shows the controls using `AppRequests`; choose **SigninLogs** in your own workspace. +2. Check `AADTenantId` and `AppId` against your source tenant and app client ID. + Compare the columns with the [SigninLogs schema](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/signinlogs#columns). + No matching records is **not** a healthy result: check the destination, time range, + category, access, and portal sign-ins before continuing. +3. Open Microsoft's [Failed Signin reasons query](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/queries/signinlogs#failed-signin-reasons). + In **KQL mode**, copy it from that source and filter to your `AADTenantId` and `AppId` + **before summarizing**. Ask someone familiar with KQL to review the edits. Check the + string type of `ResultType` and handle empty codes separately; these are authentication + codes, not provider HTTP statuses. [Query adaptation details](#4-establish-the-baseline) + explain the filters and other official query choices. +4. Choose an observation window with the receiving team, then **Run** that same calculation + across normal, peak, and quiet periods in a representative business cycle. Read `Count` + and the result codes, not the number of summary rows. Allow for measured ingestion delay; + choose a failure-count threshold for that window, not a whole week's total. There is no + universal threshold; the source query is not a turnkey EPP or fraud detector. +5. Select **Save > Save as query** and choose the agreed query pack. Saving needs + **Log Analytics Contributor**; ask an authorized teammate if you only have read access. + See [saving queries](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/save-query). + Keep the filters, count units, baseline, and chosen threshold with your team's setup notes. + +You now have one scoped query to reuse for the first alert. Leave rate, volume, and +IP-based detection for [later](#more-alert-types), once you understand this baseline. + +## 5. Create your first alert + +1. Check [alert permissions](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#prerequisites): + read access to the workspace, write access to the rule's resource group, and read access + to its action group. Creating groups or assigning roles requires additional permissions. + In **Azure portal > Monitor > Alerts > Create > Alert rule**, select your **Log Analytics + workspace** as **Scope**, not the Function or app registration. +2. On **Condition**, choose **Custom log search**, paste the saved query, and select **Run**. + Check **Preview**, then **Continue Editing Alert**. Follow the + [illustrated condition instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#configure-alert-rule-conditions). + This is a scheduled log search alert, not an Azure Activity Log alert; check that your + table plan supports the query and rule. +3. For **Failed Signin reasons**, set **Measure** to **Calculation of a numeric column**, + choose `Count`, and use **Total** if you want the total across the result-code groups. + Leave **Split by dimensions** unset for this first combined alert. Don't count summary + rows as failures. Set **Static**, the **Operator**, and **Threshold value** from Step 4. +4. Set **Aggregation granularity (window size)** and **Frequency of evaluation** to match + the team's observation window, ingestion delay, response needs, and budget. Review + **Override query time range** with the query's time filter; alert scans are limited to + **48 hours**. Start with a single violating evaluation; if you need several, review the + [required query output and evaluation settings](#query-identity-and-rule-options) first. + Review healthy and qualifying periods in Preview. Keep missing-data expectations separate from failure counts; + [collection-health guidance](#monitor-ingestion-separately) explains why. +5. On **Actions**, select or create an **action group** for the receiving team. Use the + [action-group instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/action-groups#create-in-the-azure-portal) + to configure email/push or incident routing and complete recipient verification. + On **Details**, set the rule's name, description, severity, region, and resource group. +6. Choose the query **Identity**. For a **system-assigned managed identity**, clear + **Enable upon creation**, create the rule disabled, and have your Azure administrator + grant it reader/query access to the workspace. Wait for role propagation before enabling. + An interactive query working under your account doesn't prove the rule can read logs. + Review **Automatically resolve alerts** and [identity options](#query-identity-and-rule-options) + before **Review + create**. Keep the rule disabled until ready for the test below. + +## 6. Test, then hand over + +1. Save the action group, open it, and select **Test**. Choose the notification receivers + and wait for the result; also check that the team receives the message. Microsoft's + [testing instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/action-groups#test-an-action-group-in-the-azure-portal) + cover failures and test permissions. This checks routing, not the sign-in query. +2. Test the query and a **temporary nonproduction rule** against existing records you're + allowed to inspect. Use a restricted test group and a temporary condition those records + satisfy. Check the query's window and portal override together. Verify the scheduled + alert and its later resolution, then remove the temporary rule/settings. See the + [full safe-test procedure](#validate-without-generating-provider-sends). +3. Don't generate live OTPs, repeated wrong codes, or production policy changes to populate + a chart. If records are insufficient, use an approved **non-phone test sign-in** in a + test tenant/app. An EPP evaluation does not guarantee a sign-in record or prove delivery. +4. Before enabling ongoing notifications, check that logs arrive, the rule identity has + access, the measurement matches your baseline, and the right people receive alerts. + Leave a teammate the query, rule, workspace, action group, settings, and support contacts. + Arrange a check for [missing logs](#monitor-ingestion-separately), not just sign-in failures. + +That's the first-alert path. These checks happen in your environment; this guide hasn't +run Azure/Kusto queries or configured your monitoring. + +## Optional reference + +Use these sections when you need more than the first alert: [tenant setup and access](#1-choose-the-tenant-and-permissions), +[query details](#4-establish-the-baseline), [other alert types](#more-alert-types), +[collection gaps](#monitor-ingestion-separately), [Workbooks](#6-build-a-sign-in-workbook), +and [triage, retention, and costs](#7-triage-privacy-retention-and-costs). + + + +### Understand the evidence + +1. Counts represent **stored sign-in records**, not unique customers, completed sessions, + or sends. Several records can describe one authentication sequence. A successful sign-in + can use an existing token claim without a phone challenge. +2. Invalid passwords, interrupted challenges, cancellation, and policy rejection can all + cause non-success results. Neither an SMS/Voice label nor an MFA requirement identifies + the provider. `SigninLogs` has no guaranteed EPP delivery-mode, provider-attribution, + phone-delivery, or provider-cost field. +3. Use [Function request queries](MONITORING.md#2-single-region-function-queries) and + [Application Insights](APPLICATION-INSIGHTS.md) for endpoint execution. Use the provider's + delivery and billing reports for recipient delivery and charges. Evaluation and live + Function requests can both return HTTP 200; neither proves handset receipt. + + + +### Tenant setup, access, and licensing + +1. Entra roles and Azure RBAC are separate. **Reports Reader** lets you view portal activity; + **Security Administrator** is needed for general diagnostic settings. Review + [workspace/table access](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/manage-access) + separately for queries. An external-tenant delegation does not grant every alert-management + or role-assignment operation in the subscription-owning workforce tenant. +2. Check current [monitoring licensing](https://learn.microsoft.com/en-us/entra/fundamentals/licensing#microsoft-entra-monitoring-and-health): + sign-in/audit logs are listed for Entra ID Free and P1/P2, but Graph APIs, premium reports, + risk features, and Workbook features can have other requirements. +3. The [external-tenant feature comparison](https://learn.microsoft.com/en-us/entra/external-id/customers/concept-supported-features-customers#general-feature-comparison) + currently lists **ID Protection as unavailable in external tenants**. Full supported + workforce [ID Protection capabilities](https://learn.microsoft.com/en-us/entra/id-protection/overview-identity-protection#license-requirements) + require P2 or an applicable entitlement. Don't buy workforce P2 expecting it to enable + external-tenant risk detections. -### Inspect authentication steps safely +### Prepare the external-tenant access path -1. For an existing relevant sign-in, open **Entra ID > Monitoring & health > Sign-in logs > - selected record > Authentication Details**. Use the official - [Authentication Details screenshot and explanation](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-in-log-activity-details#authentication-details) - to read the step sequence, method, outcome, and policy context. +1. An external tenant cannot have an associated Azure subscription. Follow the + [illustrated wizard](https://learn.microsoft.com/en-us/entra/external-id/customers/how-to-azure-monitor#set-up-the-azure-lighthouse-configuration-in-the-wizard) + for a workspace in a **workforce tenant** and Azure Lighthouse access. The prerequisites + include Azure RBAC **Owner** on the subscription and **Security Administrator or + Application Administrator** in the external tenant. Users configuring diagnostic settings + still need **Security Administrator**. +2. If already integrated, review the destination and access rather than repeating setup. + Otherwise select **Start set up** from external-tenant **Diagnostic settings**. + Sign in to the workforce tenant, select subscription/resource group, and specify workspace + name and region. In **Select user access**, choose the agreed users/groups and Azure roles. +3. Review the delegation, destination, region, permissions, and costs before **Create**. + Wait for confirmation, select **Done**, then configure export as in Step 3. + Don't move the EPP subscription or alter authentication policy to imitate workforce setup. + + + + +### Choose additional export categories + +1. Follow the [diagnostic-settings navigation](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-configure-diagnostic-settings#how-to-access-diagnostic-settings) + and [category descriptions](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-diagnostic-settings-logs-options) + when expanding the first export. **AuditLogs** describes directory changes, not sign-in + outcomes. Add it only if required. +2. Non-interactive user, service-principal, and managed-identity sign-ins use + `AADNonInteractiveUserSignInLogs`, `AADServicePrincipalSignInLogs`, and + `AADManagedIdentitySignInLogs`. Keep their populations/baselines separate from interactive + `SigninLogs`. Check categories actually available in your tenant. +3. **SignInLogs** does not enable **RiskyUsers** or **UserRiskEvents**. Provider OAuth logs + may be in the provider's tenant and need its administrator's help. Function diagnostic + settings and Application Insights are separate pipelines, not Entra export configuration. + + + +### Inspect schema and arrival delays + +1. Check your workspace [query scope](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#open-log-analytics), + not the tutorial's demo environment or Application Insights `requests`/`traces` context. + Use [Simple mode's table selector](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-simple-mode#get-started-in-simple-mode) + if you prefer a point-and-click preview. +2. Expand a row using its [chevron](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#expand-and-sort-records). + `AADTenantId` is the source directory; standard `TenantId` is the **workspace ID**. + `AppId` is the app client ID, not an Object ID or provider API ID. +3. `ResultType` is a **string**: zero indicates success; populated nonzero values are + authentication codes. Keep empty values as unknown. `CreatedDateTime` is sign-in initiation + in UTC; `TimeGenerated` is the workspace log timestamp. They are not ingestion time. +4. Adapt the [ingestion-latency reference](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/data-ingestion-time) + and [standard-column timing guidance](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-standard-columns#_timereceived-column) + to your `SigninLogs` scope to measure delay, including missing timestamps. + These generic examples are not a ready-made Entra monitor or delivery-latency measure. - ![Microsoft Entra ID sign-in Activity Details with Authentication Details selected and two Previously satisfied steps marked true](images/sign-in-monitoring/sign-in-activity-details-authentication.png) +### Inspect authentication steps safely - *Official Microsoft Entra ID example from - [Microsoft's sign-in activity-details instructions](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-in-log-activity-details#authentication-details). - [Original screenshot](https://github.com/MicrosoftDocs/entra-docs/blob/927efa819a6f89a40b39b178d702b30f49b63f00/docs/identity/monitoring-health/media/concept-sign-in-log-activity-details/sign-in-activity-details-authentication.png), - Copyright (c) Microsoft Corporation. This is not your sign-in or a delivery test. - The example's Previously satisfied outcomes do not prove a new phone challenge or - provider send. Your methods, policy results, timestamps, and portal layout can differ.* - -2. Check whether the step was satisfied by an existing token claim or a previous - authentication. A method named SMS/Voice is not a provider ID or delivery receipt. - Keep the sign-in's overall outcome separate from an individual step's outcome. -3. For an existing shared method report, review the official - [MFA Workbook template](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/mfaWorkbookDeployment.json) - with whoever maintains your queries. Its current queries use **AuditLogs**, not `SigninLogs` - authentication-step arrays. They need the corresponding export and recorded audit activity; - do not replace the table name or treat that report as the full sign-in step sequence. - For a `SigninLogs` step report, have the operator review the actual `AuthenticationDetails` - column separately: it is documented as a string containing step data, not a top-level - dynamic object. An adapted query must handle the parsed array shape, empty/invalid/missing - data, and nullable step outcomes explicitly. -4. Check the adapted report for coverage gaps and labels. Expanding an array counts - **authentication steps**, not sign-ins. Missing steps do not establish success or failure. - Keep `authenticationMethodDetail` and full raw payloads out of shared reports; they can - include phone identifiers or other personal data. -5. Compare a few report entries with the corresponding portal records. The methods and - outcomes should agree; use the report to understand authentication, not to prove delivery. - -## 4. Establish the baseline - -1. Open the official [SigninLogs query collection](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/queries/signinlogs). - Choose the relevant named query rather than copying an unrelated tutorial's table: - **Failed Signin reasons** for result-code distribution, **Failed login Count** for - failure counts by resource, or **Signin Locations** for successful/failed counts by location. - You'll need to set your app, tenant, time window, and alert thresholds in these examples. -2. In your workspace's **Logs**, switch to **KQL mode**. Copy the selected query from its - official source into the editor. Alternatively, use the **Queries** pane if that query - is available there. Filter to your `AADTenantId` and `AppId` **before summarizing**, - following the [filtering tutorial](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#apply-multiple-query-filters). - If you're new to KQL, ask someone familiar with it to review the edits. Don't read tenant-wide - results as if they describe one customer app. -3. Compare the query with the **actual string type of `ResultType`**. The official collection - includes examples with numeric-looking comparisons; the operator must ensure the chosen - comparison matches the documented type and separately handles empty/missing codes. - Read nonzero result codes in their authentication context, not as incorrect OTPs by default. - The catalog also includes user names/identifiers in some outputs and a **Failed MFA challenge** - query limited to one code. Review purpose and privacy: it is not a complete MFA/CYOT failure - detector. Remove unnecessary personal fields before sharing a saved report. -4. Choose a representative business cycle using **Time range** and any query time filter. - Include peak/quiet hours, releases, and approved tests. Use the illustrated - [time-range controls](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#set-the-query-time-range). - Confirm the effective range on rerun, not just the picker label. -5. Select **Run**. Inspect **Results** and, where helpful, **Chart**. Identify the output's - numeric count column and grouping; do not confuse the number of summary rows displayed - with the number of sign-in records counted. The **Show** limit can cap displayed results. - Avoid treating a truncated preview or browser-side grouping as a complete baseline. -6. Keep the query and your findings together: what it counts, how it groups results, - normal and peak traffic, common non-success codes, missing data, and arrival delay. - Distinct users, sign-in records, and authentication steps are different measures; - several records can belong to one authentication sequence. -7. With the team receiving alerts, decide what change is worth a notification and what - they would investigate. Base thresholds on this traffic, including a minimum volume - for rate rules and allowances for quiet hours and maintenance. There isn't one useful - threshold for every app. The official count queries don't automatically calculate a - failure rate, detect source-IP abuse, or check collection freshness. -8. Select **Save > Save as query**, following - [saving Azure Monitor queries](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/save-query). - Enter the name and select the approved subscription/query pack; review the proposed default - pack before creating a new resource. Saving requires **Log Analytics Contributor**; - if you only have read access, ask someone with that permission to save it. - Share its location with a teammate who has log access and check that they can reopen - it with the same filters and result columns before you use it in a rule. - -## 5. Create actionable log search alerts +1. Compare report entries with **Authentication Details** in the portal. Token claims or + previous authentication can satisfy a step; distinguish the step outcome from the whole sign-in. +2. Microsoft's [MFA Workbook template](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/mfaWorkbookDeployment.json) + currently queries **AuditLogs**, not `SigninLogs` authentication-step arrays. It needs + corresponding audit export/activity. Don't substitute tables or read it as a full step sequence. +3. A `SigninLogs` step report must handle `AuthenticationDetails` as the documented string + containing parsed array data, with empty/invalid/missing data and nullable outcomes. + Array expansion counts **steps**, not sign-ins. Missing steps aren't success or failure. + Keep `authenticationMethodDetail` and raw payloads out of shared views; they can contain + phone identifiers and other personal data. + + + +### Adapt official queries + +1. In the [SigninLogs query collection](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/queries/signinlogs), + **Failed Signin reasons** groups by code/reason; **Failed login Count** counts failures by + resource; **Signin Locations** groups success/failure by location. Pick the measure you need. + Some examples contain personal fields or limit MFA failures to one code; none is a + complete CYOT/provider-failure detector. +2. Add your source tenant/app filters **before aggregation**. Use the + [filtering tutorial](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#apply-multiple-query-filters) + or [Simple mode column filters](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-simple-mode#filter-by-column), + then switch to KQL to check them. Results-grid searches/header filters don't persist + as alert-query filters. Review numeric-looking code comparisons against the string schema. +3. Use the [time-range controls](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial#set-the-query-time-range) + with any query time filter and verify the effective range. Preview **Show** limits and + browser-side grouping can hide data; don't mistake them for the full baseline. +4. Save the reviewed query and share its location with a teammate who has log access. + Check that they get the same filters and columns. Distinct-user, record-count, and step + measures differ; note unknown-code handling and any exclusions alongside the query. + + + + +### Query identity and rule options + +1. Use the [scope screen](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#configure-the-scope-of-the-alert-rule) + and [Details/Identity instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#configure-alert-rule-details) + for the workspace rule. A **user-assigned identity** needs access before selection. + With **None**, query permissions follow the last editor. Review linked-storage policy + and identity restrictions before choosing. +2. Measurement depends on output: **Table rows / Total** suits unsummarized matching records; + a summarized query needs its numeric column. Sum and maximum of groups mean different things. + A greater-than-zero row condition is only suitable when the query returns **qualifying + incidents**, not an unconditional summary. +3. Review window, frequency, query time filter, and **Override query time range** together. + Overlapping windows can observe records repeatedly; late arrivals can be missed. + One-minute evaluation has query restrictions, including `ingestion_time()`. + Multiple violations require the documented datetime output/evaluation period. +4. **Split by dimensions** creates separate series/incidents and can raise costs/expose data. + Avoid high-cardinality IP/user/request/correlation identifiers without a specific need. + An unsplit workspace alert is a workspace incident; put app/scope in its description/runbook. +5. In a new action group, complete **Basics**, **Notifications**, and any **Actions**, then + **Review + create > Create**. Return to the rule and select the saved group. + Check processing region, recipients, required verification, and **Common alert schema** + where applicable. Keep security results restricted; don't attach automatic policy changes + to a heuristic. +6. **Automatically resolve alerts** makes the rule stateful; resolution timing depends on + frequency. Review **Mute actions** with the receiving team. Edit an existing rule through + **Monitor > Alerts > Alert rules > selected rule > Edit**. + +### More alert types + +These are optional additions after the first count alert is working. Each needs its own +reviewed query, baseline, and response plan. ### A. Elevated non-success rate -1. Begin with [Failed Signin reasons](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/queries/signinlogs#failed-signin-reasons) - to review **which result codes changed**. Use a reviewed failure-count rule first if that - meets the requirement; this official query is not a complete failure-rate alert. -2. If you need a **rate** rule, work with your query maintainer to return - failures and the corresponding total for the **same tenant, app, population, and window**, - with agreed handling of unknown codes and minimum traffic. Review healthy/empty windows - and denominator coverage before choosing the alert's numeric percentage column. -3. Note any excluded codes and monitor them separately. Route these alerts to the team - troubleshooting authentication; a change in non-success rate alone doesn't identify - a phone-provider outage. +1. Use failure counts first if they answer the question. A rate requires failures and + total traffic for the **same tenant, app, population, and window**, with unknown-code + handling and a minimum traffic level. The official count query does not calculate this rate. +2. Check denominator coverage in healthy and empty windows before choosing a numeric rate + column/threshold. Document exclusions and monitor them separately. Route to authentication + support, not automatic provider-outage classification. ### B. Unusual sign-in volume 1. Review the [authentication Workbook template](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/authenticationsWorkbookDeployment.json) - for existing sign-in traffic visualizations and query definitions. Treat it as source to - review, **not** an instruction to deploy the entire template. -2. Choose a traffic query with your query maintainer and check that it returns - a record count for the intended `SigninLogs` tenant/app/time window. The official - **User count per Application** query counts distinct users, not total sign-in records; - do not substitute that measure without changing the monitoring objective. -3. Set a volume limit from the agreed baseline and routing capacity. Investigate campaigns, - releases, clients, retries, and collection changes as possible causes. Sign-in volume is - **not OTP-send volume, SMS-pumping evidence, or provider spend**. + for traffic queries, then adapt one to your scope. **User count per Application** measures + distinct users, not sign-in record volume. +2. Choose the limit from normal traffic and response capacity. Campaigns, releases, retries, + clients, and collection changes can explain spikes. This is not OTP-send volume, + SMS-pumping evidence, or provider spend. ### C. Potential abuse from a source IP 1. Use [Signin Locations](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/queries/signinlogs#signin-locations) - and the [user-behavior Workbook template](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/userBehaviourWorkbookDeployment.json) - as investigation starting points. Neither is a ready-made source-IP fraud alert for EPP. -2. If an IP-based rule would help, ask your security team to review which `IPAddress`, - `UserId`, and `ResultType` values are actually present and choose the grouping and - threshold for your tenant/app. Check unknown users, absent IPs, approximate distinct counts, - distributed attempts, and expected shared-network activity before publishing it. -3. Restrict IP-bearing results and notifications to the security team. NAT, VPNs, mobile - networks, and proxies can cause false positives; IP geolocation does not prove a person's - location. Do not automate blocking, disable a provider/account, or change authentication - policy solely on a volume/IP heuristic. -4. Where licensed workforce ID Protection is supported, use its - [risk investigation instructions](https://learn.microsoft.com/en-us/entra/id-protection/howto-identity-protection-investigate-risk) - with the security owner. Check actual `RiskLevelDuringSignIn`, `RiskLevelAggregated`, - `RiskState`, and `RiskDetail` where available. Findings can arrive asynchronously; - empty, none, or hidden values do not clear fraud. Do not promise these detections - in an external tenant because a template is named "risk detection." - -### Configure the rule in the portal - -1. The person creating the rule needs **read access to the workspace**, **write access to - the rule's resource group**, and **read access to the action group**. Check the - [official alert prerequisites](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#prerequisites). - Creating an action group or assigning roles needs separate permissions. - External-tenant operators must use approved Azure RBAC in the subscription-owning - workforce tenant; Entra roles or Lighthouse delegation alone do not grant every operation. -2. Open **Azure portal > Monitor > Alerts > Create > Alert rule**. On **Scope**, choose - your destination **Log Analytics workspace** and select **Apply**, not the Function App or - app registration. Compare with the - [illustrated scope screen](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#configure-the-scope-of-the-alert-rule). -3. On **Condition**, select **Custom log search**. Paste the **saved, app-scoped query** - selected above. Select **Run**, inspect **Preview**, then **Continue Editing Alert**. - Use the [illustrated condition/measurement instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#configure-alert-rule-conditions). - Use a scheduled **log search alert**, not an Azure Activity Log alert. Check the workspace's - **Tables** settings for the table plan; confirm the selected plan supports the query/rule. -4. Set **Measurement** to match what the query returns. For unsummarized matching event rows, - use **Table rows** with **Total** to count those rows. For an official summarized query - such as **Failed Signin reasons**, use **Calculation of a numeric column**, select its - count column (`Count` in that source query), and choose the aggregation/grouping - that matches your objective. - Summing count groups is different from taking the maximum group; agree which is intended. - A rate query requires the reviewed numeric rate column. Do not count summary rows - as failures or assume the wizard's automatically detected measurement is correct. -5. On **Alert logic**, start with **Static** and the threshold you chose from your baseline. - Set the **Operator** and **Threshold value**, checking the units against the query output. - Only use a returned-row/greater-than-zero condition when the query itself - deliberately returns **qualifying incidents**, not an unconditional summary. Do not - apply that setting blindly to Microsoft's count examples. -6. Set **Aggregation granularity (window size)** and **Frequency of evaluation** from the - observation window, normal ingestion delay, response needs, and budget. - Keep these settings in your team's rule notes. A frequent evaluation is not proof of - fresh data; overlapping windows can observe the same records repeatedly. -7. In **Advanced options**, review **Override query time range** and any query time filter - together. Ensure the rule scans the data required by its approved calculation, including - any deliberately delayed observation window. Alert queries scan at most **48 hours**; - a longer baseline query is not automatically a valid scheduled rule. One-minute evaluation - has extra query restrictions, including `ingestion_time()`; consult the official reference - before selecting it. A time picker used during exploration is not a stored rule setting. -8. With your response team, set **Number of violations to trigger the alert**. If using - several violating evaluations, check the query's required datetime output and evaluation period - against the official instructions. Inspect the **Preview** for healthy and qualifying - periods. Do not assume missing data is a healthy evaluation. -9. Leave **Split by dimensions** unset unless separate incidents are required and reviewed. - Adding app/IP/user dimensions changes grouping, incident count, cost, and exposed data. - Avoid volatile/high-cardinality request, correlation, and user identifiers. A workspace-scoped - alert without dimensions is a workspace incident; document the app/scope in its runbook. -10. On **Actions**, select an approved action group or select **Create action group**. - Follow the [illustrated action-group creation instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/action-groups#create-in-the-azure-portal). - Confirm subscription/resource group, name, processing region, and notification recipients. - For a new group, complete **Basics**, then **Notifications** with the approved type, - recipient, and applicable **Common alert schema** setting. Review any **Actions**, then - select **Review + create > Create** and return to the rule to select the saved group. - Use approved email/push or incident routing, complete required recipient verification, - and keep security results on a restricted route. Do not attach an automated policy-change - action to an unvalidated heuristic. -11. On **Details**, select the **Subscription**, **Resource group**, **Region**, and agreed - **Severity**. Enter an **Alert rule name** and **Description** identifying source tenant, - app, measure/units, threshold rationale, window, owner, and runbook. Use - [the illustrated Details and Identity screen](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#configure-alert-rule-details). -12. Choose the **Identity** that will run the query. A **system-assigned managed - identity** has no permissions initially: create the rule with **Enable upon creation** - cleared, then ask your Azure administrator to grant that identity reader/query access to the - workspace through **Workspace > Access control (IAM)**. Allow role propagation before - enabling it. If using a **user-assigned identity**, authorize it before selection. - For **None**, record that query permissions follow the last editor. Check linked-storage - policy requirements and identity restrictions in the official reference before choosing. -13. Review **Automatically resolve alerts** for stateful behavior and **Mute actions** - where appropriate. Resolution timing depends on evaluation frequency; it is not immediate. - Make sure the receiving team knows when repeated notifications will be suppressed. -14. Select **Review + create** only after checking scope, query, measured units, time settings, - permissions, actions, and costs. Keep the initial rule disabled until its identity and - [validation checks](#validate-without-generating-provider-sends) are ready. To change it, - use **Monitor > Alerts > Alert rules > selected rule > Edit**. + and the [user-behavior template](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/userBehaviourWorkbookDeployment.json) + for investigation. Neither supplies a turnkey EPP fraud alert. +2. Have security review actual `IPAddress`, `UserId`, and `ResultType` population before + choosing a grouped rule. Account for unknown users, absent IPs, approximate distinct + counts, distributed attempts, NAT, VPNs, mobile networks, and shared proxies. + IP geolocation does not prove physical location. +3. Restrict personal-data results/notifications. Don't automatically block, disable an + account/provider, or change policy solely on these heuristics. +4. In supported, licensed workforce tenants, follow + [risk investigation instructions](https://learn.microsoft.com/en-us/entra/id-protection/howto-identity-protection-investigate-risk). + Check populated `RiskLevelDuringSignIn`, `RiskLevelAggregated`, `RiskState`, and `RiskDetail`. + Detections can arrive asynchronously; empty, none, or hidden isn't fraud clearance. + A template named "risk detection" doesn't enable ID Protection in external tenants. ### Monitor ingestion separately -1. Decide who will check log collection as well as who responds to sign-in alerts. - Quiet alerts can mean broken export, not healthy authentication. Review the - [log-alert guidance on missing data](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-types#log-alerts) - before designing a freshness rule. -2. Work out when the app normally has traffic, including quiet hours and - maintenance. Compare **Entra > Sign-in logs** with the workspace after the measured delay. - No user activity and stopped collection can look identical; do not enable staleness paging - for an idle app without a documented expectation. -3. Work with your query maintainer to adapt the - [ingestion-time/latency guidance](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/data-ingestion-time) - into a separate app-scoped freshness check. Test what happens with **no matching rows, - missing ingestion time, and stale latest arrival**. The linked - reference is not a preconfigured Entra no-data alert. Do not hide an unresolved table or - query error behind an empty-success fallback. -4. Create a separate rule using the same portal workflow, with its own freshness measure, - threshold, lookback, frequency, action group, and owner. Match its **Override query time - range** to the freshness calculation, not blindly to the aggregation window. Confirm - frequency supports the query; ingestion-time functions are restricted at one-minute frequency. -5. Check **Monitor > Alerts > Alert rules**, the selected rule's health/errors and associated - alerts, and the workspace's collection settings. Permission/query failures must be resolved - separately from a stale-data incident. Inspect transformations, ingestion limits, and service - health with your workspace administrator; missing evidence doesn't mean less abuse. +1. Assign someone to check collection as well as failures. See + [missing-data guidance](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-types#log-alerts): + quiet alerts can mean stopped export. An idle app and broken collection can look alike; + agree on normal traffic, quiet hours, and maintenance before enabling freshness paging. +2. Compare portal sign-ins with the workspace after the measured delay. Adapt the linked + ingestion guidance into a scoped check for **no rows, missing ingestion time, and stale + arrival**; test each case. It is not a preconfigured no-data alert. An unresolved table + or query error must remain visible, not become an empty-success fallback. +3. Create a separate rule with its own measure, threshold, lookback, frequency, recipient, + and maintainer. Match the query-time override to that calculation; don't blindly use + the aggregation window. Check the query's frequency restrictions. +4. Inspect rule health/query errors, export settings, workspace access, transformations, + ingestion limits, and service health. Fix evaluation failures separately from stale-data + incidents. Missing evidence doesn't mean less abuse. ### Validate without generating provider sends -1. Open the selected action group and use **Test**, following the official - [action-group testing instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/action-groups#test-an-action-group-in-the-azure-portal). - Save the group first. Choose the test's alert type and approved notification/action - receivers, then select **Test** and keep the test page open until **Success** or **Failed** - appears. On failure, use **View details**, resolve the error, save, and retest. - Confirm the intended recipients actually receive it, including verification and - spam-filter checks; access to read a group alone does not grant test permission. - This tests notification routing, not log export or query evaluation. -2. Run the saved, app-scoped query against existing records you're authorized to inspect. - Compare it with the associated Entra sign-ins. Check a healthy window, a qualifying window, an empty scope, - and known ingestion delay. Confirm output shape/units agree with the rule's Measurement. -3. For an end-to-end check, create a **temporary nonproduction rule** with a restricted - test action group. Use existing records within its lookback and an approved temporary - condition that they satisfy. If changing the query time filter, update the rule's - **Override query time range** consistently and stay within the alert scan limit. - Do not lower a production threshold or route a test to production incident automation. -4. Authorize the test rule's evaluation identity and enable it. Observe a scheduled - evaluation and notification in **Monitor > Alerts**. Keep the rule name, UTC time, - measured value, and recipients so your team can check the result. A successful query - under your own identity does not prove the rule identity can read the workspace. -5. Verify resolution when the test condition clears, allowing for stateful resolution timing. - Disable/delete the temporary rule and remove temporary overrides. Reopen the intended - rule to confirm its approved query, threshold, time settings, recipients, and enablement. -6. If records are insufficient, use only an approved **non-phone test sign-in flow** in a - test tenant/app. Do not induce repeated wrong OTPs, alter production policy, bypass Easy Auth, - or send live OTPs just to populate a report. An EPP evaluation does not validate delivery - and is not guaranteed to create `SigninLogs` records. -7. Before enabling production notifications, check that logs arrive, the saved query works, - the rule can read the workspace, and the right people receive the alert. Remove any - leftover test settings. These checks need to happen in your environment; this guide - hasn't run Azure/Kusto queries or created or tested your rules. - -## 6. Build a sign-in Workbook - -1. Open the [Microsoft External ID monitoring repository](https://github.com/microsoft/external-id-azure-monitor) - and review its setup instructions. Inspect the relevant - [authentication](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/authenticationsWorkbookDeployment.json), - [MFA](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/mfaWorkbookDeployment.json), - or [user-behavior](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/userBehaviourWorkbookDeployment.json) - template for existing queries and visualizations. Do not select **Deploy to Azure** - just to view a query; templates can create resources/delegation and require separate approval. - In the GitHub file view, inspect the workbook's **serializedData** and its query definitions - with your query maintainer. These files are ARM deployment templates, not text to paste in full - into Logs; extract/review only the needed query or use an already-approved deployed Workbook. -2. Check each chosen query's tables, tenant features, workspace/app filters, time settings, - personal-data fields, and units against your actual records. A template named - [risk detection](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/riskDetectionWorkbookDeployment.json) - does not make ID Protection available in an external tenant. -3. In **Azure portal > Monitor > Workbooks**, select **New** or an empty template and enter - **Edit** mode. Follow the - [illustrated Workbook authoring guide](https://learn.microsoft.com/en-us/azure/azure-monitor/visualize/workbooks-create-workbook). - Select **Add > Add query**, choose **Logs (Analytics)** and the verified workspace, - then use the query you reviewed and saved. -4. Select a **Visualization** matching the output, then **Run Query**. Use counts/result-code - grids for breakdowns and a time chart only for a query with the appropriate time-series - output. Check actual scope/time/units before selecting **Done editing**; the - [Add queries instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/visualize/workbooks-create-workbook#add-queries) - show the relevant controls. -5. Add a short explanation of which tenant/app the view covers, what it counts, how long - logs take to arrive, what missing data means, and who to contact. Label sign-in records - and authentication steps distinctly; an empty chart is not a healthy result. - Include the separately reviewed freshness view. -6. If adding app/workspace/time parameters, bind them into **every relevant query** and - verify that changing them changes the data as intended. A Workbook selector does not - override a hard-coded filter automatically. Keep detailed IP/user-level views restricted. -7. Select **Save** and choose the approved subscription, resource group, location, and name. - Ask a teammate with log access to open it and check the filters. Sharing a Workbook - does not grant access to the underlying logs. Workbooks visualize data; they do **not** - create the scheduled alerts above or prove those alerts are enabled. - -## 7. Triage, privacy, retention, and costs - -1. When notified, open **Monitor > Alerts > selected alert** and confirm rule name, - workspace, tenant/app scope, UTC window, measured value, and rule/collection health. - Open the approved saved query for that period, then inspect the related Entra sign-in's - **Basic info**, **Authentication Details**, and applicable policy results. -2. Review changed result codes with your identity-support team. Separate user - mistakes/interruptions, application releases, and policy changes from infrastructure - failures or potential abuse. Escalate suspected compromise through the organization's - security response process; a heuristic notification is not a confirmed fraud verdict. -3. If phone delivery is implicated, follow the existing - [runtime-specific Function queries](MONITORING.md#runtime-specific-log-discovery). - Compare UTC time, verified request context, failure stage, and provider outcome with - restricted provider records. `SigninLogs.CorrelationId`, Function `OperationId`, - request IDs, and provider references are **not guaranteed equal**. Prove any association - in an approved trace before using a join. An absent match does not prove no Function call; - fallback can also complete authentication through another path. -4. Keep personal data in approved systems. User IDs/names, IP/location/device details, - sign-in identifiers, and authentication details can be sensitive. Review workspace/table - access, Workbook sharing, and action-group recipients. Do not export raw records to public - issues or put OTPs, message bodies, tokens, or credentials in alerts. Query filters are - **not an access-control boundary**. -5. In **Log Analytics workspace > Tables**, select the relevant table and review its - table plan, **analytics retention**, and **total retention** with the privacy/retention - owner. Follow [retention configuration](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/data-retention-configure). - Confirm the setting actually saved and allows the required investigation period. - Entra portal retention and workspace retention are different. -6. Review **workspace Usage and estimated costs** and **Azure Cost Management > Cost analysis** - for the approved subscription/resource scope, using the - [log-cost guidance](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/cost-logs). - Diagnostic export selects categories, not an app-specific stream: app query filters - do not remove tenant-wide ingestion charges. Include retention, queries, alert frequency, - dimension count, notifications, and any separately enabled services in budget review. -7. Inspect caps and transformations with the collection owner. They can remove evidence - needed by a rule. Verify changes do not silently remove required fields/populations and - update collection-health checks. Provider sending/billing remains a separate cost source. -8. Put the setup notes somewhere your team can find them without exposing them publicly. - Include the tenant/app, workspace and export setting, saved queries, normal traffic and - arrival delay, Workbook, alert identity/settings, action group, and test results. - Name the contacts for collection, identity support, security, privacy, retention, and costs, - along with escalation and maintenance arrangements. -9. Walk a teammate through opening the queries and Workbook, checking rule health, - receiving a test notification, and investigating an alert. They shouldn't need to send - an OTP or change authentication policy to do this. Remove any remaining temporary test - settings before handing over. +1. Save the action group before **Test**. Keep the test page open until **Success** or + **Failed**; on failure use **View details**, fix, save, and retest. Check recipient + verification and spam filtering. Group read access alone doesn't grant test permission. +2. Compare the saved query with existing portal records in healthy, qualifying, empty, + and delayed windows. Check output units against Measurement. For a temporary + nonproduction rule, use records inside its lookback and a restricted test action group. + Change the query time filter and portal override together, within the alert scan limit. +3. Authorize the test rule identity, enable it, and observe a scheduled alert and notification + in **Monitor > Alerts**. Check resolution after the condition clears, allowing for stateful + timing. Remove the test rule/overrides and restore the intended production settings. +4. Don't lower production thresholds for testing or route tests to production automation. + If needed, use an approved non-phone test sign-in flow. Don't bypass Easy Auth, send live + OTPs, induce repeated wrong codes, or alter production authentication policy. + + + +### Build a Workbook when you need a shared view + +1. Review the [Microsoft monitoring repository](https://github.com/microsoft/external-id-azure-monitor) + and its authentication, MFA, and user-behavior templates linked above. Inspect + **serializedData** query definitions with your query maintainer. These are ARM templates, + not text to paste wholesale into Logs. **Deploy to Azure** can create resources/delegation; + don't select it just to inspect a query. +2. Check tables, tenant features, personal fields, units, filters, and time settings. + The [risk template](https://github.com/microsoft/external-id-azure-monitor/blob/main/templates/riskDetectionWorkbookDeployment.json) + doesn't make risk features available in your tenant. +3. Open **Azure portal > Monitor > Workbooks > New**, enter **Edit**, then **Add > Add query**. + Select **Logs (Analytics)** and your workspace. Use the reviewed query and follow + [Workbook authoring](https://learn.microsoft.com/en-us/azure/azure-monitor/visualize/workbooks-create-workbook) + and [Add queries](https://learn.microsoft.com/en-us/azure/azure-monitor/visualize/workbooks-create-workbook#add-queries). + Choose a suitable **Visualization**, **Run Query**, then **Done editing**. +4. Label record/step counts clearly, explain missing data and arrival delay, and include + freshness. Bind app/workspace/time parameters into every relevant query and test changes; + selectors don't automatically replace hard-coded filters. Restrict detailed user/IP views. +5. **Save** to the agreed subscription/resource group/location and have a teammate check + access. Workbook sharing doesn't grant underlying log access, create alerts, or prove + they are enabled. + + + +### Investigate alerts and manage the data + +1. In **Monitor > Alerts > selected alert**, check the rule, workspace, app/tenant scope, + UTC window, measured value, and rule/collection health. Open the saved query for that + period, then the relevant Entra **Basic info**, **Authentication Details**, and policy results. +2. Separate user mistakes/interruptions, releases, and policy changes from outages or abuse. + Escalate suspected compromise through your security response process; a heuristic isn't + a confirmed fraud verdict. +3. For phone concerns, compare [runtime-specific Function logs](MONITORING.md#runtime-specific-log-discovery) + and restricted provider records. `SigninLogs.CorrelationId`, Function `OperationId`, + request IDs, and provider references are **not guaranteed equal**. Prove an association + before joining them. No match doesn't prove no Function call; fallback can complete + authentication through another path. Provider acceptance isn't handset receipt. +4. Keep raw identity/device/IP/phone data in approved systems. Check workspace/table access, + Workbook sharing, and recipients. Don't put tokens, credentials, OTPs, or messages in + alerts/public issues. Query filters are **not an access-control boundary**. +5. Review **Workspace > Tables** plan, analytics retention, and total retention using + [retention instructions](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/data-retention-configure). + Confirm saved settings cover your investigation period; Entra portal and workspace + retention are separate. +6. Check **Usage and estimated costs** and **Cost Management > Cost analysis** with the + [cost guidance](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/cost-logs). + Export selects categories, not an app-only stream: query filters don't remove tenant-wide + ingestion charges. Include retention, queries, alert frequency/dimensions, notifications, + and separately enabled services. Provider billing is separate again. +7. Review caps/transformations with the collection maintainer; they can remove evidence + the rules need. Keep setup notes, test results, contacts for support/security/privacy/ + retention/costs, and escalation/maintenance arrangements together. Walk a teammate through + the query, Workbook, rule health, and test notification without sending OTPs or changing policy. From 1a38f772442682f364f4b9708cbee6da42b5e3ea Mon Sep 17 00:00:00 2001 From: Hou Chi Chan Date: Tue, 13 Oct 2026 14:07:15 -0700 Subject: [PATCH 7/8] docs: clarify first-alert terms and threshold choices Explain workspace, KQL, baseline and action group at first use. Make the first combined failure-count alert settings definitive and finish with a conditional readiness transition. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f1451aca-6f84-41e6-9baf-cec42e36da6e --- docs/SIGN-IN-MONITORING.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/docs/SIGN-IN-MONITORING.md b/docs/SIGN-IN-MONITORING.md index 10a20a1..8d0d64d 100644 --- a/docs/SIGN-IN-MONITORING.md +++ b/docs/SIGN-IN-MONITORING.md @@ -51,7 +51,7 @@ not changes made by this guide. [Function monitoring guide](MONITORING.md#runtime-specific-log-discovery) separately. **Only investigating one problem? You can stop here.** You don't need to export logs, create -a workspace, or incur additional Azure Monitor collection costs for this portal-only path. +a workspace (where exported logs are stored), or incur additional Azure Monitor collection costs for this portal-only path. Continue if your team wants ongoing alerts or longer-term analysis. ## 3. Export logs for ongoing monitoring @@ -104,7 +104,8 @@ Continue if your team wants ongoing alerts or longer-term analysis. No matching records is **not** a healthy result: check the destination, time range, category, access, and portal sign-ins before continuing. 3. Open Microsoft's [Failed Signin reasons query](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/queries/signinlogs#failed-signin-reasons). - In **KQL mode**, copy it from that source and filter to your `AADTenantId` and `AppId` + In **KQL mode** (Kusto Query Language, used to search logs), copy it from that source + and filter to your `AADTenantId` and `AppId` **before summarizing**. Ask someone familiar with KQL to review the edits. Check the string type of `ResultType` and handle empty codes separately; these are authentication codes, not provider HTTP statuses. [Query adaptation details](#4-establish-the-baseline) @@ -112,7 +113,8 @@ Continue if your team wants ongoing alerts or longer-term analysis. 4. Choose an observation window with the receiving team, then **Run** that same calculation across normal, peak, and quiet periods in a representative business cycle. Read `Count` and the result codes, not the number of summary rows. Allow for measured ingestion delay; - choose a failure-count threshold for that window, not a whole week's total. There is no + use your baseline (the usual failure count over the chosen period) to choose a threshold + for that window, not a whole week's total. There is no universal threshold; the source query is not a turnkey EPP or fraud detector. 5. Select **Save > Save as query** and choose the agreed query pack. Saving needs **Log Analytics Contributor**; ask an authorized teammate if you only have read access. @@ -126,7 +128,7 @@ IP-based detection for [later](#more-alert-types), once you understand this base 1. Check [alert permissions](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#prerequisites): read access to the workspace, write access to the rule's resource group, and read access - to its action group. Creating groups or assigning roles requires additional permissions. + to its action group (who gets notified). Creating groups or assigning roles requires additional permissions. In **Azure portal > Monitor > Alerts > Create > Alert rule**, select your **Log Analytics workspace** as **Scope**, not the Function or app registration. 2. On **Condition**, choose **Custom log search**, paste the saved query, and select **Run**. @@ -135,13 +137,14 @@ IP-based detection for [later](#more-alert-types), once you understand this base This is a scheduled log search alert, not an Azure Activity Log alert; check that your table plan supports the query and rule. 3. For **Failed Signin reasons**, set **Measure** to **Calculation of a numeric column**, - choose `Count`, and use **Total** if you want the total across the result-code groups. + choose `Count`, and use **Total** across the result-code groups. Leave **Split by dimensions** unset for this first combined alert. Don't count summary - rows as failures. Set **Static**, the **Operator**, and **Threshold value** from Step 4. + rows as failures. Set **Static**, **Greater than**, and a **Threshold value** based on + the normal counts for the same observation window in Step 4. 4. Set **Aggregation granularity (window size)** and **Frequency of evaluation** to match the team's observation window, ingestion delay, response needs, and budget. Review **Override query time range** with the query's time filter; alert scans are limited to - **48 hours**. Start with a single violating evaluation; if you need several, review the + **48 hours**. Start with one evaluation above the threshold; if you need several, review the [required query output and evaluation settings](#query-identity-and-rule-options) first. Review healthy and qualifying periods in Preview. Keep missing-data expectations separate from failure counts; [collection-health guidance](#monitor-ingestion-separately) explains why. @@ -175,8 +178,8 @@ IP-based detection for [later](#more-alert-types), once you understand this base Leave a teammate the query, rule, workspace, action group, settings, and support contacts. Arrange a check for [missing logs](#monitor-ingestion-separately), not just sign-in failures. -That's the first-alert path. These checks happen in your environment; this guide hasn't -run Azure/Kusto queries or configured your monitoring. +Your first alert is ready once these checks pass. Use the optional reference below when +you need more advanced monitoring. ## Optional reference From 25544c0792fcc6e963059b1411abab852d2753ac Mon Sep 17 00:00:00 2001 From: Hou Chi Chan Date: Tue, 13 Oct 2026 14:08:34 -0700 Subject: [PATCH 8/8] docs: define workspace at its first mention Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f1451aca-6f84-41e6-9baf-cec42e36da6e --- docs/SIGN-IN-MONITORING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/SIGN-IN-MONITORING.md b/docs/SIGN-IN-MONITORING.md index 8d0d64d..e9dce93 100644 --- a/docs/SIGN-IN-MONITORING.md +++ b/docs/SIGN-IN-MONITORING.md @@ -16,7 +16,7 @@ not changes made by this guide. from the tenant hosting the Function. Note its **Tenant ID** from **Overview**. 2. Ask your tenant administrator for **Reports Reader**, the minimum role for viewing activity logs. See Microsoft's [access requirements](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-access-activity-logs#prerequisites). - This role does not grant access to an Azure workspace. + This role does not grant access to an Azure workspace (where exported logs are stored). 3. Check whether you have a **workforce tenant** or an **external tenant** for customer apps. If unsure, use the [tenant comparison](https://learn.microsoft.com/en-us/entra/external-id/customers/concept-supported-features-customers) with your administrator. Both can use the portal investigation below, but external @@ -51,7 +51,7 @@ not changes made by this guide. [Function monitoring guide](MONITORING.md#runtime-specific-log-discovery) separately. **Only investigating one problem? You can stop here.** You don't need to export logs, create -a workspace (where exported logs are stored), or incur additional Azure Monitor collection costs for this portal-only path. +a workspace, or incur additional Azure Monitor collection costs for this portal-only path. Continue if your team wants ongoing alerts or longer-term analysis. ## 3. Export logs for ongoing monitoring