Elastic Defend Operations - command-line interface for Elastic Endpoint Security / Elastic Defend response actions. Isolate hosts, kill processes, retrieve files, execute commands, run osquery queries, investigate alerts, inspect session views, and run a semi-interactive shell — all from the terminal, directly against the Kibana response actions API.
Built and tested on Elastic Stack 9.3.3, but most of it should work on 8.19.+ also.
Generate your own: install VHS, set
EDOPS_KIBANA_URLandEDOPS_KIBANA_API_KEY, then runvhs docs/tapes/demo-main.tape. Seedocs/tapes/for tapes covering individual features.
- Response actions — isolate, unisolate, kill/suspend processes, get files, execute commands, upload files, scan, memory dump
- osquery — run live queries, fetch results, list saved queries
- Session View — render the process tree and terminal I/O captured by Elastic for any detection alert
- Fleet agents — list enrolled agents, filter by hostname prefix, IP, or MAC address
- Interactive console — endpoint-scoped console with tab-completion for all commands
- Semi-interactive shell — execute actions wrapped as a remote shell session (stdout/stderr rendered locally)
- Alerts — query Elastic Security detection alerts, globally or per endpoint
- JSON output on every command for scripting and piping
- Comment/ticket traceability — stamp every API call with a ticket reference
- Flexible auth — API key or username/password; config file,
.env, environment variables, or global CLI flags per invocation
SOC analysts, blue teams, and incident responders.
Applicability beyond that
is neither the goal nor the focus.
This CLI is built to interact with Elastic Kibana, Fleet, Elastic Agent and Elastic Endpoint Security (XDR) for endpoint visibility and response actions.
- Python 3.10+
- Elastic Stack 9.x (Enterprise license required)
- Elastic Agent enrolled via Fleet with Endpoint Security enabled on target endpoints
- Kibana user with the correct role for response actions
pip install edopspipx is recommended for CLI tools — it installs in an
isolated environment and puts edops on your PATH:
pipx install edopsgit clone https://github.com/renini/edops.git
cd edops
pip install -e .
# or
pipx install -e .# 1. Point at your Kibana instance
edops config set --url https://kibana.lab.internal:5601
edops config set --api-key # prompts with hidden input — nothing in shell history
# 2. Find your endpoint
edops agents workstation-01
# 3. Act on it (agent ID from step 2)
edops execute <agent-id> --command "whoami" --comment "INC-1337"Settings are stored in ~/.config/edops/config.json (mode 0600).
edops config set --url https://kibana.lab.internal:5601
edops config set --api-key # prompts with hidden input — nothing stored in shell history
edops config show| Option | Default | Description | |---|---|---| | --url | — | Kibana URL | |
--api-key | — | API key (base64 id:key); omit value to be prompted | |
--username / --password | — | Basic auth alternative to API key;
--password omit value to be prompted | | --space-id | default | Kibana
space | | --ca-cert | — | Path to CA bundle for self-signed certs | |
--no-verify-ssl | — | Disable TLS verification (never use against production)
| | --require-comment / --no-require-comment | on | Require a ticket
reference on every action | | --persist-history / --no-persist-history | off
| Save console/shell command history to ~/.config/edops/ across sessions |
- Global CLI flags (
--url,--api-key,--username,--password) — per-invocation override - Shell environment variables (
EDOPS_KIBANA_*) .envfile in the current working directoryconfig.json- Auto-prompt — if nothing provides a URL or credentials, edops asks interactively
| Variable | Description | |---|---| | EDOPS_KIBANA_URL | Kibana base URL
(e.g. https://kibana.lab.internal:5601) | | EDOPS_KIBANA_API_KEY | API key
(base64 id:key) | | EDOPS_KIBANA_USERNAME | Username for basic auth | |
EDOPS_KIBANA_PASSWORD | Password for basic auth | | EDOPS_KIBANA_VERIFY_SSL
| Set to false to skip TLS verification | | EDOPS_KIBANA_CA_CERT | Path to a
custom CA certificate bundle | | EDOPS_KIBANA_SPACE_ID | Kibana space ID
(default: default) |
Place a .env in your working directory to set credentials without exporting
shell variables — useful when working against multiple stacks from different
project directories:
# .env (add to .gitignore — never commit this file)
EDOPS_KIBANA_URL=https://kibana.lab.internal:5601
EDOPS_KIBANA_API_KEY=<base64-id:key>API key (recommended) — generate in Kibana → Stack Management → API keys:
edops config set --api-key # hidden prompt, nothing in shell history
edops config set --api-key <base64> # pass directlyUsername / password:
edops config set --username elastic
edops config set --password # hidden promptPer-invocation override — useful on shared machines or when switching stacks:
edops --url https://kibana.lab.internal:5601 --api-key <base64> processes <agent-id>
edops --api-key processes <agent-id> # prompts for key, uses URL from config
edops --url https://staging:5601 agents workstation-01edops config set --ca-cert /path/to/ca.crt # custom CA for self-signed certs
edops config set --no-verify-ssl # disable verification (not for production)| Command | Description | |---|---| | edops agents [query] | List enrolled
Fleet agents, filter by hostname prefix, IP, or MAC — omit to list all | |
edops agents --online | Only show agents currently online | |
edops metadata <agent-id> | Show OS, agent version, policy, capabilities,
isolation state |
edops agents # all enrolled agents
edops agents WIN-VM-01 # hostname prefix match
edops agents 10.10.10. # all agents on 10.10.10.x
edops agents de:ad:be # MAC address prefix
edops agents --online # all agents currently online
edops agents WIN-VM-01 --online # hostname prefix, online only| Command | Description | |---|---| | edops isolate <agent-id> | Isolate a
host from the network | | edops unisolate <agent-id> | Release network
isolation |
Both accept --wait to poll until the action completes, --comment for
traceability, and --json for raw output.
edops isolate <agent-id> --comment "INC-1337 ransomware containment" --wait
edops unisolate <agent-id> --comment "INC-1337 containment lifted" --wait| Command | Description | |---|---| | edops processes <agent-id> | List
running processes | | edops kill-process <agent-id> --pid <pid> | Terminate a
process by PID | | edops kill-process <agent-id> --entity-id <id> | Terminate
by process entity ID | | edops suspend-process <agent-id> --pid <pid> |
Suspend a process by PID | | edops suspend-process <agent-id> --entity-id <id>
| Suspend by process entity ID |
| Command | Description | |---|---| | edops execute <agent-id> --command <cmd>
| Execute a shell command and return stdout/stderr | |
edops get-file <agent-id> --path <path> | Retrieve a file from the endpoint |
| edops upload <agent-id> --file <local-path> | Upload a local file to the
endpoint | | edops scan <agent-id> --path <path> | Scan a file or directory
with Elastic Defend | | edops memory-dump <agent-id> | Full kernel memory dump
(Windows only) | | edops memory-dump <agent-id> --pid <pid> | Process memory
dump |
edops execute <agent-id> --command "whoami && hostname" --comment INC-1337
edops execute <agent-id> --command "heavyscript.ps1" --timeout 300 --comment INC-1337
edops get-file <agent-id> --path "C:\Users\analyst\Desktop\suspicious.exe" \
--output-dir ./evidence --comment INC-1337
edops scan <agent-id> --path "/tmp/dropped_file" --comment INC-1337edops alerts # all alerts from the last 24 hours
edops alerts <agent-id> # alerts for a specific endpoint
edops alerts <agent-id> --status open # filter by status: open, acknowledged, closed
edops alerts <agent-id> --since 7d # time window: 30m, 6h, 7d, etc.
edops alerts --json | jq '.hits.total.value' # total alert count across all endpointsRender the process tree and captured terminal I/O for any detection alert — equivalent to Kibana's Session View, but in the terminal:
edops session-view <alert-id>The <alert-id> is the document _id from the alert, visible via
edops alerts --json:
# Get alert IDs for a specific endpoint
edops alerts <agent-id> --json | jq -r '.hits.hits[]._id'
# Inspect the full attack chain for an alert
edops session-view 55485a1b9d9a0348d3f0328cf6565665b2e8d280a2692e40b8c35ba586750be6Session View 55485a1b9d9a0… 2026-05-03 14:10:46
Rule: Malware Prevention Alert
Process Tree
root sshd-session (11793)
└── analyst -bash (11820) [I/O]
└── root sudo -s (11822)
└── root su (11830) [I/O]
├── root ps fax (11831)
├── root wget https://secure.eicar.org/eicar.com (12085)
├── root vim malware (12100) [I/O] ◄ alerted
└── root wget https://nothing.malicious.example.org (12099)
Export the terminal I/O for an alert's session to an asciicast file for archiving, sharing, or converting to GIF/MP4:
edops session-export <alert-id> # save to tty_<alert-id[:16]>.cast
edops session-export <alert-id> --output session.cast # custom filename
edops session-export <alert-id> --comment INC-1337 # filename becomes tty_INC-1337-id.cast
edops session-export <alert-id> --force # overwrite existing file
edops session-export <alert-id> --gif # also produce a GIF via agg
edops session-export <alert-id> --mp4 # also produce an MP4 via agg + ffmpeg
edops session-export <alert-id> --no-intro # skip the 2-second animated introReplay a session as live terminal output — accepts an alert ID or a .cast file:
edops session-play <alert-id> # replay the alerted process's I/O
edops session-play <alert-id> --all # include I/O from all session processes
edops session-play session.cast # replay a previously exported .cast file
edops session-play <alert-id> --yes # skip the safety prompt# Run a live query and wait for results
edops osquery run <agent-id> --query "SELECT name, pid, path FROM processes LIMIT 10"
# Use a saved query or a pack
edops osquery run <agent-id> --saved-query-id my-query
edops osquery run <agent-id> --pack-id my-pack
# Fire and forget — fetch results later
edops osquery run <agent-id> --query "SELECT * FROM users" --no-wait
edops osquery results <action-id> <query-action-id>
# List all saved queries
edops osquery saved-queriesedops status <action-id> # status and per-agent output of a response action
edops actions # list recent response actions
edops actions <endpoint-id> # filter by endpoint
edops actions --command execute # filter by command type (isolate, execute, etc.)
edops actions --page 2 --page-size 50 # paginationA full response console scoped to a single endpoint. All commands run against the same agent — no need to repeat the agent ID. Tab-completion is available for commands and their flags.
edops console <agent-id> --comment INC-1337Elastic Defend >_ Respond console endpoint=<agent-id> host=WIN-VM-01 os=Windows 10 Pro ip=10.10.10.11
[WIN-VM-01]> processes
[WIN-VM-01]> execute --command "net localgroup administrators"
[WIN-VM-01]> alerts --status open
[WIN-VM-01]> osquery --query "SELECT name, path FROM processes WHERE on_disk = 0"
[WIN-VM-01]> isolate --wait
[WIN-VM-01]> comment INC-5678 # change the active ticket reference mid-session
[WIN-VM-01]> exit
Available console commands: isolate, unisolate, processes, kill-process,
suspend-process, get-file, execute, upload, scan, memory-dump,
status, actions, alerts, osquery, osquery-results, osquery-saved,
metadata, shell, comment, help, exit
Semi-interactive shell that wraps execute response actions. Each command you
type is dispatched as an Elastic response action; stdout/stderr are extracted
from the returned zip and printed locally.
edops shell <agent-id> --comment INC-1337Edops Shell <agent-id>
Ctrl+D or 'exit' to quit · commands routed via Kibana execute action
[65d97abd]> whoami
nt authority\system
[65d97abd]> net localgroup administrators
Alias name administrators
...
[65d97abd]> exit
Note: Each command is a separate API round-trip (submit → poll → download). Expect 3–10 seconds per command depending on network and endpoint load.
Files returned by get-file, execute (when output is large), and
memory-dump are saved as password-protected zip archives. The password is
always elastic.
edops get-file <agent-id> --path "C:\Users\analyst\Desktop\suspicious.exe" \
--output-dir ./evidence --comment INC-1337
unzip -P elastic ./evidence/INC-1337_suspicious.exe.zipThe filename is prefixed with the --comment value when provided (e.g.
INC-1337_suspicious.exe.zip), making it easy to organise evidence by case.
Every response action accepts --comment to attach a ticket or case reference.
This is recorded in the Kibana action log and is visible in the Security app.
edops isolate <agent-id> --comment "INC-1337 - ransomware containment"Enforce comments across all actions:
edops config set --require-commentWith this set, any action without --comment will be rejected before hitting
the API.
In edops console, change the active comment mid-session without leaving:
[WIN-VM-01]> comment INC-5678
These flags are accepted before any subcommand:
edops --version # show version and exit
edops --verbose <command> # print each HTTP request and response
edops --url <url> <command> # override Kibana URL for this invocation
edops --api-key <key> <command> # override API key for this invocation
edops --api-key <command> # prompt for API key with hidden input
edops --username <u> --password <p> <command> # basic auth override
edops --password <command> # prompts for password with hidden input
edops --help # show top-level help
edops <command> --help # show help for a specific command
Elastic Endpoint Security (XDR) operates with high privileges across endpoints. This tool interfaces directly with its control plane.
- Treat access as extremely sensitive
- Audit and monitor usage — every action is stamped in the Kibana action log
- Compromised XDR access == GAME OVER
Credentials are stored in ~/.config/edops/config.json (mode 0600). Prefer
environment variables or per-invocation flags on shared systems. Never commit
credentials to version control.
API keys (Kibana → Stack Management → API keys) are preferred over username/password:
- Scoped to specific privileges
- Revocable without changing the account password
- Auditable individually in the Kibana audit log
Never use --no-verify-ssl against a production stack. If your Kibana uses a
self-signed or internal CA, use --ca-cert instead:
edops config set --ca-cert /path/to/internal-ca.crtCommand history in edops shell and edops console is not persisted by
default. Enable it only if you understand the tradeoff:
edops config set --persist-history # saves to ~/.config/edops/{shell,console}_history- Endgame (now part of Elastic) — for the high-end endpoint security solution, which offers great resistance against cyber threat actors.
- Elastic — for the powerful stack and getting the wider community involved in cybersecurity defense, by being transparent on detection methods and tooling (i.e. YARA rules and other detection rules).
- Anthropic — for their assisted AI coding software; this project was created from idea to code with their top-tier models, credits $$ and Claude Code.

