The new docs.trellix.com features a modernized UI and AI-powered conversational search. Content is currently available in English, with additional languages launching in early November 2026. We hope you enjoy the updated experience.

Automate workflows

Prev Next

Set the following variables in the Python script:

  • <MANAGER_IP>

  • <USERNAME>

  • <PASSWORD>

  • <RULESET_FILE_PATH>

  • <RULESET_FILENAME>

  • <SENSOR_ID>

  • <SENSOR_NAME>

The script performs these operations:

  1. Import the ruleset — Imports the ruleset file to the Manager.

  2. Push the configuration — Performs a Suricata configuration push to the Sensor.

  3. Monitor progress — Waits for the configuration push to complete.

  4. Display results — Prints the results of the operations.

Script:

import requests
import json
import base64
import time
import urllib3
import logging

# --- Setup Logging ---
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# Suppress insecure request warnings for production-clean logs
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def base64_encode(message):
    """Encodes string to base64 for NSM-SDK-API header."""
    message_bytes = message.encode('ascii')
    base64_bytes = base64.b64encode(message_bytes)
    return base64_bytes.decode('ascii')

def create_session(manager_ip, username, password):
    """Authenticates and returns the session object."""
    try:
        url = f"https://{manager_ip}/sdkapi/session"
        headers = {
            'Accept': 'application/vnd.nsm.v2.0+json',
            'Content-Type': 'application/json',
            'NSM-SDK-API': base64_encode(f"{username}:{password}"),
        }
        response = requests.get(url, headers=headers, verify=False, timeout=30)
        response.raise_for_status()
        logger.info("Session created successfully.")
        return response.json()
    except Exception as e:
        logger.error(f"Failed in session creation. Error: {e}")
        return None

def import_ruleset(encoded_session, manager_ip, ruleset_filename, ruleset_file_path):
    """Uploads the ruleset file to the Manager."""
    try:
        url = f"https://{manager_ip}/sdkapi/suricata/ruleset/import"
        payload = {'rulesetName': 'Test', 'publisherName': 'QA'}
        headers = {
            'Accept': 'application/vnd.nsm.v2.0+json',
            'NSM-SDK-API': encoded_session
        }
        
        with open(ruleset_file_path, 'rb') as f:
            files = [('file', (ruleset_filename, f, 'application/octet-stream'))]
            response = requests.post(url, headers=headers, data=payload, files=files, verify=False, timeout=120)
            response.raise_for_status()
            logger.info("Ruleset file imported successfully.")
            return response.json()
    except Exception as e:
        logger.error(f"Failed to import ruleset file. Error: {e}")
        return None

def verify_suricata_config_deployment(encoded_session, manager_ip, sensor_id, request_id):
    """Polls the status until percentage is 100 and confirms success message."""
    url = f"https://{manager_ip}/sdkapi/sensor/{sensor_id}/action/update_sensor_config/{request_id}"
    headers = {
        'Accept': 'application/vnd.nsm.v2.0+json',
        'Content-Type': 'application/json',
        'NSM-SDK-API': encoded_session
    }

    logger.info(f"Starting deployment verification for Request ID: {request_id}")
    
    while True:
        try:
            response = requests.get(url, headers=headers, verify=False, timeout=30)
            response.raise_for_status()
            data = response.json()
            
            percentage = data.get("sigsetConfigPercentageComplete", 0)
            status_msg = data.get("sigsetConfigStatusMessage", "")
            
            logger.info(f"Deployment Progress: {percentage}% | Status: {status_msg}")

            if percentage == 100:
                if status_msg == "DOWNLOAD COMPLETE":
                    logger.info("Verification Successful: Deployment finished with 'DOWNLOAD COMPLETE'.")
                    return True, data
                else:
                    logger.error(f"Verification Failed: Reached 100% but message was '{status_msg}'.")
                    return False, data
            
            time.sleep(10) # Wait before next poll
                
        except Exception as e:
            logger.error(f"Error during status verification: {e}")
            return False, None

def deploy_suricata_config(encoded_session, manager_ip, sensor_id, sensor_name):
    """Triggers the configuration update on the sensor."""
    try:
        url = f"https://{manager_ip}/sdkapi/sensor/{sensor_id}/action/update_sensor_config"
        payload = json.dumps({
            "deviceName": sensor_name,
            "pendingChanges": {
                "isConfigurationChanged": True,
                "isSignatureSetConfigurationChanged": True,
                "isSuricataConfigurationChanged": True
            },
            "isSigsetConfigPushRequired": True,
            "isSuricataUpdateRequired": True
        })
        headers = {
            'Accept': 'application/vnd.nsm.v2.0+json',
            'Content-Type': 'application/json',
            'NSM-SDK-API': encoded_session
        }

        response = requests.put(url, headers=headers, data=payload, verify=False, timeout=30)
        response.raise_for_status()
        
        request_id = response.json().get("RequestId")
        if not request_id:
            logger.error("Deployment triggered but no Request ID received.")
            return None

        # Verify the deployment status
        success, final_data = verify_suricata_config_deployment(encoded_session, manager_ip, sensor_id, request_id)
        
        if success:
            logger.info("FINAL RESULT: Deployment Succeeded.")
        else:
            logger.error("FINAL RESULT: Deployment Failed.")
            
        return final_data
    
    except Exception as e:
        logger.error(f"Failure in triggering suricata config deployment: {e}")
        return None

if __name__ == "__main__":
    # Constants
    MANAGER_IP = "10.213.172.35"
    USERNAME = "admin"
    PASSWORD = "admin123"
    RULESET_FILE_PATH = r"C:\Users\Administrator\Desktop\All\1. PROJECTS\TROS_Deployment\suricata_ruleset_new.rules"
    RULESET_FILENAME = "suricata_ruleset_new.rules"
    SENSOR_ID = "1068"
    SENSOR_NAME = "suricata_stack_41_42"

    # Step 1: Session
    session_res = create_session(MANAGER_IP, USERNAME, PASSWORD)
    
    if session_res:
        auth_header = base64_encode(f"{session_res['session']}:{session_res['userId']}")
        
        # Step 2: Import
        import_res = import_ruleset(auth_header, MANAGER_IP, RULESET_FILENAME, RULESET_FILE_PATH)
        
        # Step 3: Deploy & Verify
        if import_res:
            deploy_suricata_config(auth_header, MANAGER_IP, SENSOR_ID, SENSOR_NAME)
        else:
            logger.error("Skipping deployment because ruleset import failed.")
    else:
        logger.error("Exiting script: Authentication failed.")

Sample output:

python suricata_automation_prod.py
2026-03-18 09:04:00,614 - INFO - Session created successfully.
2026-03-18 09:04:02,177 - INFO - Ruleset file imported successfully.
2026-03-18 09:04:11,755 - INFO - Starting deployment verification for Request ID: 1773870863956
2026-03-18 09:04:11,786 - INFO - Deployment Progress: 0% | Status: IN PROGRESS:Queued: Generation of Signature file Segment for Sensor: suricata_stack_41_42
2026-03-18 09:04:21,833 - INFO - Deployment Progress: 1% | Status: IN PROGRESS:Generating Signature Segments for Stack: suricata_stack_41_42. Sig Version: 11.10.33.7 ,sensorSoftwareVersion: 11.1.5.167
2026-03-18 09:04:31,880 - INFO - Deployment Progress: 1% | Status: IN PROGRESS:Generating Signature Segments for Stack: suricata_stack_41_42. Sig Version: 11.10.33.7 ,sensorSoftwareVersion: 11.1.5.167
2026-03-18 09:04:41,927 - INFO - Deployment Progress: 1% | Status: IN PROGRESS:Generating Signature Segments for Stack: suricata_stack_41_42. Sig Version: 11.10.33.7 ,sensorSoftwareVersion: 11.1.5.167
2026-03-18 09:04:51,958 - INFO - Deployment Progress: 1% | Status: IN PROGRESS:Generating Signature Segments for Stack: suricata_stack_41_42. Sig Version: 11.10.33.7 ,sensorSoftwareVersion: 11.1.5.167
2026-03-18 09:05:02,005 - INFO - Deployment Progress: 1% | Status: IN PROGRESS:Generating Signature Segments for Stack: suricata_stack_41_42. Sig Version: 11.10.33.7 ,sensorSoftwareVersion: 11.1.5.167
2026-03-18 09:05:12,052 - INFO - Deployment Progress: 1% | Status: IN PROGRESS:Generating Signature Segments for Stack: suricata_stack_41_42. Sig Version: 11.10.33.7 ,sensorSoftwareVersion: 11.1.5.167
2026-03-18 09:05:22,099 - INFO - Deployment Progress: 1% | Status: IN PROGRESS:Generating Signature Segments for Stack: suricata_stack_41_42. Sig Version: 11.10.33.7 ,sensorSoftwareVersion: 11.1.5.167
2026-03-18 09:05:32,146 - INFO - Deployment Progress: 1% | Status: IN PROGRESS:Generating Signature Segments for Stack: suricata_stack_41_42. Sig Version: 11.10.33.7 ,sensorSoftwareVersion: 11.1.5.167
2026-03-18 09:05:42,193 - INFO - Deployment Progress: 1% | Status: IN PROGRESS:Generating Signature Segments for Stack: suricata_stack_41_42. Sig Version: 11.10.33.7 ,sensorSoftwareVersion: 11.1.5.167
2026-03-18 09:05:52,239 - INFO - Deployment Progress: 30% | Status: IN PROGRESS:Generating Response Segments for Stack: suricata_stack_41_42
2026-03-18 09:06:02,286 - INFO - Deployment Progress: 50% | Status: IN PROGRESS:Transferring  files in progress for...  ...node :suricata_stack_41_42-2 ...node :suricata_stack_41_42-1
2026-03-18 09:06:12,318 - INFO - Deployment Progress: 50% | Status: IN PROGRESS:Transferring  files in progress for...  ...node :suricata_stack_41_42-2 ...node :suricata_stack_41_42-1
2026-03-18 09:06:22,365 - INFO - Deployment Progress: 100% | Status: DOWNLOAD COMPLETE
2026-03-18 09:06:22,365 - INFO - Verification Successful: Deployment finished with 'DOWNLOAD COMPLETE'.
2026-03-18 09:06:22,365 - INFO - FINAL RESULT: Deployment Succeeded.