Architecture
Command manager context diagram
graph TD subgraph Command_Manager["Command Manager"] API["Commands API"] Controller["Commands Controller"] Processor["Commands Expansion"] Storage["Commands Index Storage"] CommandsIndex[(commands index)] AgentsIndex[(agents index)] Scheduler["Job Scheduler Task"] end Actor("Actor") -- POST /commands --> API API --> Controller Controller --> Processor Processor --> Storage Storage -- write --> CommandsIndex Processor -- read --> AgentsIndex Scheduler -- read-write--> CommandsIndex subgraph Server["Server"] direction TB ManagementAPI["Management API"] end ManagementAPI -- read --> CommandsIndex
Commands API
Issue: https://github.com/wazuh/wazuh-indexer-plugins/issues/69
The Command Manager API is described formally in OpenAPI format. Check it out here.
Important: The
action.name
attribute must always be provided beforeaction.args
in the JSON. Otherwise, the command is rejected. This is necessary for proper validation of the arguments, which depends on the command type, defined byaction.name
.
fetch-config
The fetch-config
command is used to order an agent to update its remote configuration.
Accepted values for target.type
are agent
and group
. The target.id
represents the agent's ID or group's name, respectively.
The command takes no arguments (action.args
). Any provided argument is ignored.
{
"commands": [
{
"action": {
"name": "fetch-config",
"args": {},
"version": "5.0.0"
},
"source": "Users/Services",
"user": "Management API",
"timeout": 100,
"target": {
"id": "d5b250c4-dfa1-4d94-827f-9f99210dbe6c",
"type": "agent"
}
}
]
}
set-group
The set-group
command is used to change the groups of an agent.
Accepted values for target.type
are agent
and group
. The target.id
represents the agent's ID or group's name, respectively.
The command takes the groups
argument, an array of strings depicting the full list of groups the agent belongs too. Any other value than an array of strings is rejected. Additional arguments are ignored.
{
"commands": [
{
"action": {
"name": "set-group",
"args": {
"groups": [
"group_1",
"group_2"
]
},
"version": "5.0.0"
},
"source": "Users/Services",
"user": "Management API",
"timeout": 100,
"target": {
"id": "d5b250c4-dfa1-4d94-827f-9f99210dbe6c",
"type": "agent"
}
}
]
}
update
The update
command is used to notify about new content being available. We usually refer to content to the CVE and Ruleset catalog.
Only accepted value for target.type
is server
. The target.id
represents the server's module that is interested on the new content.
The command takes the index
and offset
arguments, strings depicting the index where the new content is and its version, respectively. Any other value than a string is rejected. Additional arguments are ignored.
{
"commands": [
{
"action": {
"name": "update",
"args": {
"index": "content-index",
"offset": "1111"
},
"version": "5.0.0"
},
"source": "Content Manager",
"timeout": 100,
"target": {
"id": "vulnerability-detector",
"type": "server"
}
}
]
}
refresh
The refresh
command is created when the Wazuh RBAC resources (users, roles, policies, ...) are modified.
This command serves to the Wazuh Server as a notification to update its local copy of these resources.
The expected values for target.type
and target.id
are server
and rbac
, respectively.
The command accepts an optional index
argument, which must be an array of strings representing the RBAC indices that changed. Any other value than an array is strings is rejected. Additional arguments are ignored.
{
"commands": [
{
"action": {
"name": "refresh",
"args": {
"index": ["index-a", "index-b"], // Optional
},
"version": "5.0.0"
},
"source": "Users/Services",
"timeout": 100,
"target": {
"id": "rbac",
"type": "server"
}
}
]
}
Commands expansion
Commands can be targeted to a group of agents, too. This is achieved by setting group
as the target type and the name of the group as the target ID. For example:
{
"commands": [
{
"action": {
"name": "fetch-config",
"args": {},
"version": "5.0.0"
},
"source": "Users/Services",
"user": "Management API",
"timeout": 100,
"target": {
"id": "group002",
"type": "group"
}
}
]
}
The command is processed by the Command Manager and expanded. We refer to expansion as the generation of analogous commands targeting the individual agents that belong to that group. For example, if the windows-group-A
group contains 10 agents, 10 commands will be generated, one for each of the agents. The target type and ID for these commands are set to agent
and the ID of the agent, respectively.
[
{
"command": {
"source": "Users/Services",
"user": "Management API",
"target": {
"type": "agent",
"id": "agent82"
},
"action": {
"name": "fetch-config",
"args": {},
"version": "5.0.0"
},
"timeout": 100,
"status": "pending"
}
},
{
"command": {
"source": "Users/Services",
"user": "Management API",
"target": {
"type": "agent",
"id": "agent21"
},
"action": {
"name": "fetch-config",
"args": {},
"version": "5.0.0"
},
"timeout": 100,
"status": "pending"
}
},
{
"command": {
"source": "Users/Services",
"user": "Management API",
"target": {
"type": "agent",
"id": "agent28"
},
"action": {
"name": "fetch-config",
"args": {},
"version": "5.0.0"
},
"timeout": 100,
"status": "pending"
}
}
]
Issue: https://github.com/wazuh/wazuh-indexer-plugins/issues/88
Orders storage
The processed commands, the orders, are stored in the wazuh-commands
index.
GET wazuh-commands/_search
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "wazuh-commands",
"_id": "yu5Li5UB5IfLPVSubqhW",
"_score": 1,
"_source": {
"agent": {
"groups": [
"group002"
]
},
"command": {
"source": "Users/Services",
"user": "Management API",
"target": {
"type": "agent",
"id": "agent28"
},
"action": {
"name": "set-group",
"args": {
"groups": [
"group_1",
"group_2"
]
},
"version": "5.0.0"
},
"timeout": 100,
"status": "pending",
"order_id": "ye5Li5UB5IfLPVSubqhW",
"request_id": "yO5Li5UB5IfLPVSubqhW"
},
"@timestamp": "2025-03-12T16:58:51Z",
"delivery_timestamp": "2025-03-12T17:00:31Z"
}
}
]
}
}
Issue: https://github.com/wazuh/wazuh-indexer-plugins/issues/42
The Job Scheduler task
A periodic task performs an updateByQuery query to set the status of past due orders to "failed".
Issue: https://github.com/wazuh/wazuh-indexer-plugins/issues/87