Posted on
Artificial Intelligence

Artificial Intelligence SOC Workflows

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

Artificial Intelligence SOC Workflows: Bash-First Playbooks You Can Ship Today

If you’ve ever stared at a blinking pager at 02:17, you know the feeling: too many alerts, not enough humans. The gap between “alert” and “actionable context” is where SOC time goes to die. The promise of AI for SOCs isn’t hype when you translate it into small, reliable workflows that reduce toil, speed up triage, and standardize reporting—without spraying sensitive data into the cloud. This post shows how to build AI-augmented SOC workflows in plain Bash with local models, so you can keep data in your perimeter and move faster.

What you’ll get:

  • Why AI in SOCs is worth your time (and where it’s not).

  • 3–5 actionable Bash-first workflows you can deploy today.

  • Installation instructions for common Linux package managers (apt, dnf, zypper).

  • Copy-pasteable scripts using jq, curl, and a local LLM via Ollama.

Why AI in the SOC (and why Bash)?

  • Volume is the villain. Modern SIEMs surface thousands of events; most require enrichment, dedup, and prioritization. AI compresses “context gathering” from minutes to seconds.

  • Bash is the lingua franca. Every SOC has shells, logs, and APIs. You don’t need new platforms to get value; small scripts can glue your stack together.

  • Data stays inside. With a local model (e.g., Ollama), you can keep telemetry on-prem while still getting natural-language summarization and transformation.

  • Known pitfalls have straightforward mitigations. Privately run models, prompt with guardrails, log model I/O, and never auto-apply risky actions.

Install the prerequisites

We’ll use:

  • curl (HTTP), jq (JSON), whois, dig, git (to fetch playbooks), and a local LLM via Ollama.

On Debian/Ubuntu (apt):

sudo apt update
sudo apt install -y curl jq whois dnsutils git

On Fedora/RHEL/CentOS (dnf):

sudo dnf install -y curl jq whois bind-utils git

On openSUSE/SLE (zypper):

sudo zypper refresh
sudo zypper install -y curl jq whois bind-utils git

Install Ollama (local LLM runtime):

curl -fsSL https://ollama.com/install.sh | sh

Pull a model (pick one you like; llama3 is a solid default):

ollama pull llama3

Optional: verify the service is running (some systems auto-start it):

systemctl status ollama
# or run it manually for this session:
ollama serve

Environment hint:

export LLM_MODEL=llama3

Note: Running models locally uses CPU/GPU and disk space. Keep telemetry minimal and redact secrets before sending any data to the model.


Workflow 1: IOC Enrichment + AI Triage Summary

Problem: Triage takes too long. You get an IP or domain and need “Is it bad? Why? What next?”

Approach: Query a couple of intel sources, add whois/dig context, then ask a local LLM for a concise, structured summary with confidence, rationale, and next steps.

Create enrich.sh:

#!/usr/bin/env bash
set -euo pipefail

IOC="${1:-}"
if [[ -z "$IOC" ]]; then
  echo "Usage: $0 <ip|domain|sha256>"
  exit 1
fi

: "${LLM_MODEL:=llama3}"

# Optional API keys (export before running if you have them)
# export OTX_API_KEY="..."
# export VT_API_KEY="..."
# export ABUSEIPDB_API_KEY="..."

tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT

