Skip to content

About

Operate Elastic Security as code with a safety-first CLI for security engineers.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

elasticctl

CI CodeQL crates.io Release License

A safety-first command-line tool and Model Context Protocol (MCP) server for operating Elastic Security as code on self-managed stacks, Elastic Cloud Hosted deployments, and Elastic Cloud Serverless projects. Keep detection rules, exception lists, and value lists in Git, triage alerts and cases, move data views, dashboards, and Fleet policies between stacks, and query Elasticsearch. It is a sibling to splunkctl and shares its operating contracts: dry-run-by-default changes, named profiles, stable output, and typed errors.

This is a personal, unofficial project, not affiliated with or endorsed by Elastic. Expect breaking changes in minor releases until 1.0.0.

Examples run elkctl, a short alias for the same binary as elasticctl. Every install method puts both names on PATH. The project, the crate on crates.io, and the GitHub repository stay named elasticctl.

Install

From crates.io, with the stable Rust toolchain:

cargo install elasticctl

This installs both binaries. Not every release reaches crates.io, so this can be a version behind. GitHub Releases always carry the newest version.

Or use a prebuilt binary. Each release ships archives for Linux (glibc and musl), macOS (Intel and Apple Silicon), and Windows, each containing both binaries. The installer scripts put them on PATH:

# macOS and Linux
curl --proto '=https' --tlsv1.2 -LsSf \
  https://github.com/dannyota/elasticctl/releases/latest/download/elasticctl-installer.sh \
  | sh
# Windows
powershell -ExecutionPolicy Bypass -c "irm https://github.com/dannyota/elasticctl/releases/latest/download/elasticctl-installer.ps1 | iex"

Quick start

Create a profile from ELASTICCTL_* environment variables; .env.example documents them. Use an Elasticsearch API key created inside Kibana, scoped to the project or deployment. An organization-level Cloud key is not supported: Hosted refuses it, and MCP planning refuses it on every flavor, though Serverless 9.7.0 accepts it for CLI rule changes.

export ELASTICCTL_KIBANA_URL=https://YOUR-PROJECT.kb.YOUR-REGION.aws.elastic.cloud
export ELASTICCTL_API_KEY=...
elkctl config init --from-env
elkctl doctor   # checks reachability, key scope, and rule access

Keep rules in a directory and review drift before pushing:

elkctl state pull --dir state   # writes rules/, exceptions/, and value-lists/
# edit rules, or add new ones
elkctl state diff --dir state   # field-level drift, no changes made
elkctl state push --dir state   # preview only
elkctl state push --dir state --yes

Every remote change previews first and applies only with --yes. state push never deletes a remote rule, exception list, or value list. See Getting Started and Rules as Code.

A state directory that holds value-lists/ needs elasticctl 0.10 or later to push. 0.9.4 refuses it; 0.9.0 to 0.9.3 would push its exceptions without its value lists.

Coverage

Area Supports Guide
Rules as code Pull, diff, and push rules, their exception lists, and the value lists those use, with change-evidence reports Rules as Code
Rules List, get, validate, enable, disable, delete, export, import, preview; prebuilt status and install Rules
Exceptions List, get, validate, export, import, and delete exception lists with their items Exceptions
Value lists List, get, validate, export, import, and delete value lists with exact value reconciliation; bootstrap a space Value Lists
Search ES|QL and Query DSL peeks and full exports Search
Alerts and cases Alert status, tags, and assignees; case create, comment, attach, close, reopen, delete Alerts and Cases
Data views and dashboards Portable files, the default data view, reference-safe delete, Saved Objects bundles Data Views and Dashboards
Fleet Agent and integration policies as portable files Fleet
MCP Twenty-four read-only tools, among them the task tools alert_context, rule_health, detection_coverage, and rule_readiness; two opt-in query tools; opt-in rule enable, disable, and disabled create, alert status and tags, and case create, comment, and status, through stored plans a person confirms MCP, MCP Mutations
Stack Profiles, doctor, and info Configuration

MCP server

elkctl mcp serve serves read-only tools over stdio for one profile and space chosen at startup:

elkctl --profile analyst --space default mcp serve

