🛡️ ROGLAG — Production Plan & Tech Stack

แผนยกระดับจาก demo (stdlib HTTP + in-memory) ไปสู่ระบบ Security Log RAG + Automation ระดับ production

RAG Security Log Analytics n8n Automation Vector DB Docker FastAPI PostgreSQL
NOW เฟส 1 (MVP รันได้) NEXT เฟส 2 (production core) LATER เฟส 3 (scale & ops)

RUN วิธีรันโปรเจกต์ตอนนี้

ต้องมี Python 3.10+ — local mode ใช้ stdlib ล้วน ไม่ต้องลง dependency

# Local mode (keyword RAG + local fallback) — ใช้ได้ทันที
python3 server.py            # เปิด http://127.0.0.1:8765

# เปิด LLM summary ผ่าน OpenRouter
export OPENROUTER_API_KEY="your_key"
python3 server.py

# Vector RAG จริง (build index ก่อน)
python3 build_vector_index.py --limit 10000 --batch-size 32
python3 server.py

# รันกับชุด 50k
LOGRAG_DATA_FILE=Data/files/security_logs_extended_50k.jsonl python3 server.py
โหมด local ทำงานได้แม้ไม่มี API key — ระบบ fallback ทุกชั้น (vector → keyword → rule-based local answer)

ประเมินของเดิม (ทำไมยังไม่ production-ready)

เข้าใจข้อจำกัดก่อน เพื่อรู้ว่าต้องเปลี่ยนอะไร

ด้านของเดิม (demo)ปัญหาตอนขึ้นจริง
Web serverhttp.server + ThreadingHTTPServerไม่มี async/connection pool, ไม่เหมาะ traffic จริง, ไม่มี auth
Data storeโหลด JSONL ทั้งไฟล์เข้า RAM ตอน startไม่ scale, restart ช้า, query ใหม่ไม่ได้, ไม่มี retention
Indexสร้าง TF-IDF/vector ใน memoryหายเมื่อ restart, ไม่ incremental, single process
Logic ซ้ำserver.py กับ api/_lograg.py ซ้ำกันเกือบหมดแก้ rule ต้องแก้ 2 ที่ — แหล่ง bug
Ingestionไม่มี — ใช้ไฟล์สังเคราะห์ staticไม่มีทางรับ log จริงแบบ real-time
Automationหน้าเว็บ poll /api/alerts ทุก 15 วิไม่มี action จริง (block IP, ticket, notify)
Secrets/Authไม่มี authentication เลยเปิด public = ใครก็เรียก API ได้
สิ่งที่เก็บไว้ได้: CATEGORY_META (rule + MITRE + runbook), logic detect_rule, query expansion ไทย/อังกฤษ, โครงสร้าง API — ทั้งหมดนี้ port ไป FastAPI ได้ตรงๆ

Target Architecture (production)

แยกเป็นชั้นชัดเจน: ingest → process → store → RAG/API → automation → notify

Log Sources
auth/nginx/fw/syslog
Collector
Vector / Fluent Bit
Queue
Redpanda / Redis Stream
Processor
classify + embed
Stores
PG + Qdrant + OpenSearch
RAG API
FastAPI
n8n
orchestration
Enrich
GeoIP / threat intel
Action
ticket / block / notify

หลักการ: ทุก critical alert ที่ classifier จับได้ → ยิงเข้า n8n → enrich ด้วย threat intel → เรียก RAG API สรุปเป็นภาษาไทย → สร้าง ticket + แจ้งเตือน + (ออปชัน) block IP อัตโนมัติ

Tech Stack รวบรวม

เลือกแบบ self-hostable ก่อน (ลง Docker ได้หมด) แล้วค่อยสลับไป managed service ทีหลัง

Core Pipeline

ชั้นเลือกใช้ทางเลือกเฟส
Log collectorVector.devFluent Bit, FilebeatNEXT
Message queueRedpanda (Kafka API)Redis Streams, NATS, KafkaNEXT
API / RAG serviceFastAPI + UvicornLitestar, FlaskNOW
Task workerARQ / Celery + RedisDramatiq, RQNEXT

Data Stores

ชนิดเลือกใช้ใช้เก็บอะไร
RelationalPostgreSQL 16alerts, incidents, users, audit, runbook, rule config
Vector DBQdrant (โค้ดเดิมรองรับอยู่แล้ว)embeddings ของ log message สำหรับ RAG
Log searchOpenSearch (หรือ ClickHouse)full-text + time-series log จำนวนมหาศาล
Cache / queueRedisrate-limit, task queue, dedup alert key
ทางลัดประหยัด: ใช้ pgvector บน PostgreSQL แทน Qdrant ได้ในเฟสแรก เหลือ DB เดียว — แต่ Qdrant scale ดีกว่าเมื่อ vector เยอะ. ClickHouse เหมาะกว่า OpenSearch ถ้าเน้น analytics/ราคาถูก

