{
  "schema": "aaes/capability-pack/1",
  "provider": "elastic",
  "version": "1.0.0",
  "description": "Elasticsearch (Elastic Cloud or self-managed): list indices, run read-only searches, index documents, create and delete indices, and delete documents by query.",
  "notes": "The endpoint host 'elastic-cluster.invalid' is a reserved non-production placeholder (an RFC 2606 reserved TLD): substitute the customer's own Elasticsearch endpoint — the Elastic Cloud deployment's Elasticsearch URL, an Elastic Cloud Serverless project endpoint, or a self-managed cluster host — before enabling, in every endpoint, in the resource locator and in every egress allowlist entry. The allowlist matches exactly, so endpoints and allowlist must be substituted together, and substitution is a required deployment step — the reserved host being allowlisted does not make an unsubstituted pack safe to enable. INDEX and DOC_ID in the endpoint paths are placeholders the deployment binds to concrete index names and document ids before enabling.\n\nThe search capability is a POST because Elasticsearch's search API takes the query in the request body; the registered effect is a read-only search, but the body is an unrestricted Elasticsearch Query DSL document (query, from, size, sort, aggregations, _source filtering and more, according to the reviewed search API reference), so this registration does not restrict which indices' fields a query may read beyond the INDEX path placeholder, and a deployment that needs field- or document-level restriction must enforce it in the API key's role descriptors, not in this pack.\n\nApproval classification: delete_by_query is registered as delete at the minimum R3 tier, not as a query, because its effect is document deletion — a match_all body deletes every document in the target index — and delete is one of the designated actions requiring human approval. Index deletion is registered as delete at the minimum R3 tier; according to the reviewed delete-index API reference, the index path parameter does not support wildcards or _all unless the cluster sets action.destructive_requires_name to false, and this pack registers concrete-index deletion only.\n\nDocument indexing (PUT /INDEX/_doc/DOC_ID) is registered as create and update at the minimum R2 tier: indexing with an existing id overwrites the previous document, and according to the reviewed privileges reference the index API allows overwriting, so this is not a create-only registration.\n\nExcluded operations: the security APIs (users, roles, role mappings, API key creation/invalidation, service accounts), snapshot and restore, index lifecycle management, index settings and mapping updates, index templates, reindex (which copies data between indices, including cross-cluster), cluster settings updates and cluster reroute, ingest pipelines, machine learning APIs, watcher, _bulk (whose unrestricted body mixes index, create, update and delete operations in one request and would defeat any single-action registration), single-document get (GET /INDEX/_doc/DOC_ID), single-document delete (DELETE /INDEX/_doc/DOC_ID), and every other Elasticsearch API.",
  "credential": {
    "secret_ref_id": "secret-ref-elastic-api-key",
    "custody": "customer_vault",
    "inject": "header",
    "inject_name": "Authorization",
    "note": "An Elasticsearch API key for the customer's own deployment, held in the client's own secret manager. The stored material must be the complete Authorization header value: the scheme 'ApiKey', one separating space, then the Base64-encoded 'id:api_key' pair as returned at creation — 'ApiKey <base64>'.\n\nIssuance is external: a user with the manage_api_key or manage_own_api_key cluster privilege (or an Elastic Cloud org admin through the Cloud console) creates the key via the create API key API or Kibana, and the Base64 value is shown once at creation, so capture it into the vault at that moment.\n\nCredential type: this reference takes an ELASTICSEARCH API key created against the customer's deployment (or Elastic Cloud Serverless project); an Elastic Cloud ORGANIZATION-management API key, which manages Cloud resources through the Cloud API rather than cluster data, is a different credential and cannot serve these endpoints. Least privilege, per operation: the _cat/indices collection read additionally requires the index-level monitor privilege on the bound indices — according to the reviewed security-privileges reference, index-level monitor covers monitoring actions on those indices; the search read needs the read index privilege on the bound indices; document indexing needs the index privilege (create_doc is insufficient because the registered PUT can overwrite an existing document id, and write would also grant document deletion, which this pack does not register); index creation needs create_index; index deletion needs delete_index; and delete_by_query needs read on the target indexes in addition to the delete index privilege — grant only the privileges the enabled capabilities need, scoped to the concrete index names the deployment binds, plus view_index_metadata where metadata columns are required.\n\nExpiry and revocation: an API key can be created with an expiration, after which it fails closed, but a key created without one does not expire on its own; revocation is explicit invalidation through the invalidate API key API or Kibana, and disabling issuance — for example removing the privilege that lets a role create keys, or turning off the API key service — does not invalidate keys already issued: each issued key must be invalidated individually.\n\nRotation and renewal therefore sit with an external deployment process: the executor injects the stored value verbatim and performs no key lifecycle of its own. Elasticsearch also accepts Basic auth with a native username and password; this pack registers the ApiKey header because API keys are scoped and individually revocable in a way a shared native password is not.\n\nExecutor hygiene: the value must live only in executor memory for the lifetime of a call, must never be written to logs, traces or diagnostics, and must not appear in crash dumps; a deployment that cannot meet that bar must not enable the pack."
  },
  "capabilities": [
    {
      "capability_id": "elastic.indices.read",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "elastic-cluster.invalid"
      ],
      "endpoint": "https://elastic-cluster.invalid/_cat/indices",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-elastic-api-key",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "elastic-cluster",
      "description": "List the cluster's indices: names, health, status, document counts and store sizes, which reveal internal data topology. Per the retrieved CAT indices reference the response enumerates indices — including the backing indices of data streams — and is not a data-stream collection listing; data-stream metadata reads are not registered.\n\nThe registered path covers the collection read only — per-index metadata reads (GET /INDEX, get mapping, get settings) are not registered by this pack.\n\nThe host is a reserved placeholder: substitute the customer's Elasticsearch endpoint before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "elastic.search.query",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "pii",
      "egress_allowlist": [
        "elastic-cluster.invalid"
      ],
      "endpoint": "https://elastic-cluster.invalid/INDEX/_search",
      "method": "POST",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-elastic-api-key",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "elastic-cluster",
      "description": "Run a read-only search against one index. The method is POST because the search API takes the query in the request body; the registered effect is a read — the search API performs no document or index mutation — and the read floor is R0.\n\nThe body is an unrestricted Elasticsearch Query DSL document (query, from, size, sort, aggregations, _source filtering and more according to the reviewed search API reference), so this registration does not narrow what the query reads beyond the INDEX path placeholder; document contents are arbitrary business data and may contain personal data, so the capability is classified as pii (personal data). INDEX is a placeholder the deployment binds before enabling; a match_all query returns whole documents, and expensive queries can load the cluster — the floor is a lower bound and policy may raise the tier.\n\nThe host is a reserved placeholder: substitute before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "elastic.documents.index",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R2",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "pii",
      "egress_allowlist": [
        "elastic-cluster.invalid"
      ],
      "endpoint": "https://elastic-cluster.invalid/INDEX/_doc/DOC_ID",
      "method": "PUT",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-elastic-api-key",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "create",
        "update"
      ],
      "resource_id": "elastic-cluster",
      "description": "Index one document into one index. Registered as create and update at the minimum R2 tier because indexing with an existing document id overwrites the previous document — according to the reviewed privileges reference the index API allows overwriting, so this is not a create-only registration and the previous document content is not recoverable from Elasticsearch afterward (the write floor is a lower bound, not a reversibility claim).\n\nThe body is the caller-supplied document, which may contain personal data, hence the pii class. The _bulk API is deliberately not registered: its body mixes index, create, update and delete operations in one request and would defeat a single-action registration. INDEX and DOC_ID are placeholders the deployment binds before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "elastic.index.create",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R2",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "elastic-cluster.invalid"
      ],
      "endpoint": "https://elastic-cluster.invalid/INDEX",
      "method": "PUT",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-elastic-api-key",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "create"
      ],
      "resource_id": "elastic-cluster",
      "description": "Create one index with the caller-supplied settings, mappings and aliases in the request body; a created index can be deleted, so the capability registers as create at the minimum R2 tier. Per the retrieved privileges reference, a create-index request that adds aliases additionally requires the manage privilege on both the index and the alias names — this registration does not restrict the body, so what the API key's role descriptors permit decides whether a given request is authorized; the registration records the endpoint, not the cluster's authorization decision. INDEX is a placeholder the deployment binds before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "elastic.index.delete",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "pii",
      "egress_allowlist": [
        "elastic-cluster.invalid"
      ],
      "endpoint": "https://elastic-cluster.invalid/INDEX",
      "method": "DELETE",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-elastic-api-key",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "delete"
      ],
      "resource_id": "elastic-cluster",
      "description": "Delete one index and all of its documents — the same arbitrary documents this pack classifies as pii on the document capabilities, hence the pii class here as well. Delete is one of the designated actions requiring human approval; absent a snapshot, the data is not recoverable, and this pack registers no snapshot capability. Per the retrieved delete-index API reference, wildcards and _all are refused unless the cluster sets action.destructive_requires_name to false — this pack registers concrete-index deletion only, and INDEX is a placeholder the deployment binds to a concrete index name before enabling.\n\nOn supported AAES-mediated execution paths, the declared irreversible actions require an authorized person’s approval. Observation-only and bypass calls cannot be stopped by this control.",
      "requires_review": true
    },
    {
      "capability_id": "elastic.documents.delete_by_query",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "pii",
      "egress_allowlist": [
        "elastic-cluster.invalid"
      ],
      "endpoint": "https://elastic-cluster.invalid/INDEX/_delete_by_query",
      "method": "POST",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-elastic-api-key",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "delete"
      ],
      "resource_id": "elastic-cluster",
      "description": "Delete every document in one index matching the caller-supplied query body. Judged by effect: this is bulk deletion, not a query — a match_all body deletes every document in the target index — so it registers as delete at the minimum R3 tier, and delete is one of the designated actions requiring human approval; absent a snapshot the deleted documents are not recoverable.\n\nThe body is an unrestricted Query DSL query, so this registration does not narrow which documents match; that is why it cannot sit below the delete floor. INDEX is a placeholder the deployment binds before enabling.\n\nOn supported AAES-mediated execution paths, the declared irreversible actions require an authorized person’s approval. Observation-only and bypass calls cannot be stopped by this control.",
      "requires_review": true
    }
  ],
  "resources": [
    {
      "resource_id": "elastic-cluster",
      "kind": "api",
      "locator": "https://elastic-cluster.invalid",
      "data_class": "pii",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN"
    }
  ],
  "review": {
    "state": "library",
    "date": "2026-09-22",
    "sources": [
      "https://www.elastic.co/docs/api/doc/elasticsearch (retrieved 2026-09-21)",
      "https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search (retrieved 2026-09-21)",
      "https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-delete (retrieved 2026-09-21)",
      "https://www.elastic.co/docs/reference/elasticsearch/security-privileges (retrieved 2026-09-21)",
      "https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-index (retrieved 2026-09-21)",
      "https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-create (retrieved 2026-09-21)",
      "https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-indices (retrieved 2026-09-21)",
      "https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-delete-by-query (retrieved 2026-09-21)",
      "https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-security-create-api-key (retrieved 2026-09-21)"
    ],
    "reviewer_id": "aaes-eng"
  }
}
