본문 바로가기
기술 공부/DevOps

Wazuh SIEM에서 Syslog 연동 실습 (1편) - 삽질부터 첫 성공까지

by soy-ul 2025. 12. 7.
반응형

안녕하세요! 😊
 
지난번에는 Wazuh SIEM 시스템을 실제로 구축해보았고, 
이번에는 실제 애플리케이션 환경을 이해하기 위해 직접 KMS(Key Management System) 로그를 Wazuh에 연동해보기로 했습니다. 단순히 파일만 읽으면 되겠지 싶었는데... 6시간의 삽질 끝에 겨우 성공했습니다. 😅
긴 시간 투자한 만큼, 이번 글은 단순한 설정 가이드가 아니라 SIEM의 핵심 개념을 이해하고 실제로 부딪힌 문제들을 해결한 과정을 담아보겠습니다.
 


🔹 SIEM의 로그 처리 파이프라인

본격적인 실습 전에, Wazuh가 로그를 어떻게 처리하는지 정리하고 가보겠습니다.
 

전체 파이프라인

[1] 로그 파일 생성
    KMS → /var/log/remote/HA1.log

[2] Agent 수집 (Syslog 서버)
    log_format: syslog로 설정
    ↓
[3] Manager 전송
    TCP 1514 포트
    ↓
[4] archives.log 저장 (Wazuh Manager 서버)
    ⚠️ 모든 로그가 여기 저장됨 (Rule 무관)
    ↓
[5] Decoder 처리
    로그 파싱 및 필드 추출
    ↓
[6] Rule 매칭
    조건 확인 및 Alert 생성
    ↓
[7] alerts.log 저장
    ⚠️ Rule에 매칭된 것만 저장됨
    ↓
[8] Filebeat 전송
    ↓
[9] OpenSearch 인덱싱
    ↓
[10] Dashboard 표시

 

여기서 핵심은 4단계와 7단계의 차이라고 생각합니다.

archives.log vs alerts.log

처음 겪은 혼란

"archives.log에 로그가 쌓이는데 왜 대시보드에 안 보이지?"
→ archives.log는 Filebeat가 읽지 않음
[참고] Filebeat란 - 로그 데이터를 전달하고 중앙 집중화하기 위한 경량 전달자 역할을 함

"Rule을 만들었는데 왜 alerts.log에 안 보이지?"
→ <decoded_as> 방식으로는 작동 안 함 (나중에 발견)

"wazuh-logtest에서는 성공하는데 왜 실제로는 안 되지?"

정리

archives.log 모든 원본 로그 로그 수집 여부 확인, 디버깅
alerts.log Rule 매칭된 Alert만 실제 분석, 대시보드 표시

 
디버깅 순서:

1. archives.log 확인 → 로그 수집 OK?
2. wazuh-logtest → Decoder/Rule 작동 OK?
3. alerts.log 확인 → Alert 생성 OK?
4. 대시보드 확인 → 인덱싱 OK?

 

archives.log - 모든 로그의 원본 저장소

tail -f /var/ossec/logs/archives/archives.log | grep HA1.log

출력:
2025 Nov 27 03:09:22 (cent9) any->/var/log/remote/HA1.log 2025-11-27T12:09:21+09:00 HA1 {"category":"access","level":"info",...}

 
특징:

  • Agent에서 수집된 모든 로그가 원본 그대로 저장
  • Rule 매칭 여부와 무관하게 무조건 기록
  • 로그 수집이 정상적으로 되고 있는지 확인하는 용도
  • 형식: 날짜 시간 (호스트) 위치-> 파일경로 원본로그

 
언제 사용하나?

  • "Agent가 파일을 제대로 읽고 있나?" 확인 가능
  • "Manager가 로그를 받고 있나?" 확인 가능
  • Rule 작성 전 로그 형식 파악 가능

 

alerts.log - Rule에 매칭된 로그만

grep HA1.log /var/ossec/logs/alerts/alerts.log

# 처음엔 로그 내용이 증적되지 않음

특징:

  • Rule에 매칭된 이벤트만 기록
  • ❌ Rule이 없으면 아무것도 기록 안 됨
  • 실제 보안 분석에 사용되는 Alert

언제 사용하나?

  • "Rule이 제대로 작동하나?" 확인
  • "Alert가 생성되고 있나?" 확인
  • 대시보드에 표시될 데이터 확인

🔹 1단계: 로그 수집 설정 - log_format 구성의 중요성

KMS 로그 형식 분석

먼저 연동할 로그 파일의 형식을 확인했습니다:

tail /var/log/remote/HA1.log