AI / RAG

หน้าที่เลือกใช้ทางเลือก
EmbeddingsOpenRouter (เดิม)OpenAI, Ollama (local: nomic-embed-text)
LLM สรุปOpenRouter (เดิม)Ollama (llama3/qwen), vLLM self-host
RAG frameworkเขียนเอง (เบา, คุมได้)LlamaIndex, Haystack

Automation, Frontend & Ops

Automation

n8n (self-host) — orchestrate alert → enrich → action

Frontend

คงหน้า HTML เดิมได้ หรือย้ายไป Next.js + Tailwind เมื่อต้อง auth/role

Notify

Slack / Discord / Email (SMTP) / PagerDuty / LINE Notify

Threat Intel

AbuseIPDB, VirusTotal, GreyNoise, MaxMind GeoIP

Observability

Prometheus + Grafana + Loki

Auth/Gateway

Traefik / Caddy + OAuth2-proxy หรือ Keycloak

Secrets

Doppler / Infisical / .env + SOPS

Container/CI

Docker Compose → Kubernetes, GitHub Actions

Pipeline จริง (data flow ละเอียด)

เส้นทางของ log ตั้งแต่เข้าระบบจนเกิด action

  1. Ingest — Vector/Fluent Bit อ่าน log จาก source (syslog, file, http) → ส่งเข้า Redpanda topic logs.raw
  2. Classify — worker consume logs.raw → รัน detect_rule() (port มาจากของเดิม) → ใส่ category/severity/MITRE → เขียนลง PostgreSQL + OpenSearch
  3. Embed — worker เดียวกัน (หรือแยก) เรียก embedding model → upsert vector เข้า Qdrant พร้อม payload (row + metadata)
  4. Detect critical — ถ้า severity = critical → group ตาม alert_key (logic เดิม) → publish เข้า topic alerts.critical + insert ตาราง alerts
  5. Orchestrate — n8n trigger จาก webhook/queue → enrich → RAG → action (รายละเอียดข้อ ⑤)
  6. Query/RAG — FastAPI /api/ask: retrieve จาก Qdrant (vector) + OpenSearch (keyword) → hybrid rank → ส่ง context ให้ LLM → ตอบภาษาไทย
logs.raw  ──> [classify worker] ──> PostgreSQL (structured + alerts)
                      │              └─> OpenSearch (full-text search)
                      └─> [embed worker] ──> Qdrant (vector RAG)

severity=critical ──> alerts.critical (queue) ──> n8n webhook ──> enrich+RAG+action

User/Frontend ──> FastAPI /api/ask ──> hybrid retrieve (Qdrant + OpenSearch)
                                          └─> LLM (OpenRouter/Ollama) ──> Thai answer

n8n Workflows

หัวใจของ automation — แต่ละ workflow คือ DAG ของ node

WF-1: Critical Alert Responder

Webhook
/critical
GeoIP + AbuseIPDB
enrich src_ip
HTTP: RAG
POST /api/ask
Switch
by category
Create Ticket
Jira/GitHub
Notify
Slack/LINE

WF-2: Daily Threat Digest

Schedule (เช้า 9 โมง) → query /api/stats + top IPs → RAG สรุปภาพรวม 24 ชม. → ส่งรายงานเข้า Slack channel

WF-3: Auto-block Feedback Loop

เมื่อ analyst กด "confirm threat" บน dashboard → webhook → n8n update firewall rule + บันทึก audit ลง PostgreSQL + (ออปชัน) ใส่ IP เข้า blocklist ที่ feed กลับ collector

ข้อควรระวัง auto-block: การ block IP อัตโนมัติคือ action ที่ผลกระทบสูง — ควรมี allowlist (IP ภายใน/พาร์ทเนอร์), require approval node สำหรับ critical action, และ TTL ให้ block ชั่วคราวก่อน

Database Schema (PostgreSQL)

โครงเริ่มต้น — เก็บ structured log, alert grouping, audit trail

-- log ที่ผ่าน classify แล้ว (hot 30-90 วัน, retention policy แยก)
CREATE TABLE log_events (
  id           BIGSERIAL PRIMARY KEY,
  ts           TIMESTAMPTZ NOT NULL,
  source       TEXT NOT NULL,              -- auth/nginx/firewall/system
  category     TEXT NOT NULL,              -- brute_force, c2_beacon, ...
  severity     TEXT NOT NULL,              -- info/medium/high/critical
  mitre        TEXT,
  risk_score   SMALLINT,
  src_ip       INET,
  dst_ip       INET,
  "user"       TEXT,
  message      TEXT NOT NULL,
  raw          JSONB NOT NULL,             -- เก็บ field ดิบทั้งหมด
  embedded     BOOLEAN DEFAULT FALSE       -- ส่งเข้า Qdrant แล้วหรือยัง
);
CREATE INDEX ON log_events (ts DESC);
CREATE INDEX ON log_events (category, severity);
CREATE INDEX ON log_events (src_ip);

