main
py 71 lines 3.35 KB
Raw
1 import json
2 import os
3
4 from fastapi import APIRouter
5 from fastapi import Depends
6 from fastapi import Header
7 from fastapi import HTTPException
8 from loguru import logger
9
10 from app.active_response.schema.active_response import InvokeActiveResponseResponse
11 from app.active_response.schema.graylog import GraylogEventNotification
12 from app.connectors.wazuh_manager.utils.universal import send_put_request
13
14 active_response_graylog_router = APIRouter()
15
16
17 # Function to validate the Graylog header
18 async def verify_graylog_header(graylog: str = Header(None)):
19 """Verify that the request has the correct Graylog header."""
20 # Get the header value from environment variable or use "ab73de7a-6f61-4dde-87cd-3af5175a7281" as default
21 expected_header = os.getenv("GRAYLOG_API_HEADER_VALUE", "ab73de7a-6f61-4dde-87cd-3af5175a7281")
22
23 if graylog != expected_header:
24 logger.error("Invalid or missing Graylog header")
25 raise HTTPException(status_code=403, detail="Invalid or missing Graylog header")
26 return graylog
27
28
29 @active_response_graylog_router.post(
30 "/invoke",
31 response_model=InvokeActiveResponseResponse,
32 description="Invoke an active response via a Graylog Alert notification.",
33 dependencies=[Depends(verify_graylog_header)],
34 )
35 async def invoke_active_response_graylog_route(
36 request: GraylogEventNotification,
37 ) -> InvokeActiveResponseResponse:
38 """
39 This route accepts an HTTP Post from Graylog. Required fields are:
40 1. Agent ID - The ID of the agent that triggered the alert
41 2. Command - The command to execute (i.e. 'dns_block.py')
42 3. Arguments - The arguments to pass to the command such as IP addresses, domains, etc.
43 4. Required Graylog Event Fields:
44 COMMAND: str - this is the active response command to execute i.e 'domain_sinkhole' (do not include the '.py')
45 AGENT_ID: str - the agent ID that triggered the alert
46 ACTION: str - the action to take i.e 'sinkhole' - this is defined in the python script of the valid actions
47 VALUE: str - the value to use i.e 'example.com' - this is the value that the action will be taken on
48
49 #### IMPORTANT: IF THE MANAGERS ARE IN A CLUSTER, THE WORKER FOR THE AGENT MUST GET THE COMMAND AND ACTIVE RESPONSE BLOCKS
50
51 Args:
52 request (InvokeActiveResponseRequest): The request object containing the command, custom, arguments, and alert.
53
54 Returns:
55 InvokeActiveResponseResponse: The response object indicating the success or failure of the active response invocation.
56 """
57 logger.info("Invoking Wazuh Active Response...")
58 # Append '0' to the command - This is required for Wazuh Active Response
59 command = f"{request.event.fields.COMMAND}0"
60 # Create a dictionary with the request data
61 # {"endpoint":"active-response","arguments":[],"command":"windows_firewall","custom":true,"alert":{"action":"block","ip":"1.1.1.1"},"params":{"wait_for_complete":true,"agents_list":["086"]}}
62
63 data_dict = {"command": command, "arguments": [], "alert": {"action": request.event.fields.ACTION, "value": request.event.fields.VALUE}}
64 await send_put_request(
65 endpoint="/active-response",
66 data=json.dumps(data_dict),
67 params={"wait_for_complete": True, "agents_list": [request.event.fields.AGENT_ID]},
68 debug=True,
69 )
70
71 return InvokeActiveResponseResponse(success=True, message="Wazuh Active Response invoked successfully")