Home / Blog / SIEM and Tools

Intermediate SIEM and Tools

How to Run Cross Tenant Sentinel Queries in an MSP SOC

Set up Azure Lighthouse access, write workspace() queries that label every client and learn the limits of cross workspace rules before you run a multi tenant SOC on them.

An MSP SOC that signs in to each client tenant separately loses time on every shift, and the gaps show up in handovers and missed SLAs. Microsoft Sentinel lets your analysts query many client workspaces from one place while each client's logs stay in their own tenant. This guide is for SOC leads and analysts at managed service providers who want cross tenant hunting and reporting that is fast, safe and easy to audit.

Access modelAzure Lighthouse delegation, least privilege
Key operatorworkspace() with union
Hard limits100 workspaces per log query, 20 per analytics rule
>

Scenario: At 03:10 a threat feed lists four IP addresses behind a password spraying campaign against Microsoft 365 tenants. Your SOC covers 14 clients and the morning handover is at 07:00. Without cross tenant access, the night analyst switches directory 14 times, runs the same query in each workspace and pastes results into a spreadsheet. With it, one query answers which clients saw the addresses, and the handover note writes itself.

Choose your multi tenant model

There are three common ways to run Sentinel across clients. Most MSPs end up using the second and third together.

Option 1

Switch per tenant

Analysts sign in to each client as a guest and work one workspace at a time. Simple to start, slow at scale and hard to compare clients.

Fine for two or three clients
Option 2

Azure Lighthouse

Each client delegates scoped Azure roles to groups in your tenant. Analysts query client workspaces with workspace() and work their incidents without switching.

The foundation for most MSPs
Option 3

Defender multitenant management

A single incident queue and advanced hunting across tenants in the Defender portal, covering Defender XDR data and onboarded Sentinel workspaces.

Unified queue for triage

Defender multitenant management uses granular delegated admin privileges (GDAP) or Microsoft Entra B2B for Defender data. For Sentinel data in other tenants, Microsoft's documentation calls for Azure Lighthouse together with Entra B2B, and GDAP support for Sentinel has been in preview, so check the current requirements page before you design around it. The Defender portal supports one primary and multiple secondary Sentinel workspaces per tenant.

i

Note: Microsoft has announced that Sentinel will only be available in the Defender portal after 31 March 2027. If you are designing a new multi tenant setup now, build it so it works in the Defender portal, and treat Azure portal only workflows as temporary.

Delegate least privilege with Azure Lighthouse

A Lighthouse delegation, sometimes called an offer, is created in the client's tenant and grants Azure roles on chosen subscriptions or resource groups to principals in your managing tenant. Delegate to groups, one per role, so that adding or removing an analyst is a change in your directory rather than a new deployment in every client.

Group in your tenantRole delegatedLets the group
SOC Tier 1Microsoft Sentinel ResponderView data and manage incidents: assign, comment, change status
SOC HuntersMicrosoft Sentinel Reader and Log Analytics ReaderRun queries and hunts without changing anything
Detection EngineersMicrosoft Sentinel ContributorCreate and edit analytics rules, watchlists and workbooks
AutomationMicrosoft Sentinel Automation ContributorAttach playbooks to automation rules
+

Tip: Lighthouse supports eligible authorisations, which work with Privileged Identity Management (PIM). Make Contributor eligible rather than permanent, with a short activation window and a justification, so rule changes in a client tenant are always tied to a reason and a person.

!

Watch out: Never accept Owner or broad subscription Contributor in a SOC delegation. Also check the contract before you query: cross tenant query results travel to your managing tenant, so the client's agreement and data processing terms should cover that. Some clients, especially in the public sector, will want written confirmation.

Write queries that name the client

The workspace() expression points a table reference at another workspace, and union joins the results together. The rule that saves you pain later is simple: add a Client column to every leg of the union, because nothing in the raw data reliably tells an analyst which customer a row came from.

Microsoft Sentinel, managing tenantKQL
let SprayIPs = dynamic(["203.0.113.50", "203.0.113.51", "198.51.100.17", "198.51.100.44"]);
union
    (workspace("c1a2b3c4-0000-4000-8000-000000000001").SigninLogs | extend Client = "Contoso"),
    (workspace("c1a2b3c4-0000-4000-8000-000000000002").SigninLogs | extend Client = "Fabrikam"),
    (workspace("c1a2b3c4-0000-4000-8000-000000000003").SigninLogs | extend Client = "Northwind")
| where TimeGenerated > ago(24h)
| where IPAddress in (SprayIPs)
| summarize Attempts = count(),
    Successes = countif(ResultType == "0"),
    Users = dcount(UserPrincipalName)
    by Client, IPAddress
| order by Successes desc, Attempts desc

Use the workspace ID (a GUID) or the full resource ID in workspace() rather than the workspace name. Names are only unique within a resource group, and two clients can easily both have a workspace called sentinel-prod.

Save the union as a function

Typing every workspace into every query is slow and error prone. Save the union as a function in your managing workspace, for example MSP_SigninLogs, and analysts can then write MSP_SigninLogs | where IPAddress in (SprayIPs). When you onboard a new client, you update one function rather than dozens of saved queries. Keep one function per table, and keep the function definitions in source control alongside your rules.

  • Every union leg adds a Client column with a consistent client name.
  • Workspaces are referenced by ID, never by display name.
  • Functions live in the managing workspace and in your repository.
  • New client onboarding includes updating every MSP_ function and running a test query.

Check every client's log health in one query

