SOC-in-a-Box: 하나의 LLM, 여덟 가지 역할, 단일 GPU로 구현한 프로덕션급 AI SOC
TL;DR
실제 SOC는 24시간 365일 동안 알림 트리아지, 심층 조사, 사고 대응, 위협 인텔리전스, 탐지 튜닝, 사냥, 교대 관리, 파괴적 행동에 대한 인간 승인 등 여덟 ~ 아홉 가지 뚜렷한 역할을 수행합니다. 우리는 이 전체 조직도를 하나의 로컬 LLM(맥 M1에서 실행되는 GLM‑4.7‑Flash)으로 구현했으며, Redis Streams 버스를 통해 조정합니다. v1은 실제 시스템에 대해 읽기 전용이며, 유일한 쓰기는 XSOAR 메모와 Webex 카드, 그리고 모든 제안된 격리 조치에 대한 인간 승인 게이트입니다.
- 8가지 역할
- 1개의 LLM
- 0개의 쓰기
- 제안 → 인간이 실행
흥미로운 부분은 에이전트 자체가 아니라 다음 세 가지입니다.
1️⃣ 하나의 로컬 LLM이 전체 SOC 조직도를 과부하 없이 처리하도록 만든 아키텍처 선택
2️⃣ “AI가 격리 작업을 수행한다”는 것을 실제 보안 팀이 신뢰하도록 만든 인간‑인‑루프(HITL) 게이트
3️⃣ 실제 과거 티켓을 가지고 에이전트 품질을 정량화할 수 있게 해주는 백테스트 하니스
SOC는 챗봇이 아닙니다. 24×7 이벤트‑드리븐 파이프라인입니다.
- 알림은 지속적으로 들어오며, 요청에 따라 발생하는 것이 아닙니다. 시스템은 누군가 질문을 하지 않아도 이벤트를 소비하고 있어야 합니다.
- 역할은 독립적입니다. Tier 2는 Tier 1에 질문하지 않고, Tier 1이 이미 발표한 결론을 받아 더 깊이 파고듭니다. 위협 인텔리전스는 IR Lead 이후에 실행되며, IR Lead의 사고 과정에 포함되지 않습니다.
- 일부 역할은 반응형이고, 일부는 주기적입니다. Sentinel은 새로운 티켓마다 반응하고, SOC Manager는 8시간마다 교대 요약을 생성하며, Threat Hunter는 하루에 두 번 감사 로그를 스캔하고, Detection Engineer는 평일 아침에 잡음이 많은 규칙을 검토합니다.
- 파괴적인 행동에는 인간 게이트가 필요합니다. 3 AM에 자동으로 호스트를 격리하는 AI는 한 달 안에 전원을 끊깁니다. 중요한 질문은 인계 절차가 어떻게 보이는가입니다.
- 감사 가능성은 절대 타협할 수 없습니다. 모든 결정은 사고 회고와 튜닝을 위해 재생 가능해야 합니다.
이러한 제약 조건이 아키텍처를 결정했으며, 반대가 아닙니다.
flowchart TB
XSOAR[XSOAR ticket feed] --> Sentinel
subgraph Bus["Redis Streams bus (lab-vm1)"]
direction LR
STRG[soc.triage]
SCAS[soc.cases]
SAUD[soc.audit]
end
Sentinel[Sentinel / Tier 1
alert triage] --> STRG
STRG --> Tier2[Tier 2 Analyst
deeper investigation]
Tier2 --> SCAS
SCAS --> IR[IR Lead
SEV + containment plan]
IR --> SCAS
IR -.HITL action proposed.-> Flask[Flask HITL pages
/soc-hitl/decide
/soc-hitl/audit]
Webex[Webex card buttons] -.click.-> Flask
Flask --> SCAS
SCAS --> TI[Threat Intel
actor + MITRE]
TI --> SCAS
SAUD -.replay.-> SOCMgr[SOC Manager
shift summaries
06/14/22 EST]
SAUD -.replay.-> DetEng[Detection Engineer
rule tuning
09:00 EST M-F]
SAUD -.replay.-> Hunter[Threat Hunter
pattern sweeps
06/18 EST]
STRG -.mirror.-> SAUD
SCAS -.mirror.-> SAUD
style Bus fill:#1e3a8a,color:#fff
style Flask fill:#fef3c7,color:#92400e
style SAUD fill:#7c2d12,color:#fff
세 개의 반응형 역할(Tier 2 / IR Lead / Threat Intel)은 버스 위의 장기 실행 컨슈머이며, 세 개의 주기형 역할(SOC Manager / Detection Engineer / Threat Hunter)은 시스템d 타이머 유닛으로 캘린더 일정에 따라 깨워져 감사 스트림을 재생하고 보고서를 내보냅니다. HITL 인터페이스는 기존 IR 웹 앱 옆에 배치된 Flask 블루프린트입니다.
프레임워크 선택은 로드‑베어링이었습니다—잘못 선택하면 이후 모든 추상화가 이를 방해합니다. 우리는 다섯 가지 경로를 평가했습니다.
-
CrewAI – 역할‑형 에이전트가 하나의 작업에 협업하도록 설계되었습니다. 선언형 Agent + Task + Process(순차 또는 계층)와 같은 강력한 위임 프리미티브를 제공합니다.
SOC와의 불일치: CrewAI는 단일 프로세스 내 오케스트레이션을 전제로 합니다. “크루를 띄우고, 작업을 실행하고, 결과를 받는다.” 우리의 역할은 독립적인 프로세스로, 자체 가동 시간, 감사, 재시작 의미론, HITL 게이트를 가집니다. CrewAI의 인간‑인‑루프는human_input=True인 Task에 대한 차단형 stdin 프롬프트이며, “Webex 카드 → Flask 페이지 → SQLite 사이드카 → 버스 이벤트” 흐름을 견디지 못합니다. 따라서 감사 스트림 재생, 백테스트, 역할별 시스템d 가동 시간을 포기하게 됩니다.
가능한 활용: 단일 역할 내부 추론에 CrewAI를 끼워 넣을 수 있습니다. 예를 들어 Tier 2의handle()안에서 LLM‑툴‑루프를 작은 크루(조사관 + 비평가 + 결정자)로 교체하고, 그 뒤에Tier2Analysis이벤트를 발행하는 식입니다. 현재는 비평가‑루프 패턴이 충분히 작동하므로 아직은 필요하지 않습니다. -
AutoGen – 에이전트‑간 대화를 관리하는 GroupChat 매니저를 제공합니다. “두 LLM이 논쟁하고 답을 수렴한다”는 시나리오(코드 작성자 vs 코드 리뷰어, 옹호자 vs 비평가)에 적합합니다.
SOC와의 불일치: SOC는 대화가 아닙니다. Tier 2는 Tier 1에 질문하지 않고, Tier 1의 결정을 소비합니다. 대화‑히스토리를 상태로 사용하는 모델은 불필요한 컨텍스트 윈도우 비용을 초래하고, GroupChat 오케스트레이터는 독립적으로 재시작할 수 없는 로드‑베어링 요소가 됩니다. -
가장 저항이 적은 경로 – 각 역할을 파이썬 함수로 구현하고 순차적으로 체인하는 방법. 처음에 우리는 이 방식으로 시작했지만, 문제가 드러났습니다. 동기 체인은 모든 역할이 이전 역할이 끝날 때까지 대기하게 만들고, 역할별 재시작을 불가능하게 하며, HITL을 해킹 없이 구현할 수 없게 하고, 별도 감사 로그를 구축하지 않으면 로그가 남지 않습니다. 두 역할만 있으면 괜찮지만 우리는 8개가 필요했습니다.
-
n8n 등 시각적 워크플로 도구 – 리더십이 박스‑와‑화살표를 보는 것을 좋아하기 때문에 후보에 올랐습니다. 하지만 LLM 노드는 1급 객체가 아니며, 모든 모델 호출을 HTTP로 감싸야 하고, 그래프가 데이터베이스에 저장돼 PR에서 검토 가능한 코드가 아닙니다. 감사 가능성과 재현성이 LangGraph + 버스 경로보다 열악합니다. (n8n은 LLM이 아닌 SOAR‑스타일 자동화에 적합합니다.)
-
솔직한 베이스라인 – 파이썬 asyncio 워커, Redis Streams 컨슈머 그룹, 에이전트 프레임워크 없이 구현. 프레임워크 추상화를 없애는 대신, LangGraph와 같은 도구가 제공하는 프롬프트 + 툴‑루프 + 상태 관리 파이프라인을 직접 구현해야 합니다. 한 역할 POC에는 괜찮지만, 8개 역할에서는 LangChain을 제대로 재구현하는 셈입니다.
LangGraph + Redis Streams 조합이 최적이었습니다. LangGraph는 역할별 툴‑루프와 명시적 상태를 제공하고, Redis Streams는 내구성 있는 이벤트, 최소 한 번 전달을 보장하는 컨슈머 그룹, 감사 스트림(다른 컨슈머) 및 기존 역할을 건드리지 않고 새로운 역할을 쉽게 추가할 수 있는 인프라를 제공합니다. 핵심은 분리입니다: LangGraph는 에이전트 런타임, 버스는 조직도 역할을 담당합니다. 두 개념을 혼동하지 마세요.
우리는 하나의 로컬 LLM—Mac M1(64 GB)에서 vllm‑mlx로 구동되는 GLM‑4.7‑Flash 8‑bit—을 사용하고, 각 역할마다 다른 시스템 프롬프트와 툴 화이트리스트를 전달합니다. 복원력은 FailoverChatModel(이전 포스트에서 최초 소개) 덕분에 확보됩니다. 기본 모델이 죽으면 스튜디오 1 박스에 있는 Qwen 3 백업 모델로 투명하게 전환하고, 기본 모델이 복구되면 즉시 되돌아갑니다.
📦 새로운 오픈소스 – 이제 이 FailoverChatModel이 독립적인 경량 패키지(langchain-failover)로 PyPI에 공개되었습니다. pip install langchain-failover 후 두 개의 챗 모델을 지정하면, GPU 박스가 다운될