Open source · MIT · Windows, macOS & Linux

Ask your tenant anything. In KQL. One query language, three data sources: Microsoft Graph, Defender hunting and Azure Resource Graph.

A desktop KQL workbench for Microsoft Graph, Defender advanced hunting and Azure Resource Graph. One query language, completion that knows the schema, and results right beside your query.

Built on .NET 10 and React. Download for Windows 11, macOS 14+ and Linux.

GRExpired app credentials
// Apps with a secret past its end date
applications
| mv-expand cred = passwordCredentials
| where todatetime(cred.endDateTime) < now()
| summarize expired = count()
    by displayName, appId
| order by expired desc
Runs locally on fetched Graph dataRequests shown before sending
Kustodian querying Microsoft Graph with KQL: schema tree, editor and a results grid

Screenshots use sample data.

Why Kustodian

OData fetches the data.
KQL answers the question.

Graph speaks OData, but $filter works on some properties and not others, and there are no joins or aggregates. You still page through results and parse the JSON yourself. Kustodian sends OData what the server can handle, then runs the rest of your KQL in memory: mv-expand, join, summarize and more.

OData by handpaging, parsing, scripting

GET /applications?$select=appId,displayName,passwordCredentials&$top=999 GET /applications?$skiptoken=… GET /applications?$skiptoken=… $filter on passwordCredentials/endDateTime: not supported → parse the JSON, flatten and compare dates in a script

In KustodianGR

applications | mv-expand cred = passwordCredentials | where todatetime(cred.endDateTime) < now() | summarize expired = count() by displayName → $filter where Graph supports it, the rest in memory

Three sources, one editor

Everything you hunt,
in one place.

GR

Microsoft Graph

Query the beta endpoint with KQL. Kustodian plans the requests, pushes what it can into $filter, and runs the rest locally.

users · applications · devices · groups …
AH

Defender advanced hunting

Hunting queries go straight to the service through security/runHuntingQuery, with the same completion and results.

DeviceProcessEvents · IdentityLogonEvents · EmailEvents …
ARG

Azure Resource Graph

Inventory and posture across your Azure estate, scoped to the subscriptions you pick.

resources · securityresources …

Explain

See every request before it’s sent.

Explain shows exactly what a Graph query will do to your tenant, without sending anything.

  • The requests. Every Graph call, including per-object reads.
  • The $filter. Which parts of your query run server-side and which run locally.
  • The permissions. The scopes a query needs, before you hit a 403.
Explain view listing the Graph requests, filter and permissions a query would use

Features

Built for the query you run
a hundred times.

Schema-aware KQL

Completion and errors from each source’s schema, including nested and mv-expanded fields.

Results, your way

Virtualized grid, charts, JSON and diagnostics. Compare two runs. Export to CSV, JSON or Markdown.

Parameters & snippets

Write {name} once and fill it at run time. Keep snippets and saved queries close.

Picks up where you left off

Tabs survive restarts. History, saved queries and a command palette for everything else.

Raw Graph requests

Send any request, like Graph Explorer, then open the response as a KQL tab to keep digging.

Keyboard first

A shortcut for every action, and light and dark themes that follow your system.

Privacy & security

Your tenant.
Your machine.

Kustodian is a desktop app that signs in as you. There is no Kustodian service in the middle, and nothing leaves your machine except calls to Microsoft.

Network
Talks only to Microsoft’s APIs.
Tokens
Cached in the OS keychain (DPAPI, Keychain or libsecret), never written in plain text.
Your data
Settings, saved queries, snippets, history and tabs are local JSON files.
Sign-in
Delegated, with your work account. Use the Azure CLI’s public client, your own app registration, or let Kustodian create one. How permissions work.
Source
MIT licensed. Read it, build it, report a vulnerability.

Permissions

Start with Azure CLI.
Grow into your own app.

Kustodian uses delegated permissions: it reads what the app you sign in with is allowed to, and never more than your own roles allow.

No setup

Azure CLI client (default)

Microsoft’s public client, already consented in most tenants. A good start for common Graph and Azure Resource Graph queries, but its permissions are fixed: security data, audit logs and advanced hunting are often out of reach.

Admin consent

Your own app registration

Grant exactly the read permissions your queries need. Kustodian can create the app for you, with the smallest set of permissions that covers your tables; an admin grants consent once.

Set up an Entra ID app registration, step by step →

Get started

Download, open, sign in.

Get the package for your platform from the latest release. Builds are self-contained: no .NET to install.

Windows 11 · x64 & Arm

MSI or portable zip

Kustodian-<version>-x64.msi (or -arm64.msi) installs for you alone, no admin rights needed. Add ALLUSERS=1 to install for everyone. Or extract Kustodian-<version>-win-x64.zip (or -win-arm64.zip) anywhere; unblock it in Properties first. On an unsigned build, SmartScreen asks once: More info → Run anyway.

> msiexec /i Kustodian-<version>-x64.msi ALLUSERS=1
macOS 14+ · Apple silicon & Intel

dmg or zip

Open Kustodian-<version>-osx-arm64.dmg (or -osx-x64.dmg; the same app is in the .zip) and drag Kustodian to Applications. The app is signed with a Developer ID and notarized by Apple, so it opens without a prompt. If a release’s notes say it’s ad-hoc signed, allow the first open in System Settings → Privacy & Security → Open Anyway.

Linux · x64

AppImage or tarball

Needs WebKitGTK 4.1, libsecret and libnotify from your distribution. chmod +x Kustodian-<version>-x86_64.AppImage, then run it; it runs without FUSE (it extracts itself), and with fuse3's fusermount, which WebKitGTK usually brings, it mounts instead. Or extract Kustodian-<version>-linux-x64.tar.gz and run ./Kustodian.

$ sudo apt-get install \
  libwebkit2gtk-4.1-0 libsecret-1-0 \
  libnotify4
$ sudo dnf install \
  webkit2gtk4.1 libsecret \
  libnotify

Then sign in with your work account and open your first tab. The install guide, step by step →

Build from source

.NET SDK 10 and Node.js 22. On Linux, also the WebKitGTK 4.1 and libsecret development packages. The build embeds the web UI for you; no separate frontend step.

$ sudo apt-get install \
  libwebkit2gtk-4.1-dev libsecret-1-dev
$ git clone https://github.com/FrodeHus/kustodian
$ cd kustodian
$ dotnet run --project src/Kustodian

Open source, and open to you.

Issues, ideas and pull requests are welcome.