| Crates.io | kql-panopticon |
| lib.rs | kql-panopticon |
| version | 0.4.0 |
| created_at | 2025-10-16 01:21:00.683013+00 |
| updated_at | 2025-12-18 23:05:12.385944+00 |
| description | Pack-based query execution framework for Azure Log Analytics with data collection, processing, and reporting |
| homepage | |
| repository | https://github.com/dolly-parseton/kql-panopticon |
| max_upload_size | |
| id | 1885197 |
| size | 3,300,033 |
KQL tooling for Azure Log Analytics - concurrent multi-workspace queries, chained investigations, HTTP enrichment, and automated reports.
Browse and execute reusable query packs from your library
Edit queries with Normal, Insert, and Visual modes
Monitor query execution with detailed job information and organized output
{{step.*.Column}} syntax - no manual extraction neededTested and supported:
Theoretical Windows support:
PathBuf, dirs crate)azure_identity crateWindows-specific notes:
%USERPROFILE%\.kql-panopticon\ (instead of ~/.kql-panopticon/)%USERPROFILE%\.azure\msal_token_cache.jsonThe CI pipeline builds and tests on windows-latest, so basic functionality should work. Community testing and feedback on Windows is welcome.
az login)cargo install kql-panopticon
git clone https://github.com/dolly-parseton/kql-panopticon.git
cd kql-panopticon
cargo build --release
The binary will be located at target/release/kql-panopticon.
Launch the terminal interface:
kql-panopticon
The application will:
Execute a query pack across workspaces:
# Run pack on all workspaces
kql-panopticon run-pack security/failed-auth.yaml
# Run pack on specific workspaces
kql-panopticon run-pack security/failed-auth.yaml --workspaces ws-prod-01,ws-prod-02
# Validate pack without executing
kql-panopticon run-pack security/failed-auth.yaml --validate-only
# Export session as reusable pack
kql-panopticon export-pack my-session-name
Execute chained queries with variable extraction:
# Run investigation with input variables
kql-panopticon run-investigation threat-hunt.yaml --set target_ip=10.0.0.1
# Validate investigation pack
kql-panopticon run-investigation threat-hunt.yaml --validate-only
Logs are written to kql-panopticon.log in the current directory.
Query packs separate reusable query definitions from execution results (sessions), enabling version control, team collaboration, and AI-assisted query generation.
Minimal format (single query):
# ~/.kql-panopticon/packs/security/failed-auth.yaml
name: "Failed Authentication Investigation"
query: |
SecurityEvent
| where EventID == 4625
| where TimeGenerated > ago(24h)
| summarize FailedAttempts=count() by Account, Computer
| order by FailedAttempts desc
Full format (multi-query investigation):
name: "Failed Authentication Investigation"
description: "Hunt for brute force and credential stuffing patterns"
author: "Security Team"
version: "1.0"
queries:
- name: "Failed Logins Baseline"
description: "Last 24h failed login volume"
query: |
SecurityEvent
| where EventID == 4625
| where TimeGenerated > ago(24h)
| summarize count() by Account
- name: "Brute Force Detection"
description: "Accounts with >10 failures in 5min windows"
query: |
SecurityEvent
| where EventID == 4625
| summarize Attempts=count() by Account, bin(TimeGenerated, 5m)
| where Attempts > 10
settings:
export_csv: true
export_json: false
parse_dynamics: true
workspaces:
scope: all # "all", "selected", or "pattern"
From CLI:
# Execute pack (creates session with results)
kql-panopticon run-pack security/failed-auth.yaml
# Override workspace selection
kql-panopticon run-pack test.yaml --workspaces all
# JSON output to stdout
kql-panopticon run-pack test.yaml --format stdout --json
From TUI:
6 to go to Packs tabUp/Down to select packEnter to load first query into editore to execute entire pack across selected workspacesConvert a refined query session back to a reusable pack:
From CLI:
# Export to default location: ~/.kql-panopticon/packs/<session-name>.yaml
kql-panopticon export-pack my-session-name
# Export to custom path
kql-panopticon export-pack my-session-name --output /path/to/pack.yaml
# Export as JSON
kql-panopticon export-pack my-session-name --format json
From TUI:
5 to go to Sessions tabUp/Down to select sessionp to export as pack~/.kql-panopticon/packs/ and appears in Packs tab~/.kql-panopticon/packs/security/ransomware.yamlkql-panopticon run-pack security/ransomware.yamlp in Sessions tabFor complete schema reference and examples, see Query Packs Documentation.
Investigation packs chain queries together - results from step 1 feed into step 2, and so on. They also support HTTP steps for external API enrichment and report generation with verdict rules.
kind: investigation
name: "Phishing Investigation"
inputs:
- name: malicious_url
description: "URL to investigate"
steps:
- name: url_clicks
query: |
UrlClickEvents
| where Url contains "{{inputs.malicious_url}}"
| project UserPrincipalName, Url, TimeGenerated
- name: user_activity
depends_on: [url_clicks]
query: |
SigninLogs
| where UserPrincipalName in ({{url_clicks.*.UserPrincipalName}})
No explicit extract block needed - just reference columns directly via {{step.*.Column}}.
Call external APIs mid-investigation:
- name: domain_whois
type: http
depends_on: [suspicious_domains]
foreach: "suspicious_domains as domain"
request:
method: POST
url: "https://api.example.com/whois"
auth: azure # or use secrets
body:
domain: "{{domain.SenderDomain}}"
response:
fields:
created: "$.created"
registrar: "$.registrar.name"
rate_limit:
requests: 5
per: second
on_error: continue
# Execute with input variables
kql-panopticon run-investigation phishing.yaml --set malicious_url=evil.com
# Validate without executing
kql-panopticon run-investigation phishing.yaml --validate-only
For complete schema reference, condition syntax, scoring engine, and examples, see Investigation Packs Documentation.
The interface consists of seven tabs accessible via number keys (1-7) or Tab/Shift+Tab:
Configure application behavior.
Navigation:
Up/Down: Select settingEnter: Edit selected settingEsc: Cancel editEnter (while editing): Save changesAvailable Settings:
./output)Select target workspaces for query execution.
Navigation:
Up/Down: Navigate workspace listSpace: Toggle selection of current workspacea: Select all workspacesn: Deselect all workspacesr: Refresh workspace list from AzureDisplay Information: Each workspace shows:
Selected workspaces are marked with [x].
Write and execute KQL queries using a Vim-style editor.
Editor Modes:
Normal Mode (default):
i: Enter Insert mode (edit at cursor)a: Enter Insert mode after cursorA: Enter Insert mode at end of lineo: Open new line below and enter Insert modeO: Open new line above and enter Insert modev: Enter Visual mode (text selection)h/j/k/l or Arrow Keys: Move cursor0: Move to start of line$: Move to end of lineg: Move to top of documentG: Move to bottom of documentx: Delete character under cursorCtrl+d: Delete current linec: Clear all textCtrl+u: UndoCtrl+r: RedoInsert Mode:
Esc: Return to Normal modeVisual Mode:
h/j/k/l or Arrow Keys: Extend selectiony: Copy (yank) selected textd or x: Delete selected textEsc: Return to Normal modeQuery Management:
Ctrl+j: Execute query (works in any mode)
l: Load query from previous job
i: Invert sort orderExample Query:
SecurityEvent
| where TimeGenerated > ago(24h)
| where EventID == 4624
| summarize LoginCount = count() by Account, Computer
| order by LoginCount desc
| take 100
Monitor query execution and view results.
Navigation:
Up/Down: Select jobEnter: View job details (status, timing, output path, errors)r: Retry selected job (failed or completed jobs only)
c: Clear all completed and failed jobs from listEsc (in details view): Close details popupJob Status:
Job Information: Each job displays:
Jobs with full query context can be retried or loaded in the Query tab.
Save and load complete application state including jobs, queries, and settings.
Navigation:
Up/Down: Navigate sessions listr: Refresh sessions list from disks: Save current session
Shift+S: Save as new session (prompts for name)n: Create new session (prompts for name)l: Load selected session
d: Delete selected session from diskp: Export selected session as query pack
Session Information: Each session displays:
[CURRENT]: Currently active session, saved[CURRENT*]: Currently active session, has unsaved changes[CURRENT - UNSAVED]: Active session never saved to diskSessions are stored in the config directory's sessions/ subdirectory as JSON files.
Browse and execute query packs from your library.
Navigation:
Up/Down: Navigate packs listEnter: Load first query from pack into Query tabe: Execute entire pack on selected workspaces
r: Refresh packs list from diskDisplay Information: Each pack shows:
Packs are loaded from the config directory's packs/ subdirectory (supports subdirectories).
Browse and execute investigation packs for chained query workflows.
Navigation:
Up/Down: Navigate investigation listEnter: View investigation detailse: Execute selected investigation on selected workspacesr: Refresh investigation list from diskInvestigation packs enable multi-step queries where results from earlier steps feed into subsequent queries. See Investigation Packs Documentation for full schema and examples.
CSV/JSON files are organized hierarchically:
output/
└── {subscription_name}/
└── {workspace_name}/
└── {timestamp}/
└── {job_name}_{query_name}.csv
Example:
output/
└── sentinel_watchlist_dev/
└── la-sentinelworkspace/
└── 2025-11-08_18-46-20/
├── security-hunt_failed-logins.csv
└── security-hunt_brute-force-detection.csv
Subscription and workspace names are normalized (lowercase, alphanumeric + hyphens/underscores only).
When executing query packs with multiple queries, each query gets its own file with a sanitized query name suffix to prevent conflicts.
These shortcuts work from any tab (except when in Insert mode in the Query tab):
1: Switch to Query tab2: Switch to Packs tab3: Switch to Investigations tab4: Switch to Workspaces tab5: Switch to Settings tab6: Switch to Jobs tab7: Switch to Sessions tabTab: Next tabShift+Tab: Previous tabq: Quit applicationkql-panopticon run-pack <pack> [OPTIONS]
Arguments:
<pack> Path to query pack file (.yaml, .yml, or .json)
Can be absolute path or relative to ~/.kql-panopticon/packs/
Options:
-w, --workspaces <WORKSPACES> Override workspace selection (comma-separated IDs or 'all')
-f, --format <FORMAT> Output format [default: files] [possible values: files, stdout]
--json Print results to stdout as JSON
--validate-only Validate pack without executing
-h, --help Print help
kql-panopticon export-pack <session> [OPTIONS]
Arguments:
<session> Session name to export
Options:
-o, --output <OUTPUT> Output path (default: ~/.kql-panopticon/packs/<session-name>.yaml)
-f, --format <FORMAT> Output format [default: yaml] [possible values: yaml, json]
-h, --help Print help
kql-panopticon run-investigation <pack> [OPTIONS]
Arguments:
<pack> Path to investigation pack file (.yaml, .yml, or .json)
Can be absolute path or relative to ~/.kql-panopticon/investigations/
Options:
-s, --set <KEY=VALUE> Set input variable (can be used multiple times)
-w, --workspaces <LIST> Workspace selection (comma-separated IDs or 'all')
-o, --output <PATH> Override output base directory
--validate-only Validate pack without executing
--json Print results to stdout as JSON
-h, --help Print help
See Investigation Packs Documentation for full schema, examples, and usage guide.
The tool uses Azure CLI authentication tokens (stored in ~/.azure/msal_token_cache.json on macOS/Linux, or %USERPROFILE%\.azure\msal_token_cache.json on Windows). Ensure you're logged in before running:
az login
If you have multiple tenants, specify the correct one:
az login --tenant YOUR_TENANT_ID
Authentication is validated on startup and periodically based on the configured validation interval.
"Terminal too small" error: Resize your terminal to at least 80 columns by 24 rows.
"Authentication failed" on startup:
Run az login to refresh your Azure CLI credentials.
No workspaces found:
Ensure your account has Log Analytics Reader or higher permissions on at least one workspace.
Query times out: Increase the timeout value in Settings tab or optimize your query.
Jobs stuck in "Running" state:
Check kql-panopticon.log for error details. The job may have exceeded the timeout or encountered a network error.
Sessions not appearing on startup:
Ensure session files exist in the config directory's sessions/ subdirectory. Press r in the Sessions tab to manually refresh the list.
Query pack validation fails:
Ensure pack has either query field (single query) or queries array (multiple queries), but not both. Use --validate-only flag to check.
Pack export shows "no queries to export": The session may not have stored query context. Only jobs created with full context (query, workspace, settings) can be exported.
The application uses The Elm Architecture (TEA) pattern for the terminal UI:
Query execution happens asynchronously via Tokio, with results communicated back to the UI through channels.
Query packs provide a clean separation of concerns:
Create reusable investigation packs for common threat scenarios. Execute across all workspaces, review results, refine queries, and share improved packs with the team.
Build query packs for compliance checks. Schedule execution via CLI in CI/CD pipelines. Track investigation sessions with full context.
Load pre-built query packs for rapid triage. Execute across affected workspaces. Export refined queries as updated packs for future incidents.
Generate query packs using AI assistants. Validate and execute in one command. Iteratively improve queries based on results.
Configuration and data stored in home directory (on macOS/Linux: ~/.kql-panopticon/, on Windows: %USERPROFILE%\.kql-panopticon\):
.kql-panopticon/
├── packs/ # Query pack library
│ ├── security/
│ │ ├── failed-auth.yaml
│ │ └── ransomware.yaml
│ └── compliance/
│ └── audit-logs.yaml
├── investigations/ # Investigation pack library
│ ├── threat-hunting/
│ │ └── phishing-investigation.yaml
│ └── incident-response/
│ └── lateral-movement.yaml
└── sessions/ # Saved sessions
├── investigation-2025-01-15.json
└── baseline-queries.json
MIT License - see LICENSE file for details.
Contributions are welcome. Please open an issue before submitting major changes to discuss the proposed modifications.
This application uses Unicode box-drawing characters for the TUI interface. For the best experience, use a modern terminal emulator with proper Unicode support:
Recommended terminals:
Known issues:
If you experience visual issues with borders, consider switching to one of the recommended terminal emulators.