is_ip() { [[ "$1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; }
is_domain() { [[ "$1" =~ ^([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$ ]]; }
is_sha256() { [[ "$1" =~ ^[A-Fa-f0-9]{64}$ ]]; }

whois_out="$tmpdir/whois.txt"
dig_out="$tmpdir/dig.txt"
intel_out="$tmpdir/intel.json"

if is_ip "$IOC" || is_domain "$IOC"; then
  whois "$IOC" > "$whois_out" 2>/dev/null || true
  dig +short A "$IOC" > "$dig_out" 2>/dev/null || true
fi

# Build a JSON blob of enrichment (OTX example; guard for missing key)
jq -n \
  --arg ioc "$IOC" \
  --arg whois "$(tr -d '\000' < "$whois_out" | jq -Rs '.')" \
  --arg dig "$(tr -d '\000' < "$dig_out" | jq -Rs '.')" \
  '
  {
    ioc: $ioc,
    whois: ($whois | fromjson? // ""),
    dig: ($dig | fromjson? // ""),
    intel: {}
  }
  ' > "$intel_out"

# Pull from OTX if available
if [[ -n "${OTX_API_KEY:-}" && ( is_ip "$IOC" || is_domain "$IOC" ) ]]; then
  OTX_URL="https://otx.alienvault.com/api/v1/indicators"
  if is_ip "$IOC"; then
    curl -s -H "X-OTX-API-KEY: $OTX_API_KEY" "$OTX_URL/IPv4/$IOC/general" \
      | jq '. | {pulse_info, reputation: .reputation, sections}' \
      | jq -c > "$tmpdir/otx.json" || true
  else
    curl -s -H "X-OTX-API-KEY: $OTX_API_KEY" "$OTX_URL/domain/$IOC/general" \
      | jq '. | {alexa: .alexa, sections}' \
      | jq -c > "$tmpdir/otx.json" || true
  fi
  if [[ -s "$tmpdir/otx.json" ]]; then
    jq --slurpfile otx "$tmpdir/otx.json" '.intel.otx = $otx[0]' "$intel_out" > "$tmpdir/x" && mv "$tmpdir/x" "$intel_out"
  fi
fi

# Add placeholder for VirusTotal if you have VT_API_KEY (domain/ip/file)
# See API docs; remember to redact and respect ToS.

prompt="$(jq -c '.' "$intel_out")"

# Ask the local LLM for a concise triage summary in JSON
read -r -d '' system_msg <<'SYS'
You are a SOC analyst. Return ONLY strict JSON with fields:

- severity: one of ["info","low","medium","high","critical"]

- confidence: 0-100

- findings: array of short strings

- recommended_actions: array of imperative steps

- reasoning: one paragraph max
Avoid speculation. If unsure, say so.
SYS

curl -s http://localhost:11434/api/generate \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg model "$LLM_MODEL" --arg sys "$system_msg" --arg ctx "$prompt" \
        '{model:$model, prompt: ($sys + "\n\nContext:\n" + $ctx), stream:false}')" \
  | jq -r '.response' \
  | jq .

Usage:

chmod +x enrich.sh
./enrich.sh 203.0.113.42
./enrich.sh suspicious.example.com
./enrich.sh 9f2c...sha256...

Real-world example: Weekend SSH brute-force on a public server. This script pulls whois/dig and OTX context locally, then produces a JSON with severity “medium”, confidence “75”, key findings (ASN, hosting provider, seen in N pulses), and action items (block at edge WAF, check auth logs, hunt for lateral movement). That JSON can be sent to your ticketing system as-is.


Workflow 2: Summarize Noisy Logs Into Analyst-Ready Notes

Problem: Journald or auth logs are noisy. Analysts want “What happened? What stands out? What should I check next?” quickly.

Approach: Filter for relevant events with jq, batch them, and ask the LLM for a 10-line summary with concrete next steps.

Summarize recent SSH failures:

#!/usr/bin/env bash
set -euo pipefail

: "${LLM_MODEL:=llama3}"
SINCE="${1:-2 hours ago}"

# Collect recent SSH auth failures from journald as JSON lines
events="$(journalctl -u ssh --since "$SINCE" -o json | jq -c 'select(.MESSAGE? | test("Failed password|Invalid user"; "i")) | {ts:.__REALTIME_TIMESTAMP, msg:.MESSAGE, pid:._PID, src:.REMOTE_ADDR?}' | head -n 200)"

if [[ -z "$events" ]]; then
  echo "No matching events."
  exit 0
fi

read -r -d '' system_msg <<'SYS'
You are a SOC analyst. Summarize SSH authentication failures from Linux journald.
Output:

- top_sources: array of {ip, count}

- top_usernames: array of {user, count}

- anomalies: array of short strings

- timeline: 3-6 bullets of notable bursts or patterns

- recommended_actions: 4-8 concrete steps
Return ONLY JSON. Avoid guessing.
SYS

curl -s http://localhost:11434/api/generate \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg model "$LLM_MODEL" --arg sys "$system_msg" --arg ctx "$events" \
        '{model:$model, prompt: ($sys + "\n\nEvents:\n" + $ctx), stream:false}')" \
  | jq -r '.response' \
  | jq .

Tip:

  • Cap batches to a few hundred lines to keep responses fast.

  • Redact usernames or IPs if policy requires.

  • For repeatability, you can add options to control generation: {"options":{"temperature":0.1}} in the body.


Workflow 3: Natural-Language to jq Filter (Safely)

Problem: Analysts often think in natural language: “Show failed SSH logins from a single IP over 5 minutes.” Writing the jq by hand takes time.

Approach: Use the LLM to propose a jq filter, validate it with a simple allowlist, then run it. Keep the model local and forbid shell metacharacters.

ask-jq.sh:

#!/usr/bin/env bash
set -euo pipefail

: "${LLM_MODEL:=llama3}"

if [[ $# -lt 2 ]]; then
  echo "Usage: $0 <json_log_file> <natural language question>"
  exit 1
fi

file="$1"; shift
question="$*"

# Ask model for ONLY a jq filter (no prose).
read -r -d '' sys <<'SYS'
You translate natural language questions into jq filters for JSON log lines.
Rules:

- Output ONLY the jq program on a single line (no backticks, no prose).

- Assume input is line-delimited JSON.

- Prefer safe selectors and pipes; avoid external functions.

- Use strings and regex carefully.
SYS

resp="$(curl -s http://localhost:11434/api/generate \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg model "$LLM_MODEL" --arg sys "$sys" --arg q "$question" \
        '{model:$model, prompt: ($sys + "\n\nQuestion:\n" + $q), stream:false, options:{temperature:0.1}}')" \
    | jq -r '.response' \
    | head -n1 \
    | tr -d '\r')"

# Basic allowlist: letters, numbers, spaces, punctuation typical for jq.
if [[ ! "$resp" =~ ^[[:print:][:space:]]+$ ]]; then
  echo "Refusing suspicious jq filter."
  exit 2
fi

echo "jq filter: $resp" >&2
jq -c "$resp" < "$file"

Example:

journalctl -u ssh -o json --since "1 hour ago" > ssh.json
./ask-jq.sh ssh.json "Show failed password attempts and count them per source IP"

Safety notes:

  • Never let the model emit shell; only a jq expression.

  • Keep a human in the loop for high-impact queries.

  • Consider timeboxing and regex restrictions for production.


Workflow 4: Incident Report Drafting From Artifacts

Problem: Writing the first draft of an incident summary is slow; important details get missed.

Approach: Feed sanitized artifacts (IOC list, detection hits, timelines) to a local model and ask for a concise Markdown report. Humans review and finalize.

draft-report.sh:

#!/usr/bin/env bash
set -euo pipefail

: "${LLM_MODEL:=llama3}"
ARTIFACT_DIR="${1:-artifacts}"

if [[ ! -d "$ARTIFACT_DIR" ]]; then
  echo "Usage: $0 <artifact_directory>"
  exit 1
fi

# Gather small text artifacts (limit size to avoid overloading the model)
context="$(find "$ARTIFACT_DIR" -type f -maxdepth 1 -size -256k -print0 \
  | xargs -0 -I{} sh -c 'echo "===== {} ====="; sed -n "1,500p" "{}"' \
  | jq -Rs '.')"

read -r -d '' sys <<'SYS'
You are a SOC incident handler. Produce a concise Markdown report with:
# Summary

- Incident ID, date range, systems affected, severity, confidence
# Timeline

- Bulleted key events with timestamps
# Findings

- What happened and how we know (cite filenames)
# Impact
# Containment & Eradication
# Recommendations
Keep to ~400-600 words. If data is missing, clearly state assumptions. Do not fabricate.
SYS

body="$(jq -n --arg model "$LLM_MODEL" --arg sys "$sys" --arg ctx "$context" \
  '{model:$model, prompt: ($sys + "\n\nContext:\n" + ($ctx | fromjson)), stream:false, options:{temperature:0.2}}')"

curl -s http://localhost:11434/api/generate \
  -H "Content-Type: application/json" \
  -d "$body" \
  | jq -r '.response' \
  > incident-draft.md

echo "Wrote incident-draft.md"

Usage:

mkdir -p artifacts
cp /var/log/auth.log artifacts/auth.log  # Example; sanitize before copying
echo "IOC: 198.51.100.23" > artifacts/iocs.txt
./draft-report.sh artifacts

Guardrails and Ops Tips

  • Data handling

    • Default to local models (Ollama). If you must use cloud, redact aggressively.
    • Avoid sending raw secrets, credentials, or full PCAPs to any model.
  • Prompt discipline

    • Ask for strict JSON when you need structure.
    • Set low temperature (0.0–0.2) for repeatable outputs.
    • Bound inputs: cap lines, truncate large logs, and batch.
  • Logging and auditing

    • Log prompts and responses to a secure location with timestamps.
    • Tag outputs with model name + version for repeatability.
  • Human-in-the-loop

    • Treat model outputs as analyst assistance, not ground truth.
    • Require human approval for containment actions.
  • Evaluate

    • Keep a sandbox corpus of known incidents; compare model summaries over time.
    • Track false positives/negatives in triage scoring to tune prompts.

What to Do Next (CTA)

  • Pilot one workflow this week:

    • Install prerequisites and Ollama.
    • Wire up Workflow 1 (IOC enrichment + triage JSON).
    • Measure time saved and analyst satisfaction on real tickets.
  • Productionize:

    • Add redaction, logging, and prompt templates under version control.
    • Wrap scripts into your SOAR or ticketing routines.
    • Document “when to use” and “when not to use” each workflow.
  • Iterate:

    • Add your SIEM/API specifics.
    • Build a small library of prompts and playbooks in git.
    • Share improvements across the team.

AI won’t replace analysts—but analysts who automate boring work with AI will outpace the ones who don’t. Start with Bash, keep data local, and ship small wins that pay off immediately.