본문 바로가기
서버구축 (WEB,DB)

리눅스 호스트 Bash 기반 경량 보안 모니터링 프레임워크

by 날으는물고기 2025. 9. 1.

리눅스 호스트 Bash 기반 경량 보안 모니터링 프레임워크

728x90

목표와 범위

  1. 실시간 위협 가시성: 파일/프로세스/네트워크/사용자 이벤트 수집 및 이상 탐지
  2. 즉각 대응 자동화: 프로세스 차단, 파일 격리, IP 봉쇄, 알림 발송
  3. 증거 보존: 포렌식 로그·해시·타임라인 확보
  4. 운영 편의: 단일 스크립트(또는 소규모 서비스)·시스템 서비스·대시보드/API 제공
  5. 연동성: SIEM/메시징/티켓 시스템으로 표준 JSON 전송

개념 아키텍처

  1. 데이터 수집
    • 커널 이벤트: eBPF/bpftrace 또는 Auditd
    • 파일 변경: inotify/fanotify
    • 네트워크: ss/nftables conntrack, 간이 허니팟
    • 사용자/권한: sudo/lastlog/wtmp, 그룹 변경
  2. 탐지 엔진
    • 룰 기반(YARA/정규식/화이트리스트) + 행위 기반(빈도·패턴·상태머신)
  3. 대응(Containment)
    • 프로세스 종료/격리, 파일 격리, IP 차단(ipset/nft), 서비스 재기동
  4. 로깅·저장
    • JSON Lines(로컬), 회전/압축, 무결성 해시
  5. API·대시보드
    • 읽기 전용 REST, 요약/검색/다운로드
  6. 연동
    • SIEM 수집기(Filebeat/Vector), Slack/Webhook, 티켓 시스템
  7. 운영 제어
    • 설정파일(.conf), allow/deny 목록, 모듈 on/off, 성능 튜닝

기술 스택 선택 가이드

  • 필수: Bash 4+, jq, inotify-tools, coreutils, openssl
  • 선택: bcc/bpftrace(커널≥4.9 권장), yara, python3(경량 API), nftables/ipset
  • 대안: 커널 제약 시 Auditd 중심 설계 → 행위 탐지는 범위 축소, 파일·프로세스 상관분석 강화
300x250

디렉터리 구조(예시)

/opt/hostsec/
 ├─ bin/                # 실행 스크립트
 ├─ rules/              # yara / regex / 정책
 ├─ conf/               # 설정(환경, 허용목록, 성능튜닝)
 ├─ quarantine/         # 격리 파일(해시, 메타)
 ├─ logs/               # jsonl, rotate 대상
 ├─ tmp/
 └─ api/                # (선택) 간이 REST

설정 파일 예시(conf/agent.conf)

MONITOR_NETWORK=true
MONITOR_PROCESSES=true
MONITOR_FILES=true
ENABLE_EBPF=true          ; 또는 ENABLE_AUDITD=true
ENABLE_YARA=true
ENABLE_HONEYPOT=true

API_ENABLE=true
API_BIND=127.0.0.1
API_PORT=8080

LOG_DIR=/opt/hostsec/logs
QUARANTINE_DIR=/opt/hostsec/quarantine
EXCLUDE_PATHS=("/var/lib/docker" "/snap")
WHITELIST_PROCESSES=("sshd" "systemd" "dockerd")
HONEYPOT_PORTS=("2222" "8080" "23")

WEBHOOK_URL=""
SIEM_SHIP=udp://log-collector.local:514

PERFORMANCE_MODE=false
PARALLEL_JOBS=2
MAX_FIND_DEPTH=3
SCAN_TIMEOUT=180

최소 동작 MVP 스크립트 조각

1) 공통 로거/알림

log() { printf '%s %s\n' "$(date -Is)" "$*" >> "$LOG_DIR/agent.log"; }

alert() { # ALERT JSON 한 줄 출력
  jq -nc --arg sev "$1" --arg msg "$2" --arg host "$(hostname)" '
    {ts: now|todateiso8601, host:$host, severity:$sev, message:$msg}' \
  | tee -a "$LOG_DIR/alerts.jsonl"
}

notify_webhook() {
  [ -z "$WEBHOOK_URL" ] && return 0
  curl -s -X POST -H 'Content-Type: application/json' \
    --data @- "$WEBHOOK_URL" <<<'{"text":"['"$(hostname)"'] '"$1"'"}' >/dev/null
}

2) 파일 변경 감시 + YARA 스캔(간이)

watch_and_scan() {
  local WATCH_DIR="/var/www/html"
  inotifywait -m -e create,modify --format '%w%f' "$WATCH_DIR" \
  | while read -r f; do
      [[ "$f" =~ \.php$|\.jsp$|\.sh$ ]] || continue
      yara -r rules/webshell.yar "$f" >/tmp/yara.out 2>/dev/null
      if [ ${PIPESTATUS[0]} -eq 0 ]; then
        alert "high" "YARA hit on $f"
        quarantine_file "$f"
        notify_webhook "YARA hit on $f (quarantined)"
      fi
    done
}

