LLM에 가공되지 않은 경고(Raw Alerts)를 그대로 전달하는 것을 멈추세요: 먼저 상관관계를 분석하고 마지막에 에스컬레이션하는 SOC
요약
LLM에 개별 보안 경고를 직접 전달하는 대신, 상관관계 분석을 통해 인시던트를 먼저 식별하는 효율적인 AI SOC 아키텍처를 제안합니다. Aegis 시스템은 규칙 엔진으로 노이즈를 먼저 제거한 뒤, 모호한 사례만 Claude 에이전트에게 전달하여 비용과 정확도를 최적화합니다.
핵심 포인트
- 고립된 경고는 노이즈이며, 경고 간의 상관관계를 분석해야 실제 위협을 식별할 수 있음
- 모든 경고에 LLM을 사용하면 막대한 API 비용이 발생하므로 결정론적 규칙 엔진이 선행되어야 함
- LLM은 자유 형식의 답변이 아닌, 다운스트림 시스템이 활용 가능한 구조화된 출력을 제공해야 함
- Aegis는 규칙 기반 필터링을 통해 실제 공격 상황에서만 토큰을 소비하도록 설계됨
몇 주마다 새로운 데모가 제 피드에 올라옵니다. 누군가가 보안 경고(Security Alert)를 대규모 언어 모델(LLM)에 전달하고, SOC 분석가처럼 들리는 한 단락의 답변을 받아낸 뒤, Tier-1 자동화를 선언합니다. Cisco FTD 침입 이벤트, Defender 탐지, 로그인 위험 경고 등 기업의 경고 큐(Alert Queues)를 수년간 직접 받아온 입장에서, 저는 왜 그러한 데모들이 실제 운영 환경(Production)에서는 실패하는지 말씀드릴 수 있습니다:
- 고립된 경고는 노이즈에 불과합니다. 진짜 신호(Signal)는 경고들 사이의 '이야기'입니다. 즉, 동일한 행위자가 위험한 Entra ID 로그인에 나타난 후, AWS 정찰(Recon)을 수행하고, 이어서 지속성(Persistence) 동작을 보이는 흐름입니다. 한 번에 하나의 경고만 분류하는 LLM은 이러한 캠페인(Campaign)을 볼 수 없습니다.
- 비용은 경고 볼륨에 따라 확장되며, 경고 볼륨은 엄청납니다. 모든 이벤트마다 API 호출 비용이 발생한다면, 분류(Triage) 비용은 가장 노이즈가 심한 센서의 볼륨에 따라 선형적으로 증가하게 됩니다.
- 자유 형식의 판결(Free-text verdicts)은 실행 가능하지 않습니다. "이것은 의심스러워 보입니다"라는 말은 누구에게도 페이지(Page)를 보낼 수 없습니다. 다운스트림 시스템(Downstream system)이 경로를 지정할 수 있는 구조화된 출력(Structured output)이 필요합니다.
만약 이런 큐(Queue)를 다뤄본 적이 없다면, 그 비율은 믿기 어려울 정도일 것입니다. 단 하나의 FTD 침입 정책이 아주 조금만 공격적으로 설정되어도 하루에 수천 개의 IPS 이벤트가 발생하며, 그중 대부분은 취약한 대상에 도달하지도 않은 스캐너 트래픽에 대해 동일한 몇 가지 시그니처가 작동하는 것입니다. MECM 패치 웨이브(Patch wave)는 휴리스틱(Heuristics)이 학습한 드롭퍼(Dropper)와 정확히 일치하는 설치 프로그램 동작을 탐지하여 엔드포인트 AV(Endpoint AV)를 가동시키기도 합니다. 대부분의 기업에서 경고 대비 인시던트(Alert-to-incident) 비율은 퍼센트(%)가 아니라 자릿수(Orders of magnitude) 단위로 측정됩니다. 따라서 흥미로운 엔지니어링 문제는 결코 "모델이 하나의 경고에 대해 그럴듯한 한 단락을 쓸 수 있는가"가 아닙니다. 그 외의 모든 것들을 어떻게 처리하느냐가 핵심입니다.
그래서 저는 제가 생각하는 올바른 형태인 **정규화(normalize) → 상관관계 분석(correlate) → LLM이 정말 필요한지 결정 → 구조화된 판결(structured verdict) → 게이트가 있는 봉쇄(gated containment)**를 입증하기 위해, 실제로 작동하는 AI SOC 분석가인 Aegis를 구축했습니다. Aegis는 네 가지 소스(AWS GuardDuty, CloudTrail, Entra ID 로그인 로그, Microsoft Defender)로부터 합성 텔레메트리(synthetic telemetry)를 수집하고, 17개의 가공되지 않은 이벤트(raw events)를 인시던트(incidents)로 엮으며, 토큰을 소비하지 않고도 오탐(false positives)을 자동으로 억제합니다. 그리고 정말로 모호하거나 위험한 사례만을, 결론을 내리기 전 조사가 반드시 필요한 Claude 도구 사용(tool-use) 에이전트에게 전달합니다.
이 전체 시스템은 의존성 없이 오프라인으로 실행되며(LLM 대신 결정론적 규칙 엔진(deterministic rule engine)이 자리 잡고 있음), ANTHROPIC_API_KEY가 존재하는 즉시 라이브 에이전트로 업그레이드됩니다. 데모 실행 결과, 4개의 인시던트 중 3개는 비용이 $0.00이었습니다. 실제 공격만이 API를 호출합니다.
이 글에서는 리포지토리(repo)의 실제 코드를 바탕으로 아키텍처와 설계 결정 사항을 살펴봅니다.
파이프라인 개요
수집(ingest) ─▶ 상관관계 분석(correlate) ─▶ AI 분류(AI triage) ─▶ 대응 플레이북(response playbook) ─▶ 보고(report)
(4개 소스) (미니 SIEM) (Claude 에이전트) (Graph / PS / AWS) (HTML + 콘솔)
ai-soc-analyst/
├─ run_demo.py # 단일 명령 엔트리 포인트
├─ data/ # 합성 텔레메트리 (소스당 파일 하나)
...
1단계: 모든 것을 하나의 스키마로 정규화하기
GuardDuty 탐지 결과, CloudTrail 기록, Entra 로그인 로그, Defender 경고는 모두 JSON 형태가 판이하게 다르며, 더 심각한 문제는 심각도(severity)를 나타내는 어휘 체계도 다르다는 점입니다. GuardDuty는 0~10 사이의 부동 소수점(float) 값을 제공하는 반면, Microsoft는 "Informational"과 같은 문자열을 제공합니다. 초기에 이를 통합하지 않으면, 모든 하위 컴포넌트가 각 소스에 특화된 분기(branch)를 가지며 비대해지게 됩니다.
Aegis는 모든 것을 하나의 SecurityEvent 데이터 클래스(dataclass)로 평탄화(flatten)하며, 심각도 강제 변환(severity coercion)은 정확히 한 곳에서 이루어집니다:
class Severity(IntEnum):
INFO = 0
LOW = 1
...
한 가지 의도적인 선택: 알 수 없는 심각도(severity) 문자열은 INFO가 아닌 MEDIUM으로 대체됩니다. 만약 소스(source)가 예상하지 못한 어휘를 방출하기 시작하더라도, 해당 이벤트들이 분류(triage) 하한선 아래로 조용히 사라지는 것이 아니라 하한선
_위(above)_에 위치하기를 원하기 때문입니다.
소스를 추가하는 것은 하나의 정규화(normalizer) 함수입니다. CloudTrail 정규화기는 수집(ingest) 시점에 운영 지식을 인코딩하는 좋은 예시입니다. 이 정규화기는 읽기 전용 정찰(recon)보다 쓰기 및 방어 회피(defense-evasion) API 호출에 더 높은 점수를 부여하므로, 상관관계(correlation) 계층은 자연스럽게 지속성(persistence) 및 변조(tamper) 작업을 더 높은 가중치로 처리합니다:
high_impact = {
"CreateAccessKey", "StopLogging", "DeleteTrail", "PutUserPolicy",
"AttachUserPolicy", "CreateUser", "UpdateAssumeRolePolicy",
...
2단계: 경고(alert)만이 아닌 행위자(actor)를 기준으로 상관관계 분석하기
이 부분은 대부분의 "LLM SOC" 데모가 건너뛰는 부분이며, 실제로 가장 중요한 부분입니다. Aegis는 슬라이딩 시간 창(sliding time window) 내에서 공유된 ID(identity) 또는 공유된 소스 IP를 기반으로 유니온 파인드(union-find) 알고리즘을 사용하여 이벤트를 클러스터링(cluster)한 다음, 중첩되는 클러스터들을 이행적으로(transitively) 병합합니다. 공격자는 피벗(pivot)을 수행하기 때문입니다:
for i in range(len(ordered)):
for j in range(i + 1, len(ordered)):
if ordered[j].timestamp - ordered[i].timestamp > window:
...
대부분의 첫 시도에서 발생하는 미묘한 버그는 다음과 같습니다: 동일한 사람이 서로 다른 제어 평면(control plane)에서 서로 다른 ID 문자열로 나타나는 경우입니다. 사용자의 Entra UPN과 AWS IAM CLI 사용자는 상관관계 엔진 입장에서 서로 다른 주체(principal)로 간주됩니다. 별도로 가르쳐주지 않는 한 말이죠:
def _same_identity(p1: str, p2: str) -> bool:
# 'j.okafor@corp.example', 'j.okafor-cli', 그리고 'j.okafor'는
# 모두 동일한 사람을 가리킵니다. 실제 공격자는 이들을 가로질러 피벗합니다.
...
이러한 휴리스틱(Heuristic)이 순진한(naive) 방식인가요? 전적으로 그렇습니다. 이는 한 조직의 명명 규칙(naming convention)을 인코딩한 것이며, 실제 운영 환경에서는 이를 아이덴티티 그래프(Identity Graph, 예: Entra ID ↔ AWS SSO 매핑)로 뒷받침해야 합니다. 하지만 아키텍처 측면에서의 핵심은 변하지 않습니다. 제어 평면(Control Plane) 간의 아이덴티티 해상도(Identity Resolution)는 사후에 추가하는 데이터 보강(Enrichment) 기능이 아니라, 일급 상관관계(First-class Correlation) 기능이어야 합니다. 데모에서 이 기능은 Tor 로그인 → MFA 피로 공격(MFA Fatigue) → AWS 정찰(Recon) → CreateAccessKey 지속성 확보 → StopLogging 변조 → 엔드포인트 로더(Endpoint Loader) → 메일박스 규칙 유출(Mailbox-rule Exfil)로 이어지는 체인을 4개의 콘솔에 흩어진 7개의 중간(Medium) 등급 경고가 아닌, **하나의 P1 인시던트(Incident)**로 엮어주는 역할을 정확히 수행합니다.
그리고 이것은 클라우드만의 문제가 아닙니다. 전형적인 Cisco 및 Microsoft 기반의 기업 환경에서, 한 명의 관리자는 Entra 로그인 로그에는 j.okafor@corp.com으로, Windows 보안 이벤트에는 CORP\jokafor로, ISE 라이브 세션 테이블에는 단순한 jokafor로(또는 세션이 MAB를 통해 인증된 경우 엔드포인트 MAC 주소로만), FMC 감사 기록에는 로컬 계정 이름으로, vCenter SSO에는 CORP.LOCAL\jokafor로 존재합니다. 5개의 제어 평면, 5개의 철자, 그리고 정규 키(Canonical Key)에 대한 합의는 전혀 없습니다. 이러한 문자열들을 5명의 서로 다른 사람으로 취급하는 상관관계 엔진(Correlation Engine)은 하나의 이야기(Story)가 있는 상황에서 5개의 중간 등급 경고를 던져줄 것입니다. SIEM 벤더들은 아이덴티티 해상도를 데이터 보강(Enrichment) 애드온으로 판매하지만, 저는 이것이 상관관계 키(Correlation Key) 자체에 포함되어야 한다고 주장합니다.
3단계: LLM이 정말 필요한지 결정하기
데모 수준을 넘어 실제 배포 가능한 수준으로 만드는 비용 제어 레버(Cost-control lever)가 여기에 있습니다. Aegis는 *계층형 분류(Tiered Triage)*를 실행합니다. 결정론적(Deterministic) 사전 필터가 명백한 사례들을 무료로 자동 해결하며, 악성 지표(Malicious Indicator), 신호가 높은 ATT&CK 기법, 또는 진정한 모호성을 포함하는 인시던트만을 에스컬레이션(Escalate)합니다.
def _should_escalate(incident: Incident) -> bool:
reputations = [enrich.lookup_ip(ip) for ip in incident.src_ips]
has_bad_ip = any(r.reputation in {"malicious", "suspicious"} for r in reputations)
...
HIGH_SIGNAL_TECHNIQUES는 핵심적인 기법들을 모아놓은 짧고 주관적인 집합입니다 — 지속성 유지 (T1098.001), 클라우드 로그 변조 (T1562.008), PowerShell 실행 (T1059.001), 메일함 규칙을 통한 데이터 유출 (T1114.003), MFA 피로 공격 (T1621), Tor 프록시 사용 (T1090.003). 이들은 잘못된 자동 억제 (auto-suppress)가 발생했을 때 비용이 매우 큰 기법들이므로, 항상 판단 (judgment call) 과정을 거치게 됩니다.
모든 기업이 결국 작성하게 되는 억제 규칙들은 이 프리필터 (pre-filter)가 인코딩하고 있는 내용과 동일합니다: 정기적으로 IPS 시그니처를 트리거하는 내부 취약점 스캐너, 보안 팀이 매 분기마다 생성하는 EICAR 파일, 새벽 3시에 데이터센터 이그레스 (egress)에서 원래 의도된 대로 인증을 수행하는 백업 및 CI 서비스 계정 등이 그것입니다. 실패 모드 또한 어디나 마찬가지입니다. 광범위하게 작성된 억제 규칙(
{
"name": "submit_verdict",
"description": "최종 분류(triage) 판결을 제출합니다. 조사를 마친 후 정확히 한 번만 호출하세요.",
...
문단에서 심각도(severity)를 추출하기 위해 산문을 파싱하거나 정규 표현식(regex)을 사용할 필요가 없습니다. 판결(verdict)은 플레이북(playbook) 선택과 보고서로 즉시 라우팅됩니다. 또한 에이전트 루프(agent loop)는 모든 도구 호출(tool call)을 사람이 읽을 수 있는 추적(trace)으로 기록하므로, 판결을 검토하는 분석가는 기계가 어떻게 조사했는지 확인할 수 있습니다.
AI 에이전트 조사 (claude-haiku-4-5를 통해):
lookup_ip(185.220.101.47) -> 악성 (tor-exit-node, 익명화 도구, c2-인접)
get_user_context(j.okafor@...) -> 일반 사용자
...
이러한 추적은 단순한 눈속임이 아닙니다. 모델이 사고 우선순위에 영향을 미치도록 허용하려면, 분석가의 신뢰를 얻기 위해, 그리고 모델이 잘못된 판단을 내렸을 때 사후 검토(post-incident review)를 위해 "풀이 과정(show your work)"을 보여주는 것은 최소한의 기준입니다.
에이전트 경로에서 실제 운영 환경을 고려한 두 가지 세부 사항은 다음과 같습니다.
- 항상 안전하게 실패(Fail safe)하십시오. 공개된
triage()엔트리 포인트(entry point)는 라이브 에이전트를try/except로 감쌉니다. 모든 API 오류나 단계 제한 초과(step-limit overrun)는 결정론적 엔진(deterministic engine)으로 폴백(fallback)되며, 발생한 상황을 판결에 주석으로 남깁니다. 단 한 번의 API 문제로 인해 교대 근무 도중 경고 큐(alert queue)가 멈추는 일은 결코 발생하지 않습니다. - 비용은 미스터리가 아니라 가시적이어야 합니다. 모든 실행은 사고당 토큰 사용량을 추적하고 예상 달러 비용을 출력합니다. 저렴한 기본 모델(Haiku급)을 사용하며, 에스컬레이션된 사고에 대해서만 더 깊은 추론을 원하는 배포를 위해 환경 변수 재정의(
AEGIS_MODEL)를 지원합니다.
5단계: 제어 평면(control plane)을 명시하는 봉쇄(Containment)
"추가 조사 필요"로 끝나는 분류 판결은 데모에 불과합니다. Aegis는 판결을 구체적인 봉쇄 조치(containment actions)에 매핑하며, 모든 조치는 이를 수행할 실제 자동화 도구의 이름을 명시합니다.
actions.append(Action(
name="계정 비활성화 및 세션 취소",
target="Microsoft Graph (Entra ID)",
...
destructive=True 플래그는 매우 중요한 역할을 합니다. 모든 계정 비활성화(account-disable), 세션 취소(session-revoke), MFA 재설정(MFA-reset), 엔드포인트 격리(endpoint-isolation) 작업은 반드시 사람의 승인을 거쳐야 하며, 동반되는 PowerShell 스크립트(Invoke-EntraContainment.ps1)는 -Execute 옵션이 명시적으로 전달되지 않는 한 시뮬레이션 모드로 실행됩니다.
자동 격리(Auto-containment)는 신뢰를 얻는 데 시간이 걸리며, 마땅히 그래야 합니다. 전형적인 실패 사례는 잘못된 속성(attribute)을 기준으로 작업을 수행하는 것입니다. ISE와 같은 NAC 배포 환경에서의 ID 기반 격리(Quarantine-by-identity)는 해당 계정이 보유한 모든 세션을 기꺼이 종료시켜 버리며, 여기에는 아무도 인증 중이라는 사실을 기억하지 못했던 엔드포인트까지 포함됩니다. "침해된" 것으로 판단된 계정이 알고 보니 서비스 ID(service identity)인 경우, 이를 자동으로 비활성화하면 보통 최악의 시간에 해당 계정에 의존하는 모든 통합(integration) 서비스가 중단됩니다. Aegis는 이러한 종류의 실수를 방지하기 위한 작은 방어 기제를 플레이북(playbook) 계층에 직접 인코딩했습니다. Aegis가 경계 차단(perimeter blocks)을 권장할 때, 평판이 나쁜(reputationally-bad) IP로만 필터링하여, ID 연결(identity linkage)을 통해 사고(incident) 내로 올바르게 끌어들여진 공격자의 정당한 기업 외부 유출(corporate egress) 트래픽이 차단 목록(deny-list)에 등록되지 않도록 합니다.
에이전트를 구축하기 전에 제가 드리고 싶은 말씀
효과적이었던 부분:
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기