Document kuery (KQL) filtering and improve Fleet API page structure#7067
Document kuery (KQL) filtering and improve Fleet API page structure#7067charlotte-hoblik wants to merge 5 commits into
Conversation
Elastic Docs AI PR menuCheck the box to run an AI review for this pull request.
Powered by GitHub Agentic Workflows and docs-actions. For more information, reach out to the docs team. |
🔍 Preview links for changed docs |
✅ Elastic Docs Style Checker (Vale)No issues found on modified lines! The Vale linter checks documentation changes against the Elastic Docs style guide. To use Vale locally or report issues, refer to Elastic style guide for Vale. |
| The {{fleet}} list endpoints for agents, agent policies, package policies, and enrollment tokens accept a `kuery` query parameter that takes a [{{kib}} Query Language (KQL)](elasticsearch://reference/query-languages/kql.md) string to filter results. To check whether another endpoint accepts `kuery`, refer to its parameters in the [Kibana API docs]({{kib-apis}}). | ||
|
|
||
| Reference each field by the saved object type that stores it. {{fleet}} stores package policies as `ingest-package-policies` objects, so to filter package policies by integration name, query the `ingest-package-policies.package.name` field. |
There was a problem hiding this comment.
I'm pretty sure this isn't true. Agents and enrollment tokens are not saved objects. They are stored in .fleet-* system indices so they must be referenced directly with no saved object prefix.
Your example for package policies works in [redacted] test cluster (I'll share w/you on Slack).
GET kbn:/api/fleet/package_policies?kuery=ingest-package-policies.package.name:activemq
✅
{
"items": [
{
"id": "9xxxxa3-b6b2-4xxx-8f20-bb9822xxxxxe",
"version": "WxxxxxxxxxQ==",
"name": "activemq-1",
...
However, appending the saved object type to an agent call does not work:
GET kbn:/api/fleet/agents?kuery=ingest-agents.status:online
{
"statusCode": 400,
"error": "Bad Request",
"message": "[request query.kuery]: KQLSyntaxError: This key 'ingest-agents.status' does NOT exist in fleet-agents saved object index patterns"
}
Excluding the saved object type from an agent call does work:
GET kbn:/api/fleet/agents?kuery=status:online
✅
{
"items": [
{
"id": "3xxxx1-4a0a-4b00-bxxxx20xxxxx9d4",
"type": "PERMANENT",
"active": true,
...
There was a problem hiding this comment.
Ok, so actually only these two Fleet endpoints are backed by saved objects:
- Agent policies (
GET /api/fleet/agent_policies): stored as afleet-agent-policiessaved object, or, on deployments where space awareness is off, as the legacyingest-agent-policiessaved object (#1 and #2).- Use
fleet-agent-policies.<field>in the KQL prefix; the legacyingest-agent-policies.<field>also works because Fleet normalizes either prefix at runtime (#3)
- Use
- Package policies (
GET /api/fleet/package_policies): stored as afleet-package-policiessaved object, or, on deployments where space awareness is off, as the legacyingest-package-policiessaved object (#1, and #2).- Use
fleet-package-policies.<field>, but the legacyingest-package-policies.<field>also works for the same reason as above (#3).
- Use
Agents (GET /api/fleet/agents) are stored in the .fleet-agents ES system index (#1). So these should be referenced without a prefix (e.g., status:online). However, here fleet-agents.status:online also works because Fleet strips it from the kuery (#2), but ingest-agents. does not exist, and that returns an error.
Enrollment API keys (GET /api/fleet/enrollment_api_keys) are stored in the .fleet-enrollment-api-keys ES system index (#1), but here no prefix should be used as the kuery is passed straight through to the index search (e.g., policy_id:"<policy-id>").
There was a problem hiding this comment.
Thanks so much, both of you, this was really helpful. I tested it all on a 9.4.2 cluster and your breakdown held up, with one surprise.
fleet-agent-policies. doesn't actually work on 9.4.2. It 400s, and only ingest-agent-policies. or a bare name:"..." work, even though the data is stored under the fleet-* types (confirmed with a type agg on .kibana*).
In the doc I went with bare fields where possible, prefixed only nested fields like package.name, and added a tip that the KQLSyntaxError names the exact pattern to use.
@vishaangelova does fleet-agent-policies. work for you on main? Thanks again.
There was a problem hiding this comment.
I can confirm that fleet-agent-policies.name 400s and the following actually work:
GET kbn:/api/fleet/agent_policies?kuery=ingest-agent-policies.name:"Elastic Cloud agent policy"
GET kbn:/api/fleet/agent_policies?kuery=name:"Elastic Cloud agent policy"
Tested on 9.4.3 (unreleased)
There was a problem hiding this comment.
Hi @paul-tavares, pulling you in this thread to confirm if the way this works is by design:
On GET /api/fleet/agent_policies, the kuery validator rejects the fleet-agent-policies.<field> prefix (returns a 400 KQLSyntaxError), so only ingest-agent-policies.<field> or bare fields work. On GET /api/fleet/package_policies the validator was widened to accept both prefixes as part of elastic/kibana#227862, but the equivalent change doesn't seem to have been made for agent policies. Wondering if this was intentional, so we can document the right prefix?
There was a problem hiding this comment.
Sorry, after checking with Paul, it seems maybe @criamico could help instead?
There was a problem hiding this comment.
On GET /api/fleet/agent_policies, the kuery validator rejects the fleet-agent-policies. prefix (returns a 400 KQLSyntaxError), so only ingest-agent-policies. or bare fields work.
I just checked the code and verified that the KQL validator rejects any kuery prefixed with fleet-agent-policies. This was probably missed when doing the work for space awareness. It is actually a bug, so I'll open a ticket to track it.
| ``` | ||
|
|
||
| ::::{tip} | ||
| The accepted saved object type prefix can differ across deployments and endpoints. If a query returns a `KQLSyntaxError` stating that a key does not exist in a saved object index pattern, use the index pattern named in the error as your prefix. For example, if the error names `ingest-agent-policies`, query `ingest-agent-policies.name`. |
There was a problem hiding this comment.
I like this tip but the current wording only handles the KQLSyntaxError that names the index pattern (for example, ingest-agents.status on the agents endpoint). Forgetting the prefix on a nested field produces a different error that does not have this pattern:
GET kbn:/api/fleet/package_policies?kuery=package.name:nginx
{
"statusCode": 400,
"error": "Bad Request",
"message": "This type package is not allowed: Bad Request"
}
Here the parser reads package as a saved object type and rejects it, so there's no index pattern in the error to copy. Could we broaden the tip to cover both errors? Something like:
| The accepted saved object type prefix can differ across deployments and endpoints. If a query returns a `KQLSyntaxError` stating that a key does not exist in a saved object index pattern, use the index pattern named in the error as your prefix. For example, if the error names `ingest-agent-policies`, query `ingest-agent-policies.name`. | |
| If a query returns an error like `This type <x> is not allowed` or a `KQLSyntaxError` about a missing key, the field needs the saved object type as a prefix. If the error names an index pattern, use that; otherwise prefix with the endpoint's saved object type (for example, `ingest-package-policies` for package policies). |
Summary
Adds KQL filtering guidance to the Fleet API page and brings the page in line with the how-to content type. Closes #3401.
Connected issue: #3401
kuery / KQL filtering (the issue)
kuery, the saved-object field-prefix rule, a verifiedpackage_policiesexample, and links to the KQL reference. The API reference nameskuerybut never explains it or links out, this is the missing on-ramp.Structure and navigation (applied the Elastic docs skills)
descriptionto the frontmatter (no longer duplicated by the intro).Copy edits throughout
curlexample.Tool(s) and model(s) used:
Claude Opus 4.8
Elastic docs review skills