3) 격리/차단

quarantine_file() {
  local f="$1" base sha dst
  base="$(basename "$f")"
  sha="$(sha256sum "$f" | awk '{print $1}')"
  dst="$QUARANTINE_DIR/$base.$sha"
  mkdir -p "$QUARANTINE_DIR"
  mv -f "$f" "$dst"
  printf '%s\t%s\t%s\n' "$(date -Is)" "$f" "$sha" >> "$QUARANTINE_DIR/index.tsv"
}

block_ip_nft() { # nftables 사전 준비: set 생성
  local ip="$1"
  nft add element inet filter bad_ips { $ip } 2>/dev/null \
   && alert "medium" "Blocked $ip via nft set"
}

4) 프로세스/실행 추적(eBPF → 대안 Auditd)

  • eBPF(bpftrace) 예 (커널≥4.9, root):
bpftrace -e 'tracepoint:sched:sched_process_exec { printf("%s|%d|%s\n", comm, pid, args->filename); }' \
  | awk -F'|' '{print strftime("%FT%TZ"),$1,$2,$3}' \
  >> "$LOG_DIR/exec_events.log"
  • Auditd 대안: -w /usr/bin -p x -k execmon 규칙 + ausearch/auparse로 후처리

5) 간이 허니팟(파이썬, 2222/TCP)

# /opt/hostsec/bin/honeypot.py
import socket, json, time
HOST, PORT = "0.0.0.0", 2222
with socket.socket() as s:
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind((HOST, PORT)); s.listen(50)
    while True:
        c, a = s.accept()
        with c:
            c.sendall(b"SSH-2.0-OpenSSH_8.2p1\r\n")
            payload = c.recv(128, socket.MSG_DONTWAIT).decode("utf-8","ignore")
            evt = {"ts": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
                   "src": a[0], "dst_port": PORT, "banner":"ssh-like", "data": payload}
            with open("/opt/hostsec/logs/honeypot.jsonl","a") as f: f.write(json.dumps(evt)+"\n")

6) 경량 REST API(읽기 전용)

# /opt/hostsec/api/app.py
from flask import Flask, jsonify
app = Flask(__name__)
@app.get("/alerts")
def alerts():
    return jsonify([line for line in open("/opt/hostsec/logs/alerts.jsonl")][-200:])

룰 설계와 오탐( FP ) 관리

  1. 레이어 설계
    • 파일 패턴(YARA)프로세스/네트워크 행위상관분석(시간·경로·UID)
  2. 화이트리스트 우선
    • 프로세스명, 경로, 서명/해시, 내부 IP/도메인
  3. 버저닝·리뷰
    • rules/ 디렉터리 Git 관리(리뷰+테스트), 변경시 파일럿 5% → 점진 확대
  4. 측정지표
    • FP율, 규칙 커버리지(자산군/업무군), 룰 업데이트 성공률

YARA 예시(단순 패턴)