The default catalog has twenty-four tools. Four task tools answer questions that span several objects: alert_context triages one alert, rule_health checks whether a rule runs and alerts, detection_coverage counts rules by MITRE ATT&CK technique, tactic, index pattern, or integration, and rule_readiness checks whether a rule has data and integrations. Twenty inspection tools read stack diagnostics, rules, exception lists, alerts, cases, data views, dashboards, and Fleet policies; rules_list also filters by ATT&CK technique or tactic. --allow-query-tools adds synchronous ES|QL and Query DSL tools. By default no tool changes the stack, and no tool selects local files or changes the target. See MCP for the client stanza, limits, and tested clients.

--allow-mutations <CLASSES> adds tools that change Elastic. A planner tool reads the stack and stores a plan; plan_apply takes only the plan id and asks the person at the client to confirm it in a form. No tool argument confirms a change, and a client without form elicitation cannot apply: the plan names the CLI command to run instead. The profile needs es_url, and an organization-level Cloud key is refused. The four classes:

  • rules-toggle enables or disables named rules. A rule without an API key that is enabled this way then runs with the server's credential; a rule that has a key keeps it.
  • alerts-triage sets the status or tags of alerts named by id. It cannot close alerts by query or assign them.
  • cases creates a case, comments on one, or closes and reopens cases whose alert sync (syncAlerts) is off. It cannot set assignees.
  • rules-create creates one rule, always disabled; it cannot create an enabled rule. The rule has no API key until it is first enabled, when it takes the key of the enabling credential.

No change is exactly reversible. A second call does not restore an alert's workflow user and time or the tags it had before, and nothing in elasticctl removes a posted comment; see MCP Mutation Kinds. For a client that uses an mcpServers object, this placeholder stanza starts such a server:

{
  "mcpServers": {
    "elasticctl": {
      "command": "elkctl",
      "args": ["--profile", "analyst", "--space", "default", "mcp", "serve",
               "--allow-mutations", "rules-toggle"]
    }
  }
}

The server can check that an answer came through the form, not that a person gave it: a client hook can accept for the person, and a model with a shell can run elkctl ... --yes without MCP. Rule names and case titles in the form are data from the stack and cannot change its fixed lines. A model can plan and ask again after a decline; each plan asks at most three times, and at most eight plans are open. A change made between the last check and the write is not seen. Claude Code shows only the form's first three lines, so read the plan with plan_get before you accept; Codex CLI's form has no decline button, so leave the value false instead. See MCP Mutations for the flow, the audit trail, and the limits of this consent model.

The server also offers five resources, four resource templates, and four prompts. Their lists are fixed: listing them sends no Elastic request and needs no credential. Reading a resource such as elasticctl://stack/info runs one read-only tool with fixed arguments and returns that tool's JSON, under the same call limit and --timeout. A prompt such as triage_alert reads nothing; it returns fixed text that asks the model to call one task tool. In Claude Code, with the server registered as elasticctl, type @ to pick a resource or write @elasticctl:elasticctl://stack/info, and type / to run a prompt such as /mcp__elasticctl__triage_alert <alert_id>. See Claude Code's resources and prompts pages, and MCP for the full lists.

Scripts and AI agents

  • Stable output: a table by default, in a terminal and in a script alike. --json or --format json|yaml|csv|jsonl for machine output, and --fields to keep only named fields.
  • Typed errors: a failure prints one JSON object on stderr with a stable kind, such as permission or not_found.
  • Exit codes: 0 success, 1 error, 2 usage error.
  • Dry run by default: every remote change previews and names the profile, host, and space; --yes applies it.
  • Named profiles: keep development, UAT, and production stacks apart.
  • Discovery: elkctl commands prints the command tree as JSON.
elkctl --profile uat rules list --source custom --json

See the CLI reference for output, errors, and selectors, and Security for credential handling and the dry-run guard.

Documentation

Contributing

See CONTRIBUTING.md for setup, the checks a pull request must pass, and the rules review holds changes to. Report security problems privately through SECURITY.md. Maintainers cut releases with docs/releasing.md.

Licensed under Apache 2.0.

About

Operate Elastic Security as code with a safety-first CLI for security engineers.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages