You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Splunk_Deploiement/apps/TA-socradar-incidents/bin/status_update_with_log.py

228 lines
8.5 KiB

#!/usr/bin/env python
import sys
import os
import requests
import time
import json
import subprocess
from datetime import datetime
# Debug log file
DEBUG_LOG = "/opt/splunk/var/log/socradar/status_update_log.txt"
def log_debug(msg):
os.makedirs(os.path.dirname(DEBUG_LOG), exist_ok=True)
with open(DEBUG_LOG, 'a') as f:
f.write(f"[{datetime.now()}] {msg}\n")
# Simple version that outputs CSV directly
print("alarm_id,status,result,message,time")
try:
log_debug("=== NEW STATUS UPDATE REQUEST ===")
# Read all input
input_lines = []
for line in sys.stdin:
input_lines.append(line.strip())
log_debug(f"Input lines: {input_lines}")
# Parse alarm_id and new_status from input
alarm_id = ""
new_status = ""
for line in input_lines:
if "alarm_id=" in line:
parts = line.split(',')
for part in parts:
if 'alarm_id=' in part:
alarm_id = part.split('=', 1)[1].strip().strip('"')
elif 'new_status=' in part:
new_status = part.split('=', 1)[1].strip().strip('"')
log_debug(f"Parsed: alarm_id={alarm_id}, new_status={new_status}")
if not alarm_id:
print("NONE,No alarm selected,WAITING,Enter an alarm ID," + str(int(time.time())))
sys.exit(0)
# Get credentials
conf_file = "/opt/splunk/etc/apps/TA-socradar-incidents/local/inputs.conf"
company_id = None
api_key = None
if os.path.exists(conf_file):
with open(conf_file, 'r') as f:
for line in f:
line = line.strip()
if line.startswith('socradar_company_id'):
company_id = line.split('=', 1)[1].strip()
elif line.startswith('socradar_api_key'):
api_key = line.split('=', 1)[1].strip()
if not company_id or not api_key:
log_debug("Missing credentials")
print(f"{alarm_id},Error,ERROR,Missing credentials," + str(int(time.time())))
sys.exit(0)
# Status mapping
status_map = {
'0': 'Open',
'1': 'OnHold-Investigating',
'2': 'Closed-Resolved',
'3': 'OnHold-Pending',
'5': 'OnHold-Legal',
'9': 'Closed-FalsePositive',
'10': 'Closed-Duplicate',
'11': 'Closed-ProcessedInternally',
'12': 'Closed-Mitigated',
'13': 'Closed-NotApplicable'
}
status_name = status_map.get(new_status, f'Status-{new_status}')
# Make API call
url = f"https://platform.socradar.com/api/company/{company_id}/alarms/status/change?key={api_key}"
payload = {
"status": new_status,
"alarm_ids": alarm_id,
"comments": f"Updated via Splunk to: {status_name}"
}
log_debug(f"Calling API: {url[:50]}...")
log_debug(f"Payload: {payload}")
response = requests.post(url, json=payload, headers={"Content-Type": "application/json"}, timeout=30)
response_data = response.json()
log_debug(f"API Response: {response.status_code} - {response_data}")
if response.status_code == 200 and response_data.get('is_success', False):
print(f"{alarm_id},{status_name},SUCCESS,Updated successfully," + str(int(time.time())))
# Map status to SOCRadar API format
api_status_map = {
'Open': 'OPEN',
'OnHold-Investigating': 'INVESTIGATING',
'Closed-Resolved': 'RESOLVED',
'OnHold-Pending': 'PENDING_INFO',
'OnHold-Legal': 'LEGAL',
'Closed-FalsePositive': 'FALSE_POSITIVE',
'Closed-Duplicate': 'DUPLICATE',
'Closed-ProcessedInternally': 'PROCESSED_INTERNALLY',
'Closed-Mitigated': 'MITIGATED',
'Closed-NotApplicable': 'NOT_APPLICABLE'
}
api_status = api_status_map.get(status_name, status_name)
# Update checkpoint
try:
checkpoint_file = "/opt/splunk/var/lib/splunk/modinputs/socradar_incidents_collector/deneme_002_socradar_v4_processed_alarms"
if os.path.exists(checkpoint_file):
with open(checkpoint_file, 'r') as f:
checkpoint_data = json.load(f)
if 'alarm_status' in checkpoint_data:
checkpoint_data['alarm_status'][str(alarm_id)] = api_status
checkpoint_data['last_updated'] = datetime.now().isoformat()
with open(checkpoint_file, 'w') as f:
json.dump(checkpoint_data, f)
log_debug(f"Updated checkpoint: {alarm_id} -> {api_status}")
except Exception as e:
log_debug(f"Checkpoint update error: {e}")
# Index the status change immediately using REST API
try:
log_debug("Attempting to index status change...")
# Create event
event = {
"time": time.time(),
"host": "socradar",
"source": "status_update",
"sourcetype": "socradar:incidents",
"index": "socradar_incidents",
"event": json.dumps({
"alarm_id": alarm_id,
"status": api_status,
"alarm_status": api_status,
"date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"update_source": "manual_status_update",
"_time": time.time()
})
}
# Use Splunk REST API to index
import urllib.request
import urllib.parse
import base64
# Use HTTP Event Collector endpoint with index specification
url = "https://localhost:8089/services/receivers/simple?index=socradar_incidents&sourcetype=socradar:incidents"
data = event['event']
# Create request
req = urllib.request.Request(
url,
data=data.encode('utf-8'),
headers={
'Authorization': 'Basic ' + base64.b64encode(b'admin:123456789').decode('ascii'),
'Content-Type': 'application/json'
}
)
# Disable SSL verification for localhost
import ssl
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
# Send request
with urllib.request.urlopen(req, context=ctx) as response:
result = response.read().decode('utf-8')
log_debug(f"Index result: {result}")
except Exception as e:
log_debug(f"Indexing error: {e}")
# Fallback to oneshot
try:
# Get the full alarm data from collector's last run
event_data = {
"alarm_id": alarm_id,
"status": api_status,
"alarm_status": api_status,
"date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"update_source": "manual_status_update",
"_time": time.time(),
"alarm_type": "incident",
"alarm_risk_level": "UNKNOWN"
}
event_json = json.dumps(event_data)
cmd = ['/opt/splunk/bin/splunk', 'add', 'oneshot', '-',
'-sourcetype', 'socradar:incidents',
'-index', 'socradar_incidents',
'-auth', 'admin:123456789']
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate(input=event_json.encode())
log_debug(f"Oneshot result: {proc.returncode}, stdout: {stdout}, stderr: {stderr}")
except Exception as e2:
log_debug(f"Oneshot error: {e2}")
else:
msg = response_data.get('message', 'Update failed').replace(',', ';')
print(f"{alarm_id},{status_name},FAILED,{msg}," + str(int(time.time())))
log_debug(f"Update failed: {msg}")
except Exception as e:
log_debug(f"EXCEPTION: {e}")
print(f"ERROR,Error,ERROR,{str(e).replace(',', ';')}," + str(int(time.time())))