In this section

Setting Up an Entra ID Detection Lab

Module 0

Introduction

This course provides its queries as artifacts you run in a tenant of your own rather than against a hosted dataset. You will finish this section knowing which of three routes fits your situation, what each costs, and the one configuration step that decides whether the rest of the course works for you at all.

Scenario

Two students start this course on the same day. One has a developer tenant they created that morning: every query in id04 parses correctly, runs in under a second, and returns nothing at all, because a tenant with four users and no history has no events to find. The other has read access to their employer's production tenant: every query returns thousands of rows, several take a minute, and one of them surfaces a service principal nobody can account for on the second day of the course.

01

What the course actually needs

Three things, and one of them is the hard one

The requirement list is short. You need a tenant you can read, a Log Analytics workspace receiving its identity logs, and enough activity in that tenant that a query has something to return.

The first is easy and the second takes ten minutes. The third is the one that decides your experience of this course, and it is not something you can configure. A tenant needs history, and history takes time or it takes a population.

History matters for a reason specific to this subject rather than as a general preference. Per section 0.5 most identity detection is about distinguishing a legitimate action from an identical malicious one, and that distinction is made against a baseline: what this account normally does, where this application normally authenticates from, how often this credential is normally used. A tenant with no past has no normal, so every record in it is equally unremarkable and the exercises that teach judgment have nothing to judge against.

That is what separates the two students in the scenario. Neither did anything wrong. The one with the fresh developer tenant has a technically perfect environment in which nothing has ever happened, and per section 0.2 a query against an empty table is indistinguishable from a query against a quiet one, which is a lesson worth learning but not one you want on every exercise.

There is a fourth thing worth naming that is not a requirement and changes the experience considerably, which is whether you can make changes. The query modules only need read access. The configuration and recovery modules, id01, id03 and id06, ask you to build a policy, scope an application permission or restore something, and reading about those is a different experience from doing them.

Most people end up with read access to one estate and write access to another, which is a workable position and is why the routes below include it explicitly rather than treating it as a compromise.

Keep this

The scarce resource in an identity lab is not the tenant, it is the history. Every other requirement can be met in an afternoon. Activity accumulates or it does not exist, which is why the routes below differ mainly in how they solve that one problem.

The three routes are worth choosing between deliberately now rather than defaulting into one, because the choice determines which exercises you can complete and it is easier to arrange access before you need it than in the middle of id04.

02

Three routes, and what each costs you

Pick before module 1 rather than during it
Three routes through this course Each solves the history problem differently, and each costs something different A. Read your employer's history: real, years of it cost: nothing access: read-only is enough you cannot change anything findings become real work B. Developer tenant history: none, at the start cost: free if you qualify access: full, break anything queries return nothing at first generate your own activity C. Both read production, change dev cost: the setup of B access: read plus full the queries have something the changes have somewhere

Figure 0.15. Route C is the one this course is written for. A and B each work, and each is missing one half.

One thing to settle before choosing, because it is the constraint people discover late: a Log Analytics workspace has a cost attached to the data it ingests, and in a lab tenant that cost is effectively nil because there is almost no data. In production it is somebody's budget line, and per section 0.1 it is the budget line that gets reviewed.

Route A costs nothing and gives you everything the query modules need. Read access to a production tenant and its workspace means every exercise in id04 returns real data with real ambiguity, and per section 0.6 the inventory exercises frequently produce a genuine finding in the first week. What it does not let you do is change anything, so the configuration work in id01, id03 and id06 becomes reading rather than doing.

Route B is a Microsoft 365 developer tenant, free if you qualify through a developer program, otherwise a thirty-day E5 trial. You can break anything in it, which matters for the modules that build policies and test recovery. Its weakness is the scenario's first student: nothing has happened in it, so queries have nothing to find until you make something happen.

Route B has one advantage worth stating that Route A cannot match: you can break things and watch what happens. Locking yourself out of a lab tenant with a Conditional Access policy is a genuinely useful experience and it is the sort of thing id06 is about. Doing that in production ends a career rather than a module.

Route C is both, and it is what the course assumes where it can. Query the estate that has history, configure the one you can break. It costs nothing beyond the setup of B, and it removes the one weakness each of the others has: the queries get an estate with history and the changes get an estate that can absorb them.