The most valuable cross tenant query is often not a hunt at all. It is the check that tells you a client's servers have gone quiet before the client asks why you missed something. This query finds machines with Azure Monitor Agent heartbeats that have stopped in the last half hour.

Microsoft Sentinel, managing tenantKQL
union
    (workspace("c1a2b3c4-0000-4000-8000-000000000001").Heartbeat | extend Client = "Contoso"),
    (workspace("c1a2b3c4-0000-4000-8000-000000000002").Heartbeat | extend Client = "Fabrikam"),
    (workspace("c1a2b3c4-0000-4000-8000-000000000003").Heartbeat | extend Client = "Northwind")
| where TimeGenerated > ago(7d)
| summarize LastHeartbeat = max(TimeGenerated) by Client, Computer
| where LastHeartbeat < ago(30m)
| extend MinutesSilent = datetime_diff('minute', now(), LastHeartbeat)
| order by Client asc, MinutesSilent desc

Run it at the start of every shift. A domain controller silent for six hours at one client is a service conversation with that client today, not a surprise in next month's report. Extend the same pattern to the tables your contracts depend on, such as SecurityEvent or CommonSecurityLog, by comparing the latest TimeGenerated per client with what you expect.

Use cross workspace analytics rules with care

You can put workspace() inside a scheduled analytics rule, which is tempting for an MSP: write one rule, cover every client. Microsoft documents limits that change how you should use this.

  • A single analytics rule query can include up to 20 workspaces, and Microsoft recommends no more than 5 for good performance. Log queries and hunting can reference up to 100.
  • Sentinel must be enabled on every workspace the rule references.
  • Alerts and incidents from a cross workspace rule exist only in the workspace where the rule is defined, not in the client workspaces it queried.
  • Microsoft's guidance for MSSPs is to keep each cross workspace rule to the workspaces of a single customer, because mixing customers makes incidents confusing to manage.

Incident in the wrong place

High
What it looks like

A rule mixing three clients raises an incident in your tenant, and the client's own SOC portal never shows it.

Control

One client per rule, with the Client column mapped into the alert details so every incident title names the customer.

Silent rule after offboarding

High
What it looks like

A delegation is removed or changed and a cross tenant rule stops returning that client's data without an obvious error.

Control

Monitor rule health and the SentinelHealth table, and review delegations as part of client offboarding.

Slow, expensive queries

Med
What it looks like

A hunting function across 30 workspaces times out at shift change when everyone runs it.

Control

Filter on time and fields early, and split very wide unions into regional or tiered functions.

For most MSPs the cleaner pattern is to deploy each detection into each client workspace as code, through repositories or a pipeline, and keep cross workspace queries for hunting, health checks and reporting. Workspace Manager is not available in the Defender portal, so if you relied on it, plan for repositories or another content as code method.

Build a handover view across clients

A shift handover should answer three questions per client: what is open, how old is it and who owns it. The SecurityIncident table records a new row every time an incident changes, so take the latest row per incident first. Incident numbers are only unique within a workspace, so always group by client as well.

Microsoft Sentinel, managing tenantKQL
union
    (workspace("c1a2b3c4-0000-4000-8000-000000000001").SecurityIncident | extend Client = "Contoso"),
    (workspace("c1a2b3c4-0000-4000-8000-000000000002").SecurityIncident | extend Client = "Fabrikam"),
    (workspace("c1a2b3c4-0000-4000-8000-000000000003").SecurityIncident | extend Client = "Northwind")
| where TimeGenerated > ago(14d)
| summarize arg_max(TimeGenerated, *) by Client, IncidentNumber
| where Status != "Closed"
| extend AgeHours = datetime_diff('hour', now(), CreatedTime),
    AssignedTo = tostring(Owner.assignedTo),
    SevRank = case(Severity == "High", 1, Severity == "Medium", 2, Severity == "Low", 3, 4)
| project Client, IncidentNumber, Title, Severity, Status, AssignedTo, AgeHours, SevRank
| order by SevRank asc, AgeHours desc

Pin the result to a workbook and review the totals at the start of each shift. A summary like the one below makes SLA risks obvious before they become breaches.

Shift handover summary example MSP, 14 clients, 07:00
14/14Clients queried
2Clients with silent hosts
0Unassigned High incidents
3Incidents near SLA
27Incidents closed overnight
18 minMedian time to acknowledge
1Spray IP seen at a client
0Successful spray sign ins
Decision: Day shift calls Fabrikam about two silent servers before 09:00 and takes ownership of the three incidents nearing SLA.
Label everythingEvery row, incident and report names the client it came from.
Least privilegeGroup based delegations, reader by default, eligible Contributor through PIM.
Hunt central, detect localCross tenant queries for hunting and health, detections deployed per client as code.

Key takeaways

  1. Azure Lighthouse is the foundation for querying Sentinel data across client tenants, and Defender multitenant management adds a unified incident queue.
  2. Delegate Azure roles to groups, keep reader access as the default and make Contributor eligible through PIM.
  3. Reference workspaces by ID and add a Client column to every leg of every union, then save the unions as functions.
  4. Know the limits: 100 workspaces per log query, 20 per analytics rule and incidents only in the rule's home workspace.
  5. Use cross tenant queries daily for log health and handover, not just for hunting.

Start small: delegate reader access from two clients, build one MSP_SigninLogs function and the heartbeat check, and run them at every handover for a fortnight. Once the team trusts the results, extend the functions to the rest of your clients and retire the spreadsheet.

Written by Stacey, SOC Manager, MSP

Keep going

More in SIEM and Tools