# 출력:
2025-11-27T12:09:21+09:00 HA1  {"category":"access","level":"info","event":"reqSymmkeySuccess","timestamp":"2025-11-27 12:09:21","message":"It requested the symmetric key.","meta":{"requestAgent":"SYLEE","remoteIp":"192.168.0.172"}}

 
형식 분석:

  1. 타임스탬프: 2025-11-27T12:09:21+09:00 (ISO 8601 + KST)
  2. 호스트명: HA1
  3. JSON 데이터: {"category":...}

로그 정보에 JSON 데이터가 있어 log_format을 json으로 구성하였습니다. 

 

첫 번째 시도: json 포맷

<!-- /var/ossec/etc/ossec.conf (Wazuh Manager 서버) -->
<localfile>
  <log_format>json</log_format>
  <location>/var/log/remote/HA1.log</location>
</localfile>

 

파일 수정 후 Agent 재시작:

systemctl restart wazuh-agent

 
 
결과 확인:

# Agent가 파일을 읽고 있는지 확인
lsof | grep HA1.log

# 결과: 아무것도 안 나옴! ❌


실패한 이유:

  • log_format: json은 순수 JSON 형식만 지원
  • 우리 로그는 타임스탬프 + 호스트명 + JSON 혼합 형식
  • Agent가 파싱 실패 → 파일을 읽지 않음

 

두 번째 시도: multi-line 포맷

<localfile>
  <log_format>multi-line:1</log_format>
  <location>/var/log/remote/HA1.log</location>
</localfile>

 

결과: 여전히 실패 ❌
 
실패한 이유:

  • multi-line은 여러 줄에 걸친 로그를 하나로 합치는 용도
  • 우리 로그는 한 줄이지만 형식이 복잡한 경우 -> 이것도 아님!

 

해결: syslog 포맷

공식 문서를 통해 아래 내용을 확인하였습니다 :

syslog format: 타임스탬프 + 호스트명 + 메시지 형식의 로그

 

<localfile>
  <log_format>syslog</log_format>
  <location>/var/log/remote/HA1.log</location>
</localfile>

 
 
결과 확인:

systemctl restart wazuh-agent
lsof | grep HA1.log

# 출력:
wazuh-age 1234  wazuh  10r  REG  8,2  2621440  /var/log/remote/HA1.log

 
드디어 파일을 읽기 시작!
 
archives.log도 확인:

# Wazuh Manager 서버에서
tail -f /var/ossec/logs/archives/archives.log | grep HA1.log

# 로그가 쌓이기 시작함!
2025 Nov 27 03:09:22 (cent9) any->/var/log/remote/HA1.log 2025-11-27T12:09:21+09:00 HA1  {"category":"access"...}

#cent9 -> syslog 서버 호스트명

 

배운 점: log_format 선택 기준

 
[참고] 형식log_format예시

순수 JSON json {"timestamp":"2025-11-27","level":"info"}
Syslog 형식 syslog Nov 27 12:00:00 host app: message
타임스탬프+JSON syslog 2025-11-27T12:00:00 host {"data":"value"}
⭐ 이번 syslog 연동 테스트 케이스
여러 줄 로그 multi-line:N Exception:\n at line 1\n at line 2

 
핵심: 타임스탬프나 호스트명이 앞에 있을 때 syslog 포맷을 사용할 것!


🔹 2단계: Decoder와 Rule 이해하기

로그가 수집되기 시작했으니, 이제 로그에 대한 Alert를 구성하고 싶었습니다. 
하지만 Alert를 생성하기 전에, DecoderRule이라는 생소한 개념을 먼저 이해해야 했습니다.

Decoder와 Rule, 차이점이 무엇일까?

처음에는 이 둘의 차이를 이해하는 게 헷갈렸습니다. 

[원본 로그] 
    ↓
[Decoder] ← "로그를 이해하는 규칙" (파싱/구조화)
    ↓
[Rule] ← "위협을 판단하는 규칙" (조건 검사/Alert 생성)

 

Decoder 

역할: 원시 데이터 로그를 "구조화"하는 것

원본 로그: "Failed password for admin from 192.168.1.100"

Decoder가 하는 일:
  → 이 로그는 SSH 로그인 실패야
  → 사용자는 "admin"이네
  → IP는 "192.168.1.100"이군
  → 액션은 "Failed password"구나

결과 (구조화된 데이터):
  - user: admin
  - srcip: 192.168.1.100
  - action: Failed password
원본 로그: "2025-11-27 12:00:00 user admin logged in from 192.168.1.100"

Decoder 처리 후:
  - timestamp: 2025-11-27 12:00:00
  - user: admin
  - action: logged in
  - srcip: 192.168.1.100

핵심: Decoder는 로그를 읽고, 분해만 합니다. 위협 판단은 하지 않습니다.

 

 

Rule 

역할: Decoder가 추출한 정보로 "위협 판단"

Decoder가 준 정보:
  - user: admin
  - srcip: 192.168.1.100
  - action: Failed password