-- alert ที่ group แล้ว (จาก alert_key เดิม)
CREATE TABLE alerts (
  id            TEXT PRIMARY KEY,          -- ALT-xxxxxx
  alert_key     TEXT NOT NULL,
  title         TEXT NOT NULL,
  category      TEXT NOT NULL,
  severity      TEXT NOT NULL DEFAULT 'critical',
  mitre         TEXT,
  status        TEXT NOT NULL DEFAULT 'new', -- new/ack/resolved/false_positive
  event_count   INT NOT NULL,
  first_seen    TIMESTAMPTZ NOT NULL,
  last_seen     TIMESTAMPTZ NOT NULL,
  src_ip        INET, dst_ip INET, "user" TEXT,
  rag_summary   TEXT,                      -- คำตอบจาก LLM
  enrichment    JSONB,                     -- ผล GeoIP/threat intel
  assigned_to   TEXT,
  created_at    TIMESTAMPTZ DEFAULT now(),
  updated_at    TIMESTAMPTZ DEFAULT now()
);

-- audit ทุก action (โดยเฉพาะ auto-block)
CREATE TABLE audit_log (
  id          BIGSERIAL PRIMARY KEY,
  ts          TIMESTAMPTZ DEFAULT now(),
  actor       TEXT NOT NULL,               -- user / n8n / system
  action      TEXT NOT NULL,               -- block_ip / create_ticket / ack
  target      TEXT,
  alert_id    TEXT REFERENCES alerts(id),
  detail      JSONB
);

-- rule config (ย้าย CATEGORY_META ออกจาก hardcode มาเป็น data)
CREATE TABLE rule_config (
  category    TEXT PRIMARY KEY,
  label       TEXT, mitre TEXT, risk SMALLINT, runbook TEXT,
  enabled     BOOLEAN DEFAULT TRUE
);
ย้าย CATEGORY_META จาก hardcode ใน Python มาเป็นตาราง rule_config → แก้ runbook/risk ได้โดยไม่ต้อง deploy ใหม่ และเลิกปัญหา logic ซ้ำ 2 ไฟล์

Docker (โครงอ้างอิงสำหรับขึ้น proj จริง)

ไฟล์อ้างอิง — ปรับ version/secret ตอนทำจริง

Dockerfile (FastAPI service)

FROM python:3.12-slim
WORKDIR /app
ENV PYTHONUNBUFFERED=1 PIP_NO_CACHE_DIR=1

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .
EXPOSE 8000
# ใช้ uvicorn worker จริง (อย่าใช้ http.server เดิม)
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]

docker-compose.yml (full stack dev)

services:
  api:
    build: .
    ports: ["8000:8000"]
    env_file: .env
    depends_on: [postgres, qdrant, redis]

  worker:                      # classify + embed consumer
    build: .
    command: python -m app.worker
    env_file: .env
    depends_on: [postgres, qdrant, redis, redpanda]

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_PASSWORD: ${PG_PASSWORD}
      POSTGRES_DB: roglag
    volumes: ["pgdata:/var/lib/postgresql/data"]
    ports: ["5432:5432"]

  qdrant:
    image: qdrant/qdrant:latest
    volumes: ["qdrant:/qdrant/storage"]
    ports: ["6333:6333"]

  redis:
    image: redis:7-alpine
    ports: ["6379:6379"]

  redpanda:                    # Kafka-compatible, เบากว่า Kafka
    image: redpandadata/redpanda:latest
    command: redpanda start --smp 1 --overprovisioned --node-id 0
    ports: ["9092:9092"]

  n8n:
    image: n8nio/n8n:latest
    environment:
      N8N_HOST: localhost
      WEBHOOK_URL: http://n8n:5678/
    volumes: ["n8n:/home/node/.n8n"]
    ports: ["5678:5678"]

  vector:                      # log collector
    image: timberio/vector:latest-alpine
    volumes: ["./vector.toml:/etc/vector/vector.toml:ro"]
    depends_on: [redpanda]

volumes:
  pgdata: {}
  qdrant: {}
  n8n: {}
ทุก service เปิด port ใน compose นี้ไม่มี auth — สำหรับ dev เท่านั้น. ตอนขึ้น production ให้วาง Traefik/Caddy + OAuth ข้างหน้า, ปิด port ที่ไม่จำเป็น, ใส่ password ทุกตัวผ่าน secret manager

Migration Roadmap

ทำเป็นเฟส — แต่ละเฟสรันได้จริงก่อนไปต่อ

เฟส 1 Refactor core (1-2 สัปดาห์)

เฟส 2 Real ingestion + automation (2-4 สัปดาห์)

เฟส 3 Scale & Ops (ต่อเนื่อง)