03

The step that decides everything

Four categories, one screen

Whichever route you take, one configuration step determines whether the query modules work, and per section 0.1 it is the same step that killed four rules in Northgate's estate.

Entra Admin Center

IdentityMonitoring & healthDiagnostic settingsAdd diagnostic setting
Tick SignInLogs, AuditLogs, NonInteractiveUserSignInLogs and ServicePrincipalSignInLogs, send to Log Analytics, and select the workspace. Four categories, one destination, and the course assumes all four.

It is worth understanding why this is one screen rather than four. Each category is an independent decision with its own volume and its own cost, and the platform presents them as checkboxes precisely because organizations do choose different combinations. Per section 0.2 that is also why an estate can be ingesting three of the four and nobody notices, since three ticked boxes look like a configured setting.

In a lab tenant tick all four without thinking about it: the volume is negligible and the cost is nothing. In production you will not be making this decision, and per section 0.2 the useful thing is to find out which four your organization actually sends before assuming the exercises will work.

Connect-MgGraph -Scopes "Directory.Read.All"

Get-MgBetaEntraDiagnosticSetting |
  ForEach-Object { $_.Logs } |
  Where-Object { $_.Enabled } |
  Select-Object Category | Sort-Object Category

# Category
# --------
# AuditLogs
# NonInteractiveUserSignInLogs
# ServicePrincipalSignInLogs
# SignInLogs

Two practical notes on running it. The Graph module for this is in the beta profile, so the cmdlet name carries Beta in it and the command will fail with a not-recognized error if only the v1.0 module is installed. And a tenant can hold more than one diagnostic setting, so the command deliberately expands the logs of every setting rather than the first one it finds, which is the mistake that reports a category as missing when it is being sent by a second setting nobody remembered.

Four rows is the answer you want. Fewer is not a blocker, it is information: the modules that depend on a missing category will be reading exercises rather than doing ones, and it is better to know that now than to conclude your query is broken.

04

Giving a fresh tenant something to find

Twenty minutes, and it pays for the whole course

If you took Route B, the fix for the empty-table problem is to spend twenty minutes producing the activity the queries will look for. This is worth doing deliberately rather than waiting for it to accumulate, because you can produce the specific shapes the course teaches.

Create six or seven users rather than one, because several exercises compare accounts against each other and a population of one has no distribution. Sign in as several of them, from a browser and from a phone if you have one, which produces both interactive and non-interactive records.

Register an application and give it a client secret, then use that secret to obtain a token. That single action populates AADServicePrincipalSignInLogs, creates an AuditLogs credential entry, and gives id01 something real to inventory.

The application step is the highest-value twenty minutes in this list and it is the one people skip, because registering an app feels like more work than creating a user. It is not: the app registration blade takes about two minutes, adding a secret takes thirty seconds, and obtaining a token with it can be a single PowerShell call. What you get is the only workload identity activity your lab will have, and per section 0.6 the workload population is where a third of this course lives.

Then make a handful of changes worth detecting: assign a directory role, modify a Conditional Access policy, consent to an application. Each writes an AuditLogs row, and per section 0.5 the useful part is that you will know which were legitimate, so you can test whether a rule can tell.

When the activity you generate becomes queryable A lab built this morning looks broken this afternoon and is merely new you act +15 min +1 hour next day SigninLogs, usually minutes NonInteractive and ServicePrincipal, longer AuditLogs, slowest Generate the activity, then come back tomorrow. Querying immediately teaches you nothing except that ingestion has latency.

Figure 0.16. The bars are ingestion delay, not retention. Everything you generated is already recorded; none of it is queryable yet.

One further step is worth the two minutes it takes: sign in as one of your users and deliberately fail the password three or four times before succeeding. That produces the failed-then-succeeded pattern several detection exercises look for, and it is the single most useful piece of synthetic activity in a fresh tenant because failure records carry result codes the successful ones do not.

Keep this

Generate the activity before you need it, not when a query returns nothing. Sign-in data takes minutes to appear in the workspace and audit data can take longer, so a lab built the same morning you start `id04` will look broken when it is merely new.

Doing all of that takes about twenty minutes and it is the single highest-return preparation in this course, because every exercise afterwards has something to operate on. It is also the closest a fresh tenant gets to the estate the examples use, which makes the worked answers comparable to what you see.

