개요 — 무엇을 하나
보안 문제 해결(Security ▸ Problem Resolution) 은 보안 인시던트·침해 대응을 하나의 케이스 보드로 관리하는 워크플로우 콘솔입니다. 케이스는 5단계 파이프라인을 따라 흐릅니다.
등록(open) → 분석(investigating) → 원인판명(cause_identified) → 해결(resolved) → 종료(closed)
각 케이스는 500 리포트 구조(직접 원인 / 배경 원인 / 해결 / 재발 방지)와 감사 가능한 타임라인을 갖습니다. 이 화면은 서비스 ▸ 문제 해결 컨트롤러를 미러한 것으로, 동일한 infr_incident 테이블을 공유하되 area='security' 로 필터링해 서비스 인시던트와 분리합니다.
케이스가 이 보드에 들어오는 경로는 두 가지입니다.
- 수동 등록 — 운영자가 직접 케이스를 만듭니다. 선택 가능한 소스:
수동(manual)·관련기관(agency)·격리(quarantine). - 보안 진단 승격 — 보안 진단의
fail + crit항목이 시스템에 의해 자동으로 케이스(source=detection)로 승격됩니다. 운영자가 손으로 만들 수 없는 시스템 전용 소스입니다.
이 콘솔은 원격 crontab이나 방화벽을 직접 조작하지 않습니다. 사람이 수행하는 대응 절차를 기록·추적하는 워크플로우 도구입니다. 실제 차단·격리 조작은 차단 목록·자동 차단에서 수행합니다.
언제 쓰나
- IDS/AI 탐지(위협, 탐지·JA3)에서 확인된 침해 의심 사건을 정식 케이스로 승격해 조사·해결 이력을 남길 때.
- CERT·수사기관 등 관련기관(agency) 협조 요청·침해사고 신고 건을 추적할 때.
- 감염 호스트를 격리(quarantine) 한 뒤 복구·재투입까지 상태를 관리할 때.
- 보안 진단 점검에서
fail+crit로 뜬 하드닝/루트킷 위험을 자동 케이스로 받아 후속 조치를 배정할 때. - 사후에 MTTR·누적 다운타임을 집계하거나, 직접·배경 원인과 재발 방지 대책을 문서화할 때.
화면 구성
KPI 스트립
| KPI | 정의 |
|---|---|
| 전체(total) | area='security' 케이스 총수 |
| 미해결(active) | open + investigating + cause_identified 상태 합 |
| 해결(resolved) | resolved + closed 상태 합 |
| 평균 해결(MTTR) | occurred_at·resolved_at 둘 다 있는 케이스의 평균 소요(분) |
| 누적 다운타임 | 모든 케이스 downtime_min 합 |
| 업타임 목표 | OpsPolicy::slaDefaults()['uptime_target'] |
케이스 보드
케이스는 다음 우선순위로 정렬됩니다.
- 상태 랭크 —
open→investigating→cause_identified→resolved→closed - 심각도 랭크 —
crit→warn→info - 최신순 —
id내림차순
카드에는 제목, 심각도, 상태, 소스 배지, 연결된 프로젝트/서비스, 발생 시각, 다운타임, 이벤트 수가 표시됩니다.
상세 모달
케이스를 열면 두 영역으로 나뉩니다.
- 리포트 — 요약·직접 원인·배경 원인·해결·재발 방지 필드.
- 타임라인 —
infr_incident_event이력(등록·노트·상태 변경 등, 시간순).
상단의 상태 이동(파이프라인) 을 클릭하면 스텝 전이 대화상자가 뜨고, 각 단계에서 "이 단계에서 할 일" 안내와 함께 해당 단계 리포트 필드를 갱신할 수 있습니다.
사용법
케이스 등록 (수동)
- 상단 [케이스 등록] 클릭.
- 제목(필수)·심각도·소스(
수동/관련기관/격리)를 입력. - 필요 시 프로젝트·서비스·URL·발생 일시·영향·다운타임(분)을 지정.
- [저장] — 신규 케이스는
status=open,area=security,detected_at=now()로 생성되고 타임라인에created이벤트가 기록됩니다.
소스에서
탐지 승격(detection)은 목록에 나오지 않습니다 — 시스템이 보안 진단에서만 자동 생성하는 전용 소스이기 때문입니다.
상태 전이 (파이프라인)
상세 모달의 파이프라인에서 목표 상태를 클릭하면 전이됩니다. 각 단계 권장 작업:
| 단계 | 이 단계에서 할 일 |
|---|---|
| 등록(open) | 접수 상태로 되돌림(분석 이전 단계) |
| 분석(investigating) | 증상 확인·영향 범위 파악·요약 정리 |
| 원인판명(cause_identified) | 직접 원인 + 배경(근본) 원인 규명·기록 |
| 해결(resolved) | 복구 방법 + 재발 방지 대책 기록 |
| 종료(closed) | 조치·재발 방지 반영 확인 후 케이스 종료 |
전이 규칙(서버):
resolved로 이동 시resolved_at이 비어 있으면now()로 채웁니다.closed로 이동 시 대화상자의 종료 일시 를 입력하면 그 값을, 비우면 기존 값이 없을 때now()로 채웁니다.- 상태가 실제 바뀌면 타임라인에
status_change(from→to) 이벤트를 남기고, 노트를 함께 입력하면note이벤트도 추가됩니다.
협업 노트
상세 모달에서 노트를 추가하면 타임라인에 kind=note 이벤트로 기록됩니다. 별도 노트 테이블 없이 infr_incident_event 로 통합되어 있습니다.
삭제
케이스를 삭제하면 연결된 infr_incident_event 이벤트가 함께 삭제되고 감사 로그에 기록됩니다. (진단 승격의 원본 스캔은 케이스와 독립이라 삭제되지 않습니다.)
진단 승격 케이스의 자동 해소
보안 진단이 프로브 결과를 접수할 때 DiagnosticsService::reconcileCases() 가 호스트별 케이스를 정합화합니다.
fail + critfinding →fingerprint기준으로 열린 케이스를 upsert(재발이면occurrence_count누적).- 이후 점검에서 해당 항목이 통과/사라짐 → 열려 있던 케이스를 자동 해소(
status=resolved,resolved_at,resolution=자동 해소 문구) 하고 타임라인에status_change이벤트를 남깁니다.
자동 해소는 진단 점검을 다시 통과했을 때만 발생합니다. 수동으로 만든 케이스(
manual/agency/quarantine)는 자동 해소 대상이 아니며, 운영자가 직접 파이프라인을 전이시켜야 합니다.
데이터 소스
테이블
| 테이블 | 역할 |
|---|---|
infr_incident |
케이스 본문(area='security' 필터). 상태·심각도·소스·500 리포트 필드·발생/해결/종료 시각·fingerprint·occurrence_count |
infr_incident_event |
케이스 타임라인(생성·노트·상태 변경 등) |
infr_project |
케이스 연결용 프로젝트 목록 |
infr_service |
케이스 연결용 서비스 목록 |
열거값
STATUSES = [open, investigating, cause_identified, resolved, closed]
SEVERITIES = [info, warn, crit]
SOURCES = [manual, pulse, alert, agency, quarantine, detection] # 전체
수동 등록 가능 소스 = [manual, agency, quarantine]
OPEN_STATUSES(디둡 대상) = [open, investigating, cause_identified]
AREAS = [service, security] # 공유 테이블 분리 축
리포트 필드 (500 구조)
| 필드 | 의미 |
|---|---|
summary |
증상·영향 요약 |
direct_cause |
직접적 원인 (예: mysql 연결 한도초과) |
root_cause |
배경적(근본) 원인 (예: 스크립트 연결 누수) |
resolution |
장애 중 적용한 복구 방법 |
action_taken |
향후 재발 방지 대책 |
downtime_min |
다운타임(분) — 누적 다운타임 KPI 원천 |
impact |
영향 범위 |
API 엔드포인트
| 메서드·경로 | 용도 |
|---|---|
GET /security/resolution |
보드 초기 렌더 |
GET /security/resolution/live |
폴링 갱신(케이스·KPI·타임스탬프) |
POST /security/resolution/save |
케이스 등록/수정 |
POST /security/resolution/transition |
상태 전이(+선택 노트·리포트 갱신) |
POST /security/resolution/note |
협업 노트 추가 |
POST /security/resolution/delete |
케이스 삭제 |
권한
- 조회: Security 그룹 전체가
infr.level:2미들웨어로 보호됩니다. 레벨 2 이상(staff=5 · admin=10)만 접근 가능하며 데모(1)는 차단됩니다. - 쓰기(save/transition/note/delete): 컨트롤러
canWrite()가 세션infr_user_level >= 2를 재확인합니다. 미달 시403(resolution.err.forbidden). - 감사: 모든 쓰기는
infr_audit_log에 기록됩니다 —sec.incident_create·sec.incident_update·sec.incident_transition·sec.incident_delete. 전이는{from,to}를, 저장은{title,severity}를 메타에 남깁니다. 자세한 내용은 감사 로그를 참고하세요.
문제해결 · FAQ
Q. 서비스 문제 해결 보드에 있던 케이스가 여기 안 보입니다.
두 보드는 같은 infr_incident 테이블을 공유하지만 area 로 분리됩니다. 이 화면은 area='security' 만 보여줍니다. 서비스 인시던트는 서비스 ▸ 문제 해결에서 확인하세요.
Q. 탐지 승격(detection) 소스로 케이스를 만들 수 없습니다.
정상입니다. detection 은 보안 진단이 fail+crit 항목에서만 자동 생성하는 시스템 전용 소스입니다. 수동 등록에서는 manual·agency·quarantine 만 선택할 수 있습니다.
Q. 자동 승격 케이스가 저절로 해결됨으로 바뀌었습니다.
재점검에서 해당 진단 항목이 통과하면 reconcileCases() 가 열린 케이스를 자동 해소합니다. resolution 에 자동 해소 문구가 채워지고 타임라인에 상태 변경 이벤트가 남습니다.
Q. MTTR이 비어 있습니다.
MTTR은 occurred_at 과 resolved_at 이 둘 다 있는 케이스에서만 계산됩니다. 발생 일시를 입력하지 않았거나 아직 해결되지 않은 케이스는 집계에서 제외됩니다.
Q. 종료 일시를 과거로 지정할 수 있나요?
예. 종료 전이 대화상자의 종료 일시 입력에 값을 넣으면 그대로 저장됩니다(발생 일시와 동일 인터페이스). 비우면 기존 값이 없을 때만 서버가 now() 로 채웁니다.
Q. 케이스를 삭제하면 진단 스캔도 지워지나요? 아니요. 승격 케이스와 원본 진단 스캔은 독립적입니다. 케이스 삭제는 연결된 타임라인 이벤트만 함께 제거합니다.
관련 항목
- 보안 진단 —
fail+crit항목을 이 보드로 자동 승격하는 소스. - 서비스 문제 해결 — 동일 워크플로우의 서비스(
area='service') 미러. - 보안 개요 — 위협→탐지→대응 방어 퍼널 서사.
- 위협 · 탐지·JA3 — 케이스로 승격할 침해 후보의 출처.
- 감사 로그 — 케이스 쓰기 작업의 영속 기록.
