> For the complete documentation index, see [llms.txt](https://h08.gitbook.io/undefined/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://h08.gitbook.io/undefined/custom-rule-and-active-response/4./4.2.md).

# 4.2 보안 관제 알림 시스템

## 1. 개요

* Wazuh에서 탐지된 보안 위협을 보안 담당자가 즉시 확인하고 신속하게 대응할 수 있도록 협업 툴인 Slack과 연동함

***

## 2. 환경 설정

### 2.1 Slack 설정

* 채널 생성: 알림을 수신할 전용 채널(예: `#Wazuh`)을 생성
* Webhook URL 발급
  * Slack App Directory에서 Incoming Webhooks 앱 추가
  * 생성된 채널을 지정하고 Webhook URL을 발급

### 2.2 Manager

/var/ossec/etc/ossec.conf/

```xml
<ossec_config>
  <integration>
    <name>slack</name>
    <hook_url>https://hooks.slack.com/services/T000/B000/XXXX</hook_url> <alert_format>json</alert_format>
  </integration>
</ossec_config>
```

***

## 3. 스크립트

/var/ossec/integrations/

```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import json
import os
import sys
try:
    import requests
except Exception:
    print("No module 'requests' found. Install with: pip install requests")
    sys.exit(1)

# 설정 및 경로
pwd = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
LOG_FILE = f'{pwd}/logs/integrations.log'
ALERT_INDEX = 1
WEBHOOK_INDEX = 3

def main(args):
    if len(args) < 4:
        log(f"ERROR: Wrong arguments: {args}")
        sys.exit(2)
    process_args(args)

def log(msg):
    with open(LOG_FILE, 'a') as f:
        f.write(msg + "\n")

def process_args(args):
    alert_file = args[ALERT_INDEX]
    webhook = args[WEBHOOK_INDEX]
    
    alert = load_json(alert_file)
    msg = generate_msg(alert)
    send_msg(msg, webhook)

def load_json(path):
    try:
        with open(path) as f:
            return json.load(f)
    except Exception as e:
        log(f"ERROR: Cannot load JSON: {e}")
        sys.exit(7)

def generate_msg(alert):
    # 알림 레벨에 따른 색상 지정
    level = alert['rule']['level']
    if level <= 4:
        color = 'good'    # Low risk
    elif level <= 7:
        color = 'warning' # Medium risk
    else:
        color = 'danger'  # High risk

    # 메시지 본문 구성
    pre = alert['rule'].get('description', 'N/A')
    agent = alert.get('agent', {})
    agent_val = f"({agent.get('id','?')}) – {agent.get('name','?')}"
    rule_id = f"{alert['rule'].get('id','?')} (Level {level})"
    
    attachment = {
        "color": color,
        "pretext": "WAZUH Alert",
        "title": pre,
        "fields": [
            {"title": "Agent", "value": agent_val, "short": True},
            {"title": "Rule ID", "value": rule_id, "short": True}
        ],
        "ts": alert.get('id')
    }
    return json.dumps({"attachments": [attachment]})

def send_msg(msg, url):
    headers = {'Content-Type': 'application/json'}
    try:
        resp = requests.post(url, data=msg, headers=headers, timeout=10)
        log(f"Slack response: {resp.status_code}")
    except Exception as e:
        log(f"Request failed: {e}")

if __name__ == "__main__":
    main(sys.argv)
```

1. JSON 파싱&#x20;

* Wazuh Manager가 경보 발생 시 전달하는 알림 파일의 내용을 읽어 Python JSON 객체로 변환

2. 데이터 정제 및 필터링&#x20;

* 원본 로그의 방대한 데이터 중 보안 담당자에게 필요한 핵심 정보(Rule ID, Description, Agent Name, Level)만 추출
* 설정에 따라 Level 7 이상의 고위험 경보만 전송하도록 커스터마이징 가능

3. 메시지 포맷팅 (Formatting)

* Slack API 포맷(`attachments`)에 맞춰 메시지를 재구성
* 경보 심각도(Level)에 따라 색상(Green, Orange, Red)을 다르게 표시하여 시인성을 높임
  * Level 1\~4 : 초록
  * Level 5\~7 : 주황
  * Level 8\~ : 빨강

***

## 4. 작동원리

1. 경보 발생

* Wazuh Manager가 Agent로부터 수집한 로그를 분석하여 탐지 룰을 매칭
* 설정된 임계치 이상의 중요 보안 이벤트(예: 웹쉘 업로드, Level 12)가 발생하면 경보(Alert)가 생성

2. 통합 스크립트 실행

* `ossec.conf`의 통합 설정에 따라 Wazuh Manager는 스크립트 실행
* 이때 발생한 경보의 상세 내용이 담긴 JSON 파일의 경로가 스크립트의 인자로 전달

3. 데이터 파싱 및 포맷팅

* 실행된 Python 스크립트는 전달받은 파일을 읽어 JSON 객체로 변환
* 심각도(Level)를 분석하여 메시지의 색상을 결정

4. Webhook 전송

* 재구성된 메시지 데이터를 담아 설정된 Slack Incoming Webhook URL로 HTTP POST 요청을 전송

5. 알림 수신

* Slack 서버가 요청을 수신하고, 지정된 채널(#Wazuh)에 알림을 띄움

<figure><img src="https://3550524140-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMQqlpxjtA7kpPBgieO9x%2Fuploads%2FMHGv0GHASy92yqP22hOk%2Fimage.png?alt=media&amp;token=23484522-d34f-48de-8e8f-646680f1f19a" alt=""><figcaption></figcaption></figure>
