개요 — 무엇을 하나
자동 차단(Auto-block) 은 InfraGuard 가 공격 IP 를 사람 개입 없이 탐지 → 심사 → 차단하는 백그라운드 파이프라인입니다. 화면(페이지)이 아니라 수집기 · 스케줄러 · 커널 ipset 이 협력하는 흐름이며, 이 문서는 그 전체 구조를 설명합니다.
파이프라인은 두 개의 독립 차단 경로가 하나의 집행 지점(ipset)으로 수렴합니다.
| 경로 | 실행 주체 | 기록 대상 | 단위 | 원천 |
|---|---|---|---|---|
| ① 수집기 자동 차단 | 각 호스트의 Node 수집기(srct_tx·kts_tx·eve_ingest) |
blacklist_info |
/24 (C클래스) | Suricata L7 · Kitsune ML |
| ② 스케줄러 자동 차단 | InfraGuard 앱(infr:auto-block → AutoBlockService) |
infr_block |
/32 (개별) 또는 /24 | suricata_alert_ct · suricata_tls_ct |
| ③ 집행(공통) | infr_sync_black.mjs(호스트 cron) |
커널 ipset blacklist |
hash:net | ①+② 합집합 |
두 경로는 모두 차단하기 직전에 화이트리스트·무죄 추정 검증을 거칩니다. 확실한 침해만 남기고, 오탐 후보는 면책합니다. 경로 ②(스케줄러)는 기본값이 OFF 이며 관리자가 켜야 동작합니다.
언제 쓰나
- 봇넷·스캐너·무차별 탐색이 상시 유입되어 수동 차단으로는 감당이 안 될 때 자동 방어를 켭니다.
- Detections ▸ JA3 분석 에서 지문 로테이션 봇넷이 보일 때, 이를 자동으로 잡도록 임계를 조정합니다.
- Threats 에서 특정 심각도(빨강/주황) IDS 경보가 반복되는 소스를 자동으로 막고 싶을 때.
- Blocklist & Reputation 에 자동으로 쌓이는 차단 근거를 검토하고, 오차단을 Whitelist 로 면책할 때.
화면 구성
자동 차단은 전용 화면이 없습니다. 제어·관측 지점은 다음과 같습니다.
- 설정 — 운영 정책 ▸ 보안 설정 탭 ▸ 자동 차단 카드(마스터 스위치·방식·범위·트리거·무죄 추정).
- 결과 관측 — Blocklist & Reputation(수집기 /24 + 스케줄러 /32 차단 목록·근거·해제).
- 면책 관측 — Whitelist(수동/무죄 자동 면책 IP·CIDR, 만료 개념).
- 트리거 원천 — Threats(IDS 심각도), Detections(JA3 로테이션).
사용법
1. 경로 ② 스케줄러 자동 차단 — 켜고 튜닝하기
기본값은 OFF 입니다(autoblock_on=0). 운영 정책 ▸ 보안 설정에서 마스터 스위치를 켠 뒤 정책을 조정합니다.
차단 방식(mode)
| 값 | 의미 |
|---|---|
global(기본) |
한 서버에서 발견된 침해를 전 함대에 광역 적용(server_index=0). |
per_server |
공격당한 대상 서버에만 적용 — 공격 대상 dest_ip 를 infr_server_index 로 해석해 지정. |
차단 범위(scope)
| 값 | 스케줄러 기록 | 설명 |
|---|---|---|
balanced(권장·기본) |
개별 /32 | IDS 프로그램은 /24, InfraGuard 는 개별 /32 — 이미 /24 로 덮인 IP 는 sync_black 이 중복 제외. |
broad |
/24 | C클래스 전체 차단 — 넓게 막지만 무고한 이웃 IP 포함 위험. |
granular |
개별 /32 | IP 하나씩만 — 정밀하지만 로테이션 대응이 느림. |
트리거(OR — 하나라도 충족하면 차단 후보)
① IDS 룰셋 심각도 suricata_alert_ct
WHERE alert_ts >= NOW() - INTERVAL {window_min} MINUTE
AND severity <= {sev_max} -- crit=1, warn=2 (Suricata: 1=심각 … 3=낮음)
GROUP BY src_ip HAVING COUNT(*) >= {sev_count}
② JA3 로테이션 봇넷 suricata_tls_ct
WHERE event_ts >= NOW() - INTERVAL {ja3_window_min} MINUTE
AND ja3_hash IS NOT NULL
GROUP BY src_ip HAVING COUNT(DISTINCT ja3_hash) >= {ja3_rotation}
심각도 트리거의 시각 컬럼은
alert_ts이고 JA3 트리거는event_ts입니다(테이블마다 다름). 임계 튜닝 시 각 창(window)이 어느 컬럼을 기준으로 하는지 유의하세요.
정책 기본값 (OpsPolicy::autoBlock())
| 설정 키 | 기본값 | 클램프 | 의미 |
|---|---|---|---|
autoblock_on |
0 |
— | 마스터 스위치(1=on). 기본 OFF |
autoblock_mode |
global |
global|per_server | 차단 방식 |
autoblock_scope |
balanced |
broad|granular|balanced | 차단 범위 |
autoblock_interval_min |
10 |
≥1 | 스케줄러 실효 순회 주기(분) |
autoblock_window_min |
10 |
≥1 | 심각도 평가 창(분) |
autoblock_sev_on |
1 |
— | 트리거① 활성 |
autoblock_severity |
crit |
crit|warn | crit=sev≤1, warn=sev≤2 |
autoblock_sev_count |
1 |
≥1 | 창 내 최소 경보 건수 |
autoblock_ja3_on |
1 |
— | 트리거② 활성 |
autoblock_ja3_rotation |
50 |
≥2 | distinct JA3 지문 ≥ N |
autoblock_ja3_window_min |
360 |
≥1 | JA3 평가 창(분·6시간) |
autoblock_innocent_on |
1 |
— | 무죄 추정 veto 활성 |
autoblock_innocent_days |
30 |
≥1 | 무죄 자동 화이트리스트 기간(일) |
autoblock_reputation_cap |
25 |
0–200 | 스윕당 평판 조회 상한 |
JA3 로테이션 임계 튜닝(실측): 실환경의 JA3 로테이션 오펜더는 대개 /32 세션당 서로 다른 JA3 약 32개 수준(데이터센터·클라우드 봇, GREASE 없이 안정적)입니다. 따라서 기본
ja3_rotation=50은 아무것도 잡지 못합니다. 실제로 발화시키려면 15–20 정도로 낮추세요.--dry로 후보 수를 먼저 확인하는 것을 권장합니다.
2. 후보 심사 순서 (AutoBlockService::run)
수집된 후보 IP 마다 아래 게이트를 순서대로 통과해야 실제 차단됩니다.
- 자기망/내부 제외 —
SecurityScope::isInternal($ip)이면 skip(skipped_internal). 등록 인스턴스 IP(/24 접두 + 정확 IP)와 운영 정책internal_networks화이트리스트를 통합한 판정입니다. 쿼리 단계에서도excludePrefixes()를NOT LIKE로 선제 배제합니다. - 화이트리스트 면책 —
infr_whitelist에 /32 또는 /24 로 활성·미만료 등록이 있으면 skip(skipped_wl). - 무죄 추정 veto — 하드 신호(심각도 트리거)가 없는 JA3 단독 후보만 대상.
reputation_cap한도 내에서 AbuseIPDB 평판을 조회해 완전 청정(악용점수 0 AND 신고 0 AND Tor 아님)이면 차단 대신infr_whitelist(source=auto)로innocent_days일 면책(innocent). 심각도 후보는 이 관문을 건너뛰고 즉시 차단합니다. - server_index 해석 —
global→[0],per_server→대상dest_ip를ServerIndexResolver::byIp로 해석(없으면[0]). - 기록 —
InfrBlock::updateOrCreate([server_index, cidr], …)로infr_block에 upsert.source='schedule',is_active=true,reason='[InfraGuard Auto] …'(근거 note).
후보 수집(OR) → 내부 제외 → 화이트리스트 → (JA3단독) 무죄 veto → server_index → infr_block 기록
isSpotless()는 평판 조회가 실패·미설정·미해석이면 false(=신중하게 차단)로 판정합니다. 무죄 면책은 "확실히 결백할 때만" 적용되는 보수적 관문입니다.
3. 스케줄러 & 커맨드
infr:auto-block 은 데몬이 아니라 1회 평가 후 종료하는 단발 커맨드입니다. 스케줄러가 매분 tick 하되 실효 주기는 autoblock_interval_min 입니다.
# 게이트 확인(운영정책 OFF 면 즉시 no-op) 후 1회 평가·기록
php artisan infr:auto-block
# 기록 없이 후보만 집계(튜닝·검증용)
php artisan infr:auto-block --dry
# 운영 정책 게이트(on·주기)를 우회해 강제 1회 실행
php artisan infr:auto-block --force
# 차단이 없으면 출력 억제(스케줄용)
php artisan infr:auto-block --quiet-if-ok
스케줄 등록(routes/console.php):
Schedule::command('infr:auto-block --quiet-if-ok')
->everyMinute()
->withoutOverlapping(2)
->onOneServer()
->when($is_leader); // 리더 게이팅 — 다중 서버에서 1곳만
게이트 로직:
autoblock_on=0→ 커맨드가 즉시건너뜀(기본 OFF, 안전).- 마지막 실행 후
interval_min미도달 → skip. --force·--dry는 게이트 우회.
출력 예:
infr:auto-block — 후보 12(sev 3·ja3 9) · 차단 7 · 화이트skip 1 · 내부skip 2 · 무죄면책 2
4. 경로 ① 수집기 자동 차단 (Node)
각 호스트의 Node 수집기가 Suricata 이벤트를 소비해 직접 blacklist_info 에 /24 로 차단합니다. 스케줄러(경로 ②)와 독립이며 항상 동작합니다.
| 수집기 | 계층 | 탐지 |
|---|---|---|
infr_eve_ingest.cjs |
인제스트 | Suricata eve.json → suricata_http_ct·suricata_tls_ct·suricata_flow_ct·suricata_alert_ct 적재 |
infr_srct_tx.cjs |
시그니처/휴리스틱 | Suricata L7 종합 → 5카테고리 스캐너/봇 탐지 → blacklist_info /24 |
infr_kts_tx.cjs |
Kitsune ML | conntrack + 오토인코더 이상탐지(anomaly_score) → blacklist_info /24 |
srct_tx 의 5가지 위협 카테고리:
(A) [HTTP] URL 스캐너 .env / .git / wp-login 등 스캐너 지문 URL
(B) [HTTP] 봇 User-Agent curl / python-requests / sqlmap 등 툴 지문
(C) [HTTP] 무차별 탐색 짧은 시간에 4xx 다수(경로 브루트포스)
(D) [TLS] JA3 지문 이상 다중 JA3 · SNI 부재 등 봇넷 지문
(E) [FLOW] TCP 플래그 이상 짧은 스캔 세션 다수(포트 스캔)
srct_tx 도 차단 직전 화이트리스트 필터 + 무죄 자동 면책을 수행합니다: E-only(짧은 스캔 단독) 후보만 AbuseIPDB 평판을 조회해, 신고 0·악용점수 0·Tor 아님 이면 30일 면책(infr_whitelist(source=auto))으로 등록하고 차단을 건너뜁니다. 하드 신호(A/A2/B/C/D)가 하나라도 있으면 즉시 차단합니다. 상수·임계는 규칙 임계 에서 관리합니다.
5. 경로 ③ 집행 — sync_black → ipset
infr_sync_black.mjs 가 각 호스트에서 주기 실행되어 두 목록을 커널 ipset blacklist 로 동기화합니다.
# 호스트별 server_index 로 실행(root 필요)
node infr_sync_black.mjs sv=4
# crontab (매 5분, flock 로 중복 방지)
*/5 * * * * /usr/bin/flock -n /var/run/sync_black.lock \
/usr/bin/node /root/server_monitor/infr_sync_black.mjs sv=4 \
>> /var/log/sync_black.log 2>&1
동작:
blacklist_info(/24) +infr_block(/32) 에서server_index IN (0, <sv>) AND is_active/is_use=1로드.- 균형 dedup — 부모 /24 가 이미 덮은 /32 는 건너뜀.
- 커널 ipset 을
hash:net으로 강제(다른 타입이면 재생성), 임시 셋에 로드 후 atomic swap(무중단). iptables -I INPUT -m set --match-set blacklist src -j DROP존재 보장(idempotent).- 안전장치 — 사설망(RFC1918)·loopback·자기망 접두(
HOME_NET_PREFIX)는 DB 에 실수로 들어와도 ipset 에 절대 로드하지 않음.
sync_black은 root 권한과 커널ipset/iptables가 필요하며, 대상 호스트에 사전에blacklistipset 이 존재해야 합니다:ipset create blacklist hash:net family inet hashsize 8192 maxelem 65536 iptables -I INPUT -m set --match-set blacklist src -j DROP
데이터 소스
모든 원천·기록 테이블은 legacy_glory 커넥션에 있습니다(수집기·집행 스크립트가 공유하는 DB).
| 테이블 | 커넥션 | 역할 | 단위 |
|---|---|---|---|
suricata_alert_ct |
legacy_glory | 심각도 트리거 원천(컬럼 alert_ts·severity·src_ip·dest_ip·signature) |
— |
suricata_tls_ct |
legacy_glory | JA3 로테이션 트리거 원천(컬럼 event_ts·ja3_hash·src_ip) |
— |
blacklist_info |
legacy_glory | 수집기 자동 차단 목록(IDS 프로그램·srct/kts) | /24 |
infr_block |
legacy_glory | InfraGuard 스케줄러 소유 차단 목록(마이그레이션 000751) | /32·/24 |
infr_whitelist |
legacy_glory | 차단 면책(수동·무죄 자동·seed) | /32·/24 |
infr_server_index |
기본(MAIN) | 희소·비순차 server_index ↔ alias/instance 룩업(000750) | — |
infr_block 스키마 (요약)
| 컬럼 | 타입 | 의미 |
|---|---|---|
server_index |
int | 0=전역 · else=infr_server_index 로 해석된 서버 |
cidr |
varchar(43) | 개별 IP(/32) 또는 정규화 /24 · UNIQUE(server_index,cidr) |
ip |
varchar(45) | 원 IP(표시) |
reason |
varchar(500) | 트리거 근거([InfraGuard Auto] sev1 x3 …) |
source |
varchar(16) | auto · manual · schedule |
is_active |
bool | sync_black 이 로드하는 활성 여부 |
expires_at |
datetime | NULL=영구 |
last_seen_at |
datetime | 마지막 재탐지(purge 판단) |
권한
자동 차단에는 사용자 대면 실행 UI 가 없습니다. 관련 권한 게이트는 다음과 같습니다(레벨: demo=1 · staff=5 · admin=10).
| 대상 | 필요 권한 |
|---|---|
| 자동 차단 정책 설정(운영 정책 ▸ 보안 설정) | 관리자(Administration, 레벨 5 이상 / admin) |
| 차단 결과 조회(Blocklist) | 보안 열람(staff, 레벨 2 이상) |
| 수동 차단/해제·Whitelist 쓰기 | staff(레벨 2 이상) + 감사 로그 |
스케줄러 실행(infr:auto-block) |
시스템(로그인 사용자 아님) — 리더 게이팅 |
스케줄러가 쓰는 자격증명은 하드코딩하지 않고
infr_collector·.env로 외부화됩니다.sync_black의 DB 크리덴셜·자기망 접두도 env 또는 Inventory ▸ Tools 매시업 치환으로 주입합니다(하드코딩 금지).
문제해결 · FAQ
켰는데 아무것도 차단되지 않습니다.
--dry로 후보 수를 확인하세요:php artisan infr:auto-block --dry.- JA3 임계가 너무 높을 가능성이 큽니다(기본 50). 실제 오펜더는 ~32 수준이라 15–20 으로 낮추세요.
- 심각도 트리거:
autoblock_severity=crit은 sev≤1(빨강)만 잡습니다. 주황까지 포함하려면warn(sev≤2) 으로. - 후보가 전부
내부skip/화이트skip이면 운영 정책 내부망 화이트리스트 또는 Whitelist 를 점검하세요.
차단이 실제 방화벽에 반영되지 않습니다.
infr_block에는 기록됐지만sync_black이 안 돌면 ipset 에 반영되지 않습니다. 대상 호스트 cron 과sv=<server_index>인자,blacklistipset 존재를 확인하세요.balanced범위에서는 부모 /24 가 이미 덮은 /32 는 의도적으로 dedup 되어 별도 로드되지 않습니다(정상).
무고한 IP 가 차단됐습니다.
- Whitelist 에 /32 또는 /24 로 등록하면 다음 스윕부터 면책됩니다(기존
infr_block행은 Blocklist 에서 해제). - 무죄 자동 면책은 JA3 단독 후보에만 적용됩니다. 심각도 트리거로 잡힌 IP 는 평판과 무관하게 즉시 차단되므로, 수동 면책이 필요합니다.
per_server 인데 전역(server_index=0)으로 기록됩니다.
- 공격 대상
dest_ip가infr_server_index로 해석되지 않으면 안전하게[0]으로 폴백합니다. 수집기/인스턴스 IP 매핑을 확인하세요.
스케줄러가 여러 서버에서 중복 실행됩니다.
->onOneServer()->when($is_leader)리더 게이팅으로 1곳만 실행됩니다. 리더 락 상태를 관측 대시보드 에서 확인하세요.
관련 항목
- 운영 정책 — 자동 차단 마스터 스위치·트리거·범위 설정(보안 설정 탭)
- Blocklist & Reputation — 자동 차단 결과 목록·근거·해제
- Whitelist — 면책 IP/CIDR·무죄 자동 면책
- Detections ▸ JA3 — JA3 로테이션 트리거 원천
- Threats — IDS 심각도 트리거 원천
- IP 평판(AbuseIPDB) — 무죄 추정 veto 의 평판 조회