Rule이 하는 일:
  → 만약 "Failed password"가 5분 내 5회 이상 발생하면
  → 이건 Brute Force 공격 시도야!
  → Alert 생성! (level 10, 긴급)

핵심: Rule은 조건을 검사하고 Alert를 생성합니다.

 

Decoder와 Rule을 분리하는 이유 

 
분리의 장점:
→ 하나의 Decoder로 여러 Rule 작성이 가능하다고 합니다.

Decoder (재사용 가능)
  - SSH 로그는 항상 같은 방식으로 파싱
  
Rule (다양한 시나리오)
  - Rule A: 로그인 실패 5회 → Brute Force
  - Rule B: root 계정 로그인 성공 → 의심스러운 활동
  - Rule C: 알려진 악성 IP → 즉시 차단

 

🔹 [중간 정리] Wazuh의 로그 처리 프로세스

[원본 로그]
    ↓
[Phase 1: Pre-decoding]
  → 기본 정보 추출 (타임스탬프, 호스트명)
    ↓
[Phase 2: Decoding]
  → Decoder 매칭 및 필드 추출
    ↓
[Phase 3: Rule Matching]
  → Rule 조건 확인 및 Alert 생성

wazuh-logtest - 실시간 테스트 도구

실습하면서 wazuh-logtest 를 많이 사용하였습니다. 
이 도구를 통해, 실제 로그를 Manager에 보내기 전에, 로컬에서 Decoder와 Rule을 테스트할 수 있습니다.
 
사용법:

# Wazuh Manager 서버에서
echo '2025-11-27T12:09:21+09:00 HA1  {"level":"error"}' | /var/ossec/bin/wazuh-logtest

# 출력:
**Phase 1: Completed pre-decoding.
	full event: '2025-11-27T12:09:21+09:00 HA1  {"level":"error"}'
	timestamp: '2025 Nov 27'
	hostname: 'HA1'

**Phase 2: Completed decoding.
	No decoder matched.

(Phase 3 없음 - Decoder가 없어서 Rule도 없음) **

 
이걸 보고 어떤 부분에서 처리가 잘못 되었을지 트러블슈팅이 바로 가능했습니다.
ex) "아, Decoder가 없구나!" 
 
wazuh-logtest의 장점:

  • ✅ 실제 로그 보내기 전에 미리 테스트
  • ✅ Phase별로 어디서 문제인지 바로 확인
  • ✅ Decoder 작성 → Rule 작성 → 즉시 검증 가능
  • ✅ 실수로 Manager 재시작 반복 안 해도 됨


실제 사용 예:

# Decoder 작성
vi /var/ossec/etc/decoders/local_decoder.xml

# 바로 테스트 (Manager 재시작 불필요!)
echo '테스트 로그' | /var/ossec/bin/wazuh-logtest

# Rule 작성
vi /var/ossec/etc/rules/local_rules.xml

# 바로 테스트
echo '테스트 로그' | /var/ossec/bin/wazuh-logtest

즉시 피드백을 받을 수 있다는 게 정말 편했습니다.
"No decoder matched"라는 메시지가 나왔습니다. 커스텀 Decoder가 필요하다는 뜻입니다.

 

Decoder 작성 - 정규표현식의 함정

처음에는 타임스탬프, 호스트명, JSON을 전부 파싱하려고 복잡한 정규표현식(Regex)을 작성했습니다.
정규표현식 자체도 생소한데, 여기서 또 문제가 발생했습니다.

 
<!-- 실패한 시도 -->
<decoder name="ha_kms">
  <prematch>^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d{2}:\d{2} HA\d+</prematch>
</decoder>

 
결과:

ERROR: Syntax error on regex

 

 

POSIX Regex vs Perl Regex    (생소한 부분)

알고 보니 Wazuh는 POSIX Regex를 사용합니다!
일반적으로 많이 쓰는 Perl Regex와는 문법이 다릅니다:
패턴Perl RegexPOSIX Regex (Wazuh)

숫자 \d [0-9] ⭐
공백 \s (공백 문자 직접) ⭐
+ 기호 + \+ (이스케이프 필요) ⭐

저에게는 정규표현식 구성하는것 자체도 어려운데, POSIX 문법까지 신경 써야 하는 부분이 정말 어려웠습니다. 😅
AI툴과 구글링을 하면서 패턴을 구성해보았지만 잘 되지 않았습니다.
다음번에 이 정규표현식에 대해서 별도로 공부하고, 블로그 글로 정리해볼 생각입니다. 
 
POSIX로 수정:

<decoder name="ha_kms">
  <prematch>[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\+[0-9]{2}:[0-9]{2} HA[0-9]\+</prematch>
</decoder>

결과: 문법 오류는 해결되었지만 Rule에서 제대로 작동하지 않음

 

결론: Decoder는 단순하게!

 
"정규표현식을 완벽하게 만들려고 하지 말자..."
복잡한 Regex는:

  • ❌ 작성하기 어려움
  • ❌ POSIX 문법 실수 가능성 높음
  • ❌ 유지보수 어려움
  • ❌ 오히려 매칭 실패 확률 높음

 
최종 Decoder (극도로 단순화):

<!-- /var/ossec/etc/decoders/local_decoder.xml (170 서버) -->
<decoder name="ha_kms">
    <prematch>HA1.log|HA2.log</prematch>
</decoder>

 
핵심:

  • Decoder는 로그를 식별할 수 있으면 충분
  • 파일명(HA1.log, HA2.log)만으로도 충분히 식별 가능
  • 복잡한 파싱은 오히려 오류 가능성만 높임 

 
검증:

echo '2025-11-27T12:09:21+09:00 HA1  {"level":"error"}' | /var/ossec/bin/wazuh-logtest

# 출력:
**Phase 2: Completed decoding.
	decoder: 'ha_kms'

✅ Decoder 매칭 성공!
 


🔹 최종 배운 점

1. archives.log vs alerts.log

  • archives.log = 모든 수집 로그 (Rule 무관)
  • alerts.log = Rule 매칭된 로그만
 
로그 수집 성공 ≠ Alert 생성

 
대시보드에 로그가 안 보일때 확인했어야 하는 부분들:

  1. archives.log 먼저 확인 (수집은 되나?)
  2. alerts.log 확인 (Alert는 생성되나?)
  3. Filebeat 확인 (전송은 되나?)

2. Decoder vs Rule

역할 로그 파싱 (이해/구조화) 위협 탐지 (조건/Alert)
입력 원본 로그 Decoder 결과
출력 구조화된 데이터 Alert
예시 user: admin 추출 admin 5회 실패 → Alert

3. log_format의 중요성

타임스탬프나 호스트명이 앞에 있으면 syslog!
시도포맷결과

1차 json ❌ 순수 JSON이 아니라서 실패
2차 multi-line:1 ❌ 한 줄 로그라서 실패
3차 syslog ✅ 성공!

4. Decoder는 단순하게

복잡한 정규표현식보다 최소한의 식별 패턴이 더 안정적입니다.

<!-- ❌ 복잡함 + POSIX 문법 어려움 -->
<prematch>[0-9]{4}-[0-9]{2}-[0-9]{2}T...</prematch>

<!-- ✅ 단순함 + 확실함 -->
<prematch>HA1.log|HA2.log</prematch>

5. wazuh-logtest를 통한 사전 검증

  • Phase별 즉시 확인
  • Manager 재시작 불필요
  • 실제 운영 환경 영향 없음
  • 개발 → 테스트 → 배포 사이클 단축

🔹 유용한 명령어 정리

로그 수집 확인

# archives.log에서 원본 로그 확인
tail -f /var/ossec/logs/archives/archives.log | grep "HA1.log\|HA2.log"

# Agent가 파일을 읽고 있는지 확인
lsof | grep HA1.log

Decoder 테스트

# Decoder 매칭 확인
echo '2025-11-27T12:10:00+09:00 HA1  {"level":"error"}' | /var/ossec/bin/wazuh-logtest

# 파일에서 읽어서 테스트
cat sample.log | /var/ossec/bin/wazuh-logtest

Wazuh (Manager/Agent) 서비스 재시작 & 상태 조회

# Wazuh Agent
systemctl restart wazuh-agent
systemctl status wazuh-agent

# Wazuh Manager
systemctl restart wazuh-manager
systemctl status wazuh-manager

🔹 마치며

이번 글에서는 SIEM의 로그 수집부터 Decoder까지를 다뤘습니다.
핵심 내용:

  1. archives.log vs alerts.log - 수집과 Alert는 다르다
  2. Decoder vs Rule - 파싱과 탐지는 분리되어 있다
  3. log_format - 형식에 맞는 설정이 중요하다
  4. wazuh-logtest - 즉시 테스트로 개발 속도 향상
  5. POSIX Regex - 생소하지만 단순하게  OK

Wazuh 시스템 구축 테스트를 진행하면서,
archives.log와 alerts.log의 차이를 이해한 것이 가장 중요한 것 같습니다. 실제로 테스트를 진행하며 "로그는 수집되는데 왜 대시보드에 안 보이지?"하면서 계속 헤맸습니다.
 
통합 SIEM 관점에서 분산된 로그들을 한곳에 모아 분석하는 시각이 열릴 수 있도록 계속 테스트를 진행해볼 예정입니다. 
다음 편에서는 Rule 작성부터 대시보드까지 - 완전한 파이프라인을 다뤄보겠습니다.
Decoder로 파싱한 로그를 실제 Alert로 만들고, Filebeat와 OpenSearch를 거쳐 대시보드에 표시하는 과정을 공유해보겠습니다. 

반응형