05

Working in production safely

The permissions, and the finding you will make

Route A raises two questions worth answering before you start rather than afterwards.

The first is permissions. Every command in this course reads, and the scopes it uses are Directory.Read.All, Application.Read.All, Policy.Read.All, AuditLog.Read.All and RoleManagement.Read.Directory. None of them writes. The directory roles that carry them are Global Reader and Security Reader, both of which are read-only by design and are a reasonable thing to ask for.

The second is what happens when an exercise produces a real finding, which per section 0.6 it frequently does within the first week. A service principal with a four-year-old secret and no owner is not a training artifact, it is a thing in your organization, and finding it in a course exercise puts you in the position of knowing something nobody asked you to look for.

It is worth being precise about the second point rather than leaving it implied. Reading an estate you do not own is not a grey area: with a read-only role, granted deliberately, running documented commands against your own organization's tenant, you are doing exactly what a Security Reader role exists for. Nothing in this course asks you to test an attack technique against production, and nothing in it needs write access.

What can become awkward is not the reading, it is what the reading turns up.

That is worth thinking about in advance. The reason this needs saying is that the situation is genuinely uncomfortable and it catches people unprepared. You were doing a training exercise, the exercise worked, and now you know about a four-year-old credential on an application with tenant-wide mail access. Nobody assigned you that, there may be no process for reporting it, and the person who owns it may not welcome the news.

The finding is more useful than the exercise, and handling it well means recording what you found and how, and taking it to whoever owns the estate, rather than either fixing it quietly or leaving it.

06

Checking the lab before module 1

Six checks, one output

Below is what a working environment looks like against what the six checks return, so you can tell a lab that is not ready from one that is ready and quiet.

The distinction that matters in that output is between not configured and configured and empty, which produce very similar-looking results and mean opposite things. Per section 0.2 the way to separate them is never to read the row count alone: check the diagnostic setting for whether the category is emitted, then check the table for whether anything is in it.

The other distinction in that output is between a query returning nothing because the estate is quiet and one returning nothing because the time window is wrong. A fresh lab has no data older than this morning, so a query filtering to the last thirty days is technically correct and structurally guaranteed to return whatever exists, while one filtering to a specific week last month returns nothing forever.

That is a small thing and it accounts for a large share of the confusion people have in the first week.

That habit is worth forming here, on your own lab, because it is the same habit id04 and id05 depend on and it is easier to learn when the stakes are a tutorial rather than an investigation. It is also the habit that would have saved the estate in section 0.1, where four enabled rules queried a table nobody had checked was arriving, and where nothing in fourteen months prompted anybody to look.

07

Practice

Get to four rows before module 1

Forty minutes on Route B, ten on Route A, and it is the difference between the course working and the course looking broken.

Do this Build the environment you will use
  1. Decide your route. If you have read access to a production tenant, take it even if you also build a lab, because the history is the part you cannot manufacture.
  2. Configure the four diagnostic categories in whichever tenant you can change, and run the command above to confirm four rows come back.
  3. On a fresh tenant, generate the activity above: several users signing in, one application with a secret that obtains a token, and three or four audit-worthy changes.
  4. Wait, then query. Sign-in data appears within minutes and audit data can take longer, so run something simple the next day rather than immediately.
  5. Write down which route you took and what is missing from it. Every module assumes something, and knowing in advance which exercises will be reading rather than doing saves the frustration of discovering it mid-module.

What you should end up with: four categories confirmed flowing, at least one query returning rows, and a written note of what your environment cannot do. That last item is the one people skip and the one that saves time in `id06`.

That completes the orientation. id01 starts with the population section 0.6 counted, and the first thing it does is ask you to inventory your own.

// reasoning-review IS NAMED HERE BECAUSE IT EMITS ITS rc-code AT RUNTIME. // This condition scans the SERVER-RENDERED content, and reasoning-review.js builds its // artifact block after fetch, so the page contains no rc-code at the moment this runs and // code-chrome never loaded. Deployed 2026-08-26 with correct markup, transparent background // and no chrome, because the class the loader looks for did not exist yet. Any future // component that writes rc-code from script has to be named here too.