Triage 구축기: SigNoz를 Blue Team SOC로 변환하기 (그리고 내가 겪은 배포 악몽)
요약
OpenTelemetry와 SigNoz를 활용하여 사이버 공격을 추적하는 보안 운영 센터(SOC)인 'Triage'를 구축한 경험담입니다. Azure VM의 메모리 부족, Vercel 환경에서의 localhost 통신 문제, Supabase 환경 변수 설정 오류 등 실제 배포 과정에서 겪은 기술적 시행착오를 다룹니다.
핵심 포인트
- SigNoz와 OTel을 활용한 보안 모니터링 시스템 구축 가능성 확인
- 클라우드 인스턴스(Azure)의 RAM 용량에 따른 데이터베이스 실행 제약 주의
- Vercel과 같은 클라우드 환경에서는 localhost 대신 퍼블릭 URL 사용 필수
- Next.js 환경에서 보안 키 노출 방지를 위한 환경 변수 접두사 관리 중요
대부분의 사람들은 CPU 사용량을 모니터링하거나, 메모리 누수(memory leaks)를 찾거나, 왜 API 응답 시간이 200ms가 아닌 400ms가 걸리는지 파악하기 위해 OpenTelemetry와 SigNoz를 사용합니다. 하지만 Agents of SigNoz Hackathon (Track 3: Observe Anything Weird)을 위해, 저는 완전히 다른 것을 해보고 싶었습니다.
저는 하드웨어를 관찰하고 싶지 않았습니다. 저는 해커들을 관찰하고 싶었습니다.
그렇게 Triage가 탄생했습니다. Triage는 일반적인 애플리케이션 성능 대신 활발한 사이버 공격을 추적하는 OpenTelemetry 기반의 Blue Team SOC (Security Operations Center, 보안 운영 센터)입니다.
원래의 비전 vs 현실
이것을 구축하는 것은 서류상으로는 간단해 보였습니다. 나쁜 트래픽을 포착하고, 이를 OpenTelemetry span으로 감싸서 SigNoz로 보내고, 커스텀 대시보드에 표시하면 됩니다. 하지만 마감 기한 전에 이 괴물을 실제로 배포하는 것은 완전히 다른 이야기였습니다.
시간이 촉박한 상황에서 풀스택 Next.js 앱, Python 허니팟(honeypot), 그리고 OTel 파이프라인을 배포하려고 시도해 본 적이 있다면, 제가 어떤 종류의 패닉을 말하는지 정확히 알 것입니다. 무대 뒤에서 실제로 일어난 일은 다음과 같습니다.
1. Azure VM 및 Docker 충돌
저는 SigNoz 백엔드를 셀프 호스팅하기 위해 Azure 가상 머신(virtual machine)을 생성하는 것으로 시작했습니다. 저장소(repo)를 가져와서 docker compose up -d를 실행하자마자 서버가 완전히 멈추는 것을 목격했습니다. 알고 보니, 제 무료 티어 Azure 인스턴스(Standard_B2ats_v2)는 RAM이 1 GiB밖에 없었습니다. 1GB의 메모리로는 거대한 ClickHouse 데이터베이스와 전체 OTel collector를 즉시 충돌 없이 실행할 수 없습니다. 저는 빠르게 방향을 틀어 클라우드 엔드포인트에 의존해야 했습니다.
2. Vercel vs Localhost 함정
백엔드를 실행한 후, 다음 벽에 부딪혔습니다. Vercel Next.js 대시보드는 위협 시뮬레이션 API에서 계속 500 Internal Server Error를 던졌고, SigNoz 연결은 계속 OFFLINE(fetch failed)으로 표시되었습니다. 저는 로그를 뚫어지게 쳐다보며 정신이 나갈 지경이었는데, 마침내 깨달았습니다. 제 Vercel 환경 변수(environment variables)의 SIGNOZ_API_URL이 http://localhost:8080으로 설정되어 있었고, 제 Python 스크립트는 localhost:4318에서 OTel을 찾고 있었던 것입니다.
참고 사항 (그리고 다른 모든 분들께): Vercel은 클라우드 서버입니다. 이 서버는 사용자의 로컬 Kali Linux 머신이나 Azure VM이 localhost에서 무엇을 하고 있는지 전혀 알지 못합니다. 저는 로컬 엔드포인트를 퍼블릭 인터넷으로 터널링하기 위해 Ngrok을 사용하거나, 아니면 모든 것을 엄격하게 퍼블릭 클라우드 URL로 지정해야만 Vercel이 백엔드와 실제로 통신할 수 있었습니다.
3. Supabase 키 지옥 (The Supabase Keys Nightmare)
대시보드에 위협 로그를 영구 저장하기 위해 저는 Supabase에 연결했습니다. 하지만 데이터베이스에는 아무것도 기록되지 않았고 UI는 'UNCONFIGURED' 상태에 멈춰 있었습니다.
알고 보니 제가 마스터 데이터베이스 키를 공개 변수처럼 잘못 취급했던 것입니다. Next.js에서는 비밀 키 앞에 NEXT_PUBLIC_을 접두사로 붙이면 브라우저에 노출됩니다. 하지만 제 API 라우트는 데이터를 안전하게 삽입하기 위해 정확히 SUPABASE_SERVICE_ROLE_KEY라는 문자열만을 찾고 있었습니다. 단 하나의 접두사 불일치가 전체 흐름을 망가뜨렸습니다. 제가 접두사를 제거하고, 순수한 서비스 키를 Vercel 설정에 전달한 다음 재배포 버튼을 누르자, 데이터베이스가 마침내 연결되었고 트레이스가 흘러나오기 시작했습니다.
우리가 구축한 기능들
배포 과정의 혼란에도 불구하고, 최종 시스템은 완벽하게 작동합니다. Triage가 실제로 하는 일은 다음과 같습니다:
AI 기반 위협 분석 (Groq & Llama-3.1)
일반적인 APM(Application Performance Monitoring)이 403 오류를 감지하면, 단순히 그래프에 일반적인 급증을 기록할 뿐입니다. 하지만 Triage는 SQL 인젝션이나 유출된 API 키를 가로채면, 원시 페이로드(raw payload)를 포착하여 즉시 Groq으로 전송합니다. LLM은 공격 벡터에 대한 깔끔한 3문장 요약을 생성하고, 이를 OpenTelemetry 트레이스에 직접 첨부합니다.
Python TCP Honeypot 함정
저는 웹 트래픽을 감시하는 것 이상을 원했습니다. 저는 포트 2222(SSH 모방)와 63790(Redis 모방)에서 리스닝하는, honeypot 역할을 하는 asyncio Python 스크립트를 작성했습니다. 자동화된 봇이나 Nmap 같은 도구가 제 서버에 대해 포트 스캔을 실행할 때, 이 honeypot이 IP를 포착하고, 사용자 정의 OTel 트레이스를 생성하며, 이를 포트 4318의 OTLP HTTP를 통해 컬렉터로 전송합니다.
SRE Sidekick (Auto-Ban)
우리는 능동적 방어 메커니즘 (active defense mechanism)을 구축했습니다. 시스템이 60초 이내에 동일한 IP로부터 5번의 공격을 감지하면, 자가 치유 프로토콜 (self-healing protocol)이 트리거됩니다. 이 과정에서 sre.auto_ban.triggered 스팬 (span)을 생성하고, 해당 공격자에 대해 즉각적으로 방화벽 차단을 강제합니다.
Cyberpunk SOC Command Center
프론트엔드 전체를 Next.js 16으로 구축했습니다. 이 시스템은 실시간 텔레메트리 트레이스 (telemetry traces)를 가져와 실시간 위협 통계를 보여주며, "레드 팀 시뮬레이터 (Red Team Simulator)" 기능을 갖추고 있습니다. 심사위원과 사용자는 브라우저에서 클릭 한 번으로 SQL 인젝션 (SQL injections)이나 데이터 유출을 안전하게 시뮬레이션할 수 있으며, 텔레메트리 데이터가 실시간으로 채워지는 것을 확인할 수 있습니다.
내가 실제로 SigNoz를 사용한 방법
여기서부터 재미있어집니다. 보안 계층을 위해 표준 HTTP 자동 계측 (auto-instrumentation)을 전혀 사용하지 않았습니다. 대신 블루 팀 (Blue Team)에 특화된 커스텀 OpenTelemetry 스팬 (spans)을 직접 구축했습니다.
표준 경로 (routes)를 추적하는 대신, 공격자의 발자취 (adversary's footprint)를 매핑했습니다. 제가 SigNoz 컬렉터 (collector)로 전송한 내용은 정확히 다음과 같습니다:
- 커스텀 스팬 (Custom Spans): 웹 익스플로잇 (web exploit)이 포착되었을 때는
security.trap과 같은 커스텀 스팬 이름을 생성했고, TCP 프로브 (probes)에 대해서는honeypot.port_scan을 생성했습니다. - 보안 속성 (Security Attributes): 이러한 스팬 내부에
security.severity = 'CRITICAL',security.threat_type = 'SQL_INJECTION', 그리고security.source_ip와 같은 속성 (attributes)을 주입했습니다. - AI 메트릭 (AI Metrics): Groq에 의해 분석된 모든 페이로드 (payload)에 대해, 트레이스에는
llm.latency,llm.model, 그리고threat.goal이 포함되었습니다.
이렇게 함으로써, SigNoz 쿼리 빌더 (Query Builder)를 열어 간단한 쿼리를 실행하는 것만으로 전체 인프라 전반에 걸친 모든 심각한 SQL 인젝션 시도를 실시간으로 매핑하여 확인할 수 있었습니다.
마치며
이번 해커톤은 저를 한계까지 몰아붙였습니다. 클라우드 네트워킹 규칙과 싸우고, Next.js 서버 충돌을 디버깅하며, OpenTelemetry가 SIEM처럼 작동하도록 강제하는 과정 사이에서, 저는 몇 달 동안 배운 것보다 더 많은 것을 단 며칠 만에 배웠습니다.
SigNoz는 믿기지 않을 정도로 유연하다는 것을 증명했습니다. 단순히 업타임 (uptime)을 추적하기 위한 도구가 아닙니다. 텔레메트리 (telemetry)를 올바르게 구조화한다면, 그 어떤 것이든 관찰할 수 있습니다. 심지어 아주 기이한 것들까지도 말이죠.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기