Metadata-Version: 2.4
Name: edops
Version: 0.1.2
Summary: Elastic Defend Operations - Response Actions CLI for Elastic Endpoint Security XDR
Project-URL: Repository, https://github.com/renini/edops
Project-URL: Bug Tracker, https://github.com/renini/edops/issues
Project-URL: Changelog, https://github.com/renini/edops/blob/main/CHANGELOG.md
License: MIT
License-File: LICENSE
Keywords: defend,dfir,edr,elastic,endpoint,kibana,response-actions,security,soc
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27.0
Requires-Dist: prompt-toolkit>=3.0.0
Requires-Dist: rich>=13.0.0
Requires-Dist: typer[all]>=0.12.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Description-Content-Type: text/markdown

![edops logo](docs/edops-logo.png)

# edops

[![PyPI version](https://img.shields.io/pypi/v/edops.svg)](https://pypi.org/project/edops/)
[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
[![Elastic 8.x](https://img.shields.io/badge/elastic-8.x-005571.svg)](https://www.elastic.co/)
[![Elastic 9.x](https://img.shields.io/badge/elastic-9.x-005571.svg)](https://www.elastic.co/)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)

**Elastic Defend Operations** - command-line interface for
[Elastic Endpoint Security / Elastic Defend](https://www.elastic.co/security/endpoint-security)
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.

______________________________________________________________________

## Demo

![edops demo](docs/demo.gif)

> **Generate your own:** install [VHS](https://github.com/charmbracelet/vhs),
> set `EDOPS_KIBANA_URL` and `EDOPS_KIBANA_API_KEY`, then run
> `vhs docs/tapes/demo-main.tape`. See [`docs/tapes/`](docs/tapes/) for tapes
> covering individual features.

______________________________________________________________________

## 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

______________________________________________________________________

## Target Audience

SOC analysts, blue teams, and incident responders.<br> 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**.

______________________________________________________________________

## Requirements

- 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

______________________________________________________________________

## Installation

### From PyPI

```bash
pip install edops
```

[pipx](https://pipx.pypa.io/) is recommended for CLI tools — it installs in an
isolated environment and puts `edops` on your PATH:

```bash
pipx install edops
```

### From source

```bash
git clone https://github.com/renini/edops.git
cd edops
pip install -e .
# or
pipx install -e .
```

______________________________________________________________________

## Quick Start

```bash
# 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"
```

______________________________________________________________________

## Configuration

Settings are stored in `~/.config/edops/config.json` (mode `0600`).

```bash
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 |

### Credential priority (highest to lowest)

1. Global CLI flags (`--url`, `--api-key`, `--username`, `--password`) —
   per-invocation override
1. Shell environment variables (`EDOPS_KIBANA_*`)
1. `.env` file in the current working directory
1. `config.json`
1. Auto-prompt — if nothing provides a URL or credentials, edops asks
   interactively

### Environment variables

| 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`) |

### .env file

Place a `.env` in your working directory to set credentials without exporting
shell variables — useful when working against multiple stacks from different
project directories:

```bash
# .env  (add to .gitignore — never commit this file)
EDOPS_KIBANA_URL=https://kibana.lab.internal:5601
EDOPS_KIBANA_API_KEY=<base64-id:key>
```

### Authentication

**API key** (recommended) — generate in Kibana → Stack Management → API keys:

```bash
edops config set --api-key              # hidden prompt, nothing in shell history
edops config set --api-key <base64>     # pass directly
```

**Username / password**:

```bash
edops config set --username elastic
edops config set --password             # hidden prompt
```

**Per-invocation override** — useful on shared machines or when switching
stacks:

```bash
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-01
```

### TLS

```bash
edops 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)
```

______________________________________________________________________

## Commands

### Endpoint discovery

| 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 |

```bash
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
```

### Isolation

| 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.

```bash
edops isolate <agent-id> --comment "INC-1337 ransomware containment" --wait
edops unisolate <agent-id> --comment "INC-1337 containment lifted" --wait
```

### Process management

| 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 |

### File operations

| 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 |

```bash
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-1337
```

### Security alerts

```bash
edops 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 endpoints
```

### Session View

Render the process tree and captured terminal I/O for any detection alert —
equivalent to Kibana's Session View, but in the terminal:

```bash
edops session-view <alert-id>
```

The `<alert-id>` is the document `_id` from the alert, visible via
`edops alerts --json`:

```bash
# 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 55485a1b9d9a0348d3f0328cf6565665b2e8d280a2692e40b8c35ba586750be6
```

```
Session 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)
```

### Session Export

Export the terminal I/O for an alert's session to an
[asciicast](https://docs.asciinema.org/manual/asciicast/v3/) file for
archiving, sharing, or converting to GIF/MP4:

```bash
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 intro
```

### Session Play

Replay a session as live terminal output — accepts an alert ID or a `.cast` file:

```bash
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
```

### osquery

```bash
# 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-queries
```

### Action management

```bash
edops 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           # pagination
```

______________________________________________________________________

## Interactive Modes

### Console

A 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.

```bash
edops console <agent-id> --comment INC-1337
```

```
Elastic 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`

### Shell

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.

```bash
edops shell <agent-id> --comment INC-1337
```

```
Edops 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.

______________________________________________________________________

## File Retrieval

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`.

```bash
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.zip
```

The filename is prefixed with the `--comment` value when provided (e.g.
`INC-1337_suspicious.exe.zip`), making it easy to organise evidence by case.

______________________________________________________________________

## Comment and Ticket Traceability

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.

```bash
edops isolate <agent-id> --comment "INC-1337 - ransomware containment"
```

Enforce comments across all actions:

```bash
edops config set --require-comment
```

With 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
```

______________________________________________________________________

## Global Options

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
```

______________________________________________________________________

## Security Notes

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**

### Credential storage

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 key vs. username/password

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

### TLS

Never use `--no-verify-ssl` against a production stack. If your Kibana uses a
self-signed or internal CA, use `--ca-cert` instead:

```bash
edops config set --ca-cert /path/to/internal-ca.crt
```

### Shell and console history

Command history in `edops shell` and `edops console` is **not** persisted by
default. Enable it only if you understand the tradeoff:

```bash
edops config set --persist-history   # saves to ~/.config/edops/{shell,console}_history
```

______________________________________________________________________

## Credits and Acknowledgements

- **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](https://claude.ai/code).

______________________________________________________________________

## License

[MIT](LICENSE)
