From eccf7664197e4897b64fec127e8af9b656f340f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Ruiz?= Date: Fri, 11 Oct 2024 12:48:00 +0200 Subject: [PATCH] Update commands index data model (#453) * Update commands index data model * Update commands event generator * Move agent fields as extended --- .../event-generator/event_generator.py | 62 ++++++++++--------- ecs/command/fields/custom/agent.yml | 12 ++++ ecs/command/fields/custom/command.yml | 18 +++--- ecs/command/fields/subset.yml | 3 + .../fields/template-settings-legacy.json | 8 +-- ecs/command/fields/template-settings.json | 4 +- 6 files changed, 64 insertions(+), 43 deletions(-) create mode 100644 ecs/command/fields/custom/agent.yml diff --git a/ecs/command/event-generator/event_generator.py b/ecs/command/event-generator/event_generator.py index 60c960064a9e1..f8bafa11f0921 100644 --- a/ecs/command/event-generator/event_generator.py +++ b/ecs/command/event-generator/event_generator.py @@ -1,15 +1,12 @@ #!/bin/python3 -# This script generates sample events and injects them into an OpenSearch index. -# The events follow the provided template structure with command-related data fields. -# Additional fields are generated when the --index option is passed. - import random import json import requests import warnings import logging import argparse +import uuid LOG_FILE = 'generate_data.log' GENERATED_DATA_FILE = 'generatedData.json' @@ -22,32 +19,37 @@ def generate_random_command(include_all_fields=False): - command = { - "source": random.choice(["Users/Services", "Engine", "Content manager"]), - "user": f"user{random.randint(1, 100)}", - "target": f"WazuhServerCluster{random.randint(1, 10)}", - "type": random.choice(["agent_group", "agent", "wazuh_server"]), - "action": { - "type": random.choice(["Agent groups", "Agent", "Server cluster"]), - "args": [f"/path/to/executable/arg{random.randint(1, 10)}"], - "version": f"v{random.randint(1, 10)}" - }, - "timeout": random.randint(10, 100) + document = { + "command": { + "source": random.choice(["Users/Services", "Engine", "Content manager"]), + "user": f"user{random.randint(1, 100)}", + "target": { + "id": f"target{random.randint(1, 10)}", + "type": random.choice(["agent", "group", "server"]) + }, + "action": { + "name": random.choice(["restart", "update", "change_group", "apply_policy"]), + "args": [f"/path/to/executable/arg{random.randint(1, 10)}"], + "version": f"v{random.randint(1, 5)}" + }, + "timeout": random.randint(10, 100) + } } if include_all_fields: - command["status"] = random.choice( - ["pending", "sent", "success", "failure"] - ) - command["result"] = { + document["agent"]["groups"] = [f"group{random.randint(1, 5)}"], + document["command"]["status"] = random.choice( + ["pending", "sent", "success", "failure"]) + document["command"]["result"] = { "code": random.randint(0, 255), "message": f"Result message {random.randint(1, 1000)}", "data": f"Result data {random.randint(1, 100)}" } - command["request_id"] = random.randint(1000, 9999) - command["order_id"] = random.randint(1000, 9999) + # Generate UUIDs for request_id and order_id + document["command"]["request_id"] = str(uuid.uuid4()) + document["command"]["order_id"] = str(uuid.uuid4()) - return command + return document def generate_random_data(number, include_all_fields=False): @@ -58,8 +60,6 @@ def generate_random_data(number, include_all_fields=False): def inject_events(ip, port, index, username, password, data, use_index=False): - url = f'https://{ip}:{port}/_plugins/_commandmanager' - session = requests.Session() session.auth = (username, password) session.verify = False @@ -68,8 +68,12 @@ def inject_events(ip, port, index, username, password, data, use_index=False): try: for event_data in data: if use_index: - id = event_data["request_id"] + event_data["order_id"] - url = f'https://{ip}:{port}/{index}/_doc/{id}' + # Generate UUIDs for the document id + doc_id = str(uuid.uuid4()) + url = f'https://{ip}:{port}/{index}/_doc/{doc_id}' + else: + # Default URL for command manager API without the index + url = f'https://{ip}:{port}/_plugins/_commandmanager' response = session.post(url, json=event_data, headers=headers) if response.status_code != 201: @@ -83,7 +87,8 @@ def inject_events(ip, port, index, username, password, data, use_index=False): def main(): parser = argparse.ArgumentParser( - description="Generate and optionally inject events into an OpenSearch index or Command Manager.") + description="Generate and optionally inject events into an OpenSearch index or Command Manager." + ) parser.add_argument( "--index", action="store_true", @@ -108,7 +113,8 @@ def main(): logging.info('Data generation completed.') inject = input( - "Do you want to inject the generated data into your indexer/command manager? (y/n) ").strip().lower() + "Do you want to inject the generated data into your indexer/command manager? (y/n) " + ).strip().lower() if inject == 'y': ip = input("Enter the IP of your Indexer: ") port = input("Enter the port of your Indexer: ") diff --git a/ecs/command/fields/custom/agent.yml b/ecs/command/fields/custom/agent.yml new file mode 100644 index 0000000000000..17b6f7324d830 --- /dev/null +++ b/ecs/command/fields/custom/agent.yml @@ -0,0 +1,12 @@ +--- +- name: agent + title: Wazuh Agents + short: Wazuh Inc. custom fields. + type: group + group: 2 + fields: + - name: groups + type: keyword + level: custom + description: > + The groups the agent belongs to. \ No newline at end of file diff --git a/ecs/command/fields/custom/command.yml b/ecs/command/fields/custom/command.yml index fdf4054ccb492..749f49fe23835 100644 --- a/ecs/command/fields/custom/command.yml +++ b/ecs/command/fields/custom/command.yml @@ -17,21 +17,21 @@ level: custom description: > The user that originated the request. - - name: target + - name: target.id type: keyword level: custom description: > - Wazuh Server Cluster name to send the command to. - - name: type + Unique identifier of the destination to send the command to. + - name: target.type type: keyword level: custom description: > - The requested action type. One of 'agent_group', 'agent', 'wazuh_server'. - - name: action.type + The destination type. One of [`group`, `agent`, `server`] + - name: action.name type: keyword level: custom description: > - The actual requested action. One of Agent groups, Agent, Server cluster. + The requested action type. Examples: `restart`, `update`, `change_group`, `apply_policy`, ... - name: action.args type: keyword level: custom @@ -51,7 +51,7 @@ type: keyword level: custom description: > - Status within the Command Manager's context. One of 'pending', 'sent', 'success', 'failure'. + Status within the Command Manager's context. One of ['pending', 'sent', 'success', 'failure']. - name: result.code type: short level: custom @@ -71,9 +71,9 @@ type: keyword level: custom description: > - Unique identifier generated by the Command Manager. UUID. + UUID generated by the Command Manager. - name: order_id type: keyword level: custom description: > - Unique identifier generated by the Command Manager. UUID. + UUID generated by the Command Manager. diff --git a/ecs/command/fields/subset.yml b/ecs/command/fields/subset.yml index 4a9f0c63cf30a..80cf43234f2c1 100644 --- a/ecs/command/fields/subset.yml +++ b/ecs/command/fields/subset.yml @@ -4,5 +4,8 @@ fields: base: fields: tags: [] + agent: + fields: + groups: {} command: fields: "*" diff --git a/ecs/command/fields/template-settings-legacy.json b/ecs/command/fields/template-settings-legacy.json index 896d926e2d48c..75ef7b40f81f8 100644 --- a/ecs/command/fields/template-settings-legacy.json +++ b/ecs/command/fields/template-settings-legacy.json @@ -10,10 +10,10 @@ "number_of_replicas": "0", "refresh_interval": "5s", "query.default_field": [ - "command.source", - "command.target", - "command.status", - "command.type" + "command.source", + "command.target.type", + "command.status", + "command.action.name" ] } } diff --git a/ecs/command/fields/template-settings.json b/ecs/command/fields/template-settings.json index 6041ec672f4bd..70b65197303ad 100644 --- a/ecs/command/fields/template-settings.json +++ b/ecs/command/fields/template-settings.json @@ -12,9 +12,9 @@ "refresh_interval": "5s", "query.default_field": [ "command.source", - "command.target", + "command.target.type", "command.status", - "command.type" + "command.action.name" ] } }