rule Php_Webshell_Eval_Base64 {
  meta: severity = "high"
  strings: $a = /eval\s*\(\s*base64_decode\s*\(/ nocase
  condition: 1 of ($a)
}

위협 인텔(TI)·IP 차단 자동화(개념)

  1. 시간별(예: 6h) 공개 TI 피드 받아 CSV/IP 목록 갱신
  2. ipset/nft set에 추가 후 input 체인에서 참조
  3. 신뢰등급·첫 탐지 시각·만료시각 메타데이터로 자동 만료
nft add set inet filter bad_ips { type ipv4_addr; timeout 1d; }
nft add rule inet filter input ip saddr @bad_ips drop
# 갱신 스크립트에서: nft add element inet filter bad_ips { 198.51.100.10 timeout 6h }

대응 자동화 Runbook(요약)

  1. 심각도 매핑: high(즉시 격리/차단) · medium(감시+승인 후 차단) · low(관찰)
  2. 즉시 조치
    • 파일: quarantine_file, 해시/메타 기록
    • 프로세스: kill -9 <pid>, 서비스 안전 재기동
    • 네트워크: block_ip_nft <ip>
  3. 사후 처리
    • 패치/비밀번호 초기화/키 교체, 로그 타임라인 정리, 재발 방지 룰 보강
  4. 예외 승인
    • Change Ticket 기반 허용(만료시각 포함), 룰·화이트리스트 동기화

보안·신뢰성 설계 포인트

  • 최소권한: root 필요한 모듈만 분리 실행, 나머지는 비루트
  • Capability/격리: AmbientCapabilities= 최소화, API는 localhost 바인드 + mTLS/토큰
  • 서플라이체인: 해시 검증, 내부 미러, shellcheck·정적분석, 서명 배포
  • 무결성: 로그 JSONL에 체인 해시 추가(이전 라인 해시 포함)
  • 설정 보호: chmod 600 conf/*, 민감 키 분리(.env.d/)

배포·서비스화

1) systemd 유닛(예시)

# /etc/systemd/system/hostsec.service
[Unit]
Description=Host Security Agent
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/opt/hostsec
ExecStart=/opt/hostsec/bin/agent.sh run
Restart=always
RestartSec=5
# 경량 보호
NoNewPrivileges=true
ProtectSystem=full
PrivateTmp=true
ReadWritePaths=/opt/hostsec /var/log
AmbientCapabilities=CAP_SYS_ADMIN CAP_NET_ADMIN

[Install]
WantedBy=multi-user.target

2) 로그 수집기(Filebeat 예시)

filebeat.inputs:
  - type: log
    paths:
      - /opt/hostsec/logs/alerts.jsonl
      - /opt/hostsec/logs/honeypot.jsonl
    json.add_error_key: true
    processors:
      - decode_json_fields:
          fields: ["message"]
          process_array: true
          max_depth: 2
output.logstash:
  hosts: ["siem-collector.local:5044"]

관측성·대시보드·지표

  • 탐지: alerts.count, high/medium/low, MTTD, 재발율
  • 행위: exec 이벤트, 허니팟 히트, 차단 건수
  • 품질: FP율, 룰 커버리지, 업데이트 성공률
  • 성능: CPU/메모리/로그 증가량, 스캔 소요시간 p90

성능·안정화 팁

  • 경로 제외(EXCLUDE_PATHS)·깊이 제한(MAX_FIND_DEPTH)·동시성(PARALLEL_JOBS) 조정
  • 스캔/알림 레이트리밋(초당 N건)·백오프 재시도
  • 고부하 시간대(배치/백업)에는 감시 민감도 하향 또는 휴지시간 설정

멀티테넌시·호스팅 환경 운영(서비스 프로바이더용)

  1. 고객 격리: 계정·그룹·cgroup·네임스페이스·chroot/컨테이너 분리
  2. 정책 템플릿: 웹/DB/배치/도구서버 등 프로파일별 룰팩
  3. 감사 체계: 고객 데이터 접근 로그 별도 보관, 대시보드 고객 단위 필터
  4. 헌팅/수사: 허니팟을 고객망과 분리된 보안 세그먼트에 배치

PoC 체크리스트

  1. 커널/권한/네트워크 요구조건 충족(eBPF 또는 Auditd)
  2. 파일·프로세스·네트워크 3대 축 이벤트 수집 정상
  3. 웹셸·리버스셸·코인마이너 샘플에 대한 탐지≥95%, FP≤2%
  4. 고부하 시 CPU≤10%, RSS≤80MB, 로그 회전 정상
  5. 알림→티켓 연계, 롤백/비상중지 스크립트 검증

실무에 바로 쓰는 스니펫 모음

1) 메인 실행기(요약형)

#!/usr/bin/env bash
set -Eeuo pipefail
. conf/agent.conf

init() {
  mkdir -p "$LOG_DIR" "$QUARANTINE_DIR"
  log "agent start on $(hostname)"
  # nft set 사전 준비
  nft list set inet filter bad_ips >/dev/null 2>&1 || {
    nft add table inet filter
    nft add chain inet filter input { type filter hook input priority 0; }
    nft add set inet filter bad_ips { type ipv4_addr; }
    nft add rule inet filter input ip saddr @bad_ips drop
  }
}

main() {
  init
  $MONITOR_FILES    && watch_and_scan &
  $ENABLE_HONEYPOT  && /usr/bin/python3 bin/honeypot.py &
  $MONITOR_PROCESSES && bpftrace_exec &   # 또는 auditd 파서
  $API_ENABLE       && python3 api/app.py &
  wait -n           # 한 워커 종료 시 전체 재시작
}
main "$@"

2) exec 이벤트(bpftrace) 워커

bpftrace_exec() {
  command -v bpftrace >/dev/null || { log "bpftrace missing"; return; }
  bpftrace -e 'tracepoint:sched:sched_process_exec { printf("%s|%d|%s\n", comm, pid, args->filename); }' \
   | while IFS='|' read -r comm pid file; do
       case "$file" in
         */curl|*/wget) alert "medium" "Net tool exec: $comm($pid) -> $file";;
       esac
     done >> "$LOG_DIR/exec_events.log"
}

운영 수칙

  1. 테스트→파일럿(5~10%)→전면 단계적 롤아웃
  2. 룰 변경은 티켓 필수, 만료일·소유자 지정
  3. API 외부 노출 금지, 원격 필요 시 mTLS·IP 제한
  4. 정기 점검: FP 리뷰, 성능 리포트, TI 품질 평가
  5. 비상절차: systemctl stop hostsec + 차단규칙 롤백 스크립트

마무리

  • 위 구조는 작고 단단한 구성으로 시작해 환경에 맞게 확장(ML기반 스코어링, 중앙 정책 서버, 고급 대시보드)하기 좋습니다.
  • 핵심은 레이어드 수집→룰·행위 상관분석→신속 대응→증거 보존의 사이클을 자동화하고, FP 관리와 운영지표로 지속 개선하는 것입니다.
  • 필요하시면 통합 설치 스크립트, Auditd 전환 설계, 프로메테우스 지표 노출까지 이어지는 확장안도 바로 정리해드리겠습니다.
728x90
그리드형(광고전용)

댓글