개요 — 무엇을 하나
Security ▸ Firewall(/security/firewall)는 우리 서버 함대가 열어 둔 포트를 한 장의 노출 지도로 그려 줍니다. 각 오픈 포트를 위험도(치명/주의/표준/미상)로 채색하고, 등록된 서비스인지(관리됨) 아니면 뜻밖의 열림(미등록)인지를 구분해 "무엇이 왜 밖에서 보이는가"를 즉시 파악하게 합니다.
세 원천을 교차(join)합니다:
infr_instance_firewall (인스턴스별 방화벽 룰 = 오픈 포트/서비스)
× infr_instance (호스트 메타 — 공인 IP·중요도·환경·상태)
× infr_service (등록된 논리 서비스 — instance_id·port)
→ FirewallLore 로 위험 분류 → 노출 지도
- 읽기 전용 관제 화면입니다. 방화벽 룰 자체의 편집·수집은 Assets ▸ Instances ▸ [fw]가 담당하고, 이 화면은 그 원장을 함대 관점으로 재구성만 합니다.
- 원천이 전부 신규
infr_테이블이라legacy_glory(Suricata·Kitsune 등)에 붙지 않습니다 — Eloquent 직접 조회,SecurityRepository불필요. - 30초 폴링(라이브). 위험 분류의 정본 로직은
App\Support\FirewallLore, 해설 텍스트는resources/lang/{ko,en}/fwlore.php.
역할 경계: 이 화면은 물리 포트의 오픈/노출(공격 표면)을 봅니다. *논리 서비스의 도달성(헬스체크)*은 Service ▸ Catalog 소관입니다. 같은 포트라도 관점이 다릅니다.
언제 쓰나
- 함대 전체의 공격 표면을 감사하고 싶을 때 — "지금 밖에서 어떤 포트가 보이나?"
- 뜻밖의 열림을 찾을 때 — 등록 서비스가 아닌데 열려 있는 DB·캐시·원격관리 포트(미등록 노출).
- 최악의 노출을 우선 처리할 때 — 공인 IP 를 가진 호스트에 열린 치명(crit) 포트.
- 특정 포트가 어느 호스트들에서 열려 있는지 한 번에 보고 싶을 때(포트별 뷰).
- 한 머신이 무엇을 얼마나 열고 있는지 점검할 때(호스트별 뷰).
- 포트의 위험을 왜 위험한지·어떻게 좁히는지 학습하려 할 때(포트 위험 해설 모달).
화면 구성
헤더(HERO)
제목·부제(함대가 열어둔 포트 — 공격 표면 노출 지도), 최종 수집 시각 스탬프, LIVE / PAUSED 토글(30s 폴링 on/off), 전체화면 버튼.
빈 상태(Empty)
방화벽 룰이 하나도 없으면 온보딩 안내가 뜹니다 — Instances 로 이동 버튼이 /asset/instances로 보냅니다. Instances ▸ [fw]에서 firewall-cmd 결과를 import 하거나 원격 에뮬레이트로 오픈 포트를 수집하면 지도가 그려집니다.
KPI 밴드(5종)
| KPI | 라벨 | 정의 | 산출 |
|---|---|---|---|
| ports | 오픈 포트 | 전 호스트의 열림 항목 총계 | 분류된 룰 개수 |
| hosts | 노출 호스트 | 포트를 하나라도 연 머신 수 | distinct instance_id |
| crit | 위험 노출 | 치명 등급으로 분류된 포트 수 | risk == 'crit' |
| unmanaged | 미등록 노출 | 등록 서비스가 아니면서 위험이 ok가 아닌 포트 |
!managed && risk != 'ok' |
| public_crit | 공인·치명 | 공인 IP 를 가진 호스트에 열린 치명 포트 | crit && public |
공인·치명(public_crit)은 의도적인 중복 집계입니다. 공인 IP 위의 치명 포트는 이미
위험 노출에, (등록 서비스가 아니라면)미등록 노출에도 잡히지만, 이 조합(공인 × 치명)이 함대에서 가장 나쁜 단일 노출이므로 별도 KPI 로 한 번 더 표면화해 놓친 것이 없도록 합니다. 이 타일이 0 이 아니면 최우선으로 손봐야 합니다.
노출 위험 분포 밴드
crit·warn·ok·unknown 4색 스택 바로 위험도 구성비를 보여줍니다. 아래 레전드는 클릭형 필터 — 한 위험 등급을 누르면 그 등급만 남기고(다시 누르면 해제) 뷰가 좁아집니다. 밴드 옆 coverage(예: 7 / 12 호스트 수집됨)는 방화벽 룰이 수집된 호스트 수 대비 전체 인스턴스 수입니다.
툴바 · 필터
- 뷰 토글: 포트별 / 호스트별.
- 프로토콜: 전체 / TCP / UDP.
- 위험도: 전체 / 치명 / 주의 / 표준 / 미상.
- 미등록만 체크박스: 등록 서비스가 아닌 포트만.
- 검색: 포트·서비스·호스트(별칭 포함) 문자열 매칭.
포트별 뷰
포트 카드 그리드. 카드마다 포트/프로토콜·서비스 라벨·위험 배지, 이 포트를 여는 호스트 칩(최대 8개 + +N), 하단에 호스트 수·공인 노출 수·분류. 카드 클릭 → 포트 상세 + 위험 해설 모달. 정렬은 위험도 → 호스트 수 → 포트 번호.
호스트별 뷰
호스트 카드 그리드. 카드마다 호스트명·별칭·환경·중요도, 공인 여부 배지, 그 머신이 여는 포트 칩(위험도 채색, 등록 서비스면 check-decagram 표식), 하단에 위험 등급별 카운트·총 포트 수. 포트 칩 클릭 → 같은 상세 모달. 정렬은 crit 수 → warn 수 → 포트 수.
포트 상세 + 위험 해설 모달
포트/프로토콜·서비스명·위험 배지·분류, 그리고 fwlore 해설 3단:
- 무엇인가(what) — 이 포트가 어떤 서비스인지.
- 왜 위험한가(why) — 외부 노출 시 어떤 공격으로 이어지는지.
- 권장 조치(best) — 노출을 좁히는 방법.
아래에 이 포트를 여는 호스트 목록(환경·중요도·존·공인/내부·등록/미등록 배지)과 Instances ▸ [fw] 에서 관리 링크.
사용법
- 상단 LIVE 가 켜져 있으면 30초마다 자동 갱신됩니다. 조사 중 값이 흔들리는 게 싫으면 PAUSED 로 멈춥니다.
- 공인·치명 KPI부터 확인합니다 — 0 이 아니면 위험도 레전드에서
치명을 눌러 포트별 뷰로 좁힌 뒤, 공인 칩(지구 아이콘)이 붙은 호스트를 먼저 처리합니다. - 미등록만 체크로 "뜻밖의 열림"을 골라냅니다. 등록 서비스가 아닌 DB(3306/5432/27017)·캐시(6379/11211)·Docker(2375)·원격관리(23/3389/VNC)가 여기 걸리면 즉시 좁혀야 합니다.
- 포트 카드를 눌러 해설 모달에서 why/best 를 읽고,
Instances ▸ [fw] 에서 관리로 넘어가 룰을 좁히거나 서비스로 등록합니다. - 실제로 포트를 닫거나 룰을 편집하는 것은 이 화면이 아니라 대상 호스트의 방화벽 + Instances ▸ [fw] 에서 합니다. 이 화면은 지도이자 감사 도구입니다.
위험 분류 규약(FirewallLore)
포트 문자열은 단일(8080) 또는 범위(6081-6100)를 받습니다. 범위는 시작 포트 기준으로 well-known 매핑을 찾습니다.
| risk | 순위 | 의미 | 예시 |
|---|---|---|---|
| crit | 3 | 외부 노출 시 즉시 위험 — 데이터스토어·원격관리·파일공유·컨테이너 | MySQL 3306, Redis 6379, RDP 3389, SMB 445, Docker 2375, k8s-api 6443 |
| warn | 2 | 주의 — 관리·레거시·비표준 | SSH 22, SMTP 25, 8080/8443, SNMP 161, Grafana 3000 |
| ok | 1 | 표준 공개 서비스 | HTTP 80, HTTPS 443, DNS 53, NTP 123, WireGuard 51820 |
| unknown | 0 | 매핑 없음 — 검토 필요 | 카탈로그에 없는 포트/대역 |
- **VNC 대역(5900–5910)**은 개별 등록 대신 범위로 처리하며
remote_admin · crit. - 넓은 포트 대역(예
6081-6100)이 unknown 이면 표면적이 크므로 최소 warn 으로 승격합니다. - 매핑 없는 포트는 서비스 라벨이 있으면 표시에 쓰되 위험도는
unknown, 라벨이 없으면 프런트가미상 서비스로 렌더합니다.
관리됨(managed) 판정
등록 서비스 맵은 infr_service.instance_id : port로 만듭니다. 인스턴스에 그 포트의 등록 서비스가 있으면 관리됨(check-decagram 표식, managed_name). 범위 포트는 시작 포트(low) 기준으로 매칭합니다. 등록 서비스가 없으면 미등록 — 위험이 ok가 아니면 미등록 노출 KPI 에 잡힙니다.
데이터 소스
| 테이블 / 소스 | 역할 | 채우는 주체 |
|---|---|---|
infr_instance_firewall |
인스턴스별 오픈 포트/서비스 룰(원장) | Assets ▸ Instances ▸ [fw] — 수동 CRUD / firewall-cmd --list-all 원시 텍스트 import / scripts/infr_firewall_probe.cjs JSON import |
infr_instance |
호스트 메타 — name·alias·env·criticality·status·ip_public |
Assets ▸ Instances |
infr_service |
등록 논리 서비스(instance_id·port·name·kind) → 관리됨 판정 |
Service ▸ Catalog |
App\Support\FirewallLore |
포트 → {key,label,category,risk,icon} 분류 SOT(로케일 독립) | 코드 |
resources/lang/{ko,en}/fwlore.php |
위험 등급·분류별 what/why/best 해설 | lang pack |
infr_instance_firewall 룰 형태(UNIQUE instance_id, zone, proto, port):
{
"zone": "public",
"ports": [
{ "port": "22", "proto": "tcp", "service": "ssh" },
{ "port": "443", "proto": "tcp", "service": "https" },
{ "port": "3306", "proto": "tcp", "service": "mysql" },
{ "port": "6081-6100", "proto": "tcp", "service": "" }
]
}
원시 firewall-cmd --list-all 텍스트도 [fw] import 가 파싱합니다(존 헤더 → services: 매핑 → ports: 직접):
public (active)
services: http https ssh
ports: 8080/tcp 6081-6100/tcp 3306/tcp
빌드된 대시보드는 서버에서 30초 캐시(infr:sec:firewall:dashboard)됩니다. 룰이 하나도 없으면 빈 페이로드(empty=true)로 온보딩 상태를 그립니다.
권한
- 화면 조회:
/security/*전체가infr.level:2미들웨어로 묶여 있습니다 → staff(5) 이상만(내부적으로user_level >= 2). demo(1)는 보안 정보 접근 자체가 차단됩니다. - 이 화면은 쓰기 없음(순수 조회). 방화벽 룰 편집·import 는 Assets ▸ Instances ▸ [fw]에서 하며 level ≥ 2 + 감사 로그로 게이팅됩니다.
- 레벨 체계: demo=1 · staff=5 · admin=10(일부 영역은
infr.level:N으로 추가 게이팅). 자세한 것은 RBAC 레벨.
문제해결 · FAQ
빈 화면(“아직 방화벽 데이터가 없습니다”)만 보여요.
infr_instance_firewall에 룰이 없다는 뜻입니다. Assets ▸ Instances ▸ [fw]에서 firewall-cmd --list-all 결과를 붙여넣어 import 하거나, 원격 에뮬레이트로 오픈 포트를 수집하세요.
포트가 미상 서비스로 나와요.
FirewallLore 카탈로그에 없는 포트입니다(위험 unknown). 정상 서비스면 Service ▸ Catalog에 서비스로 등록하거나 [fw] 룰의 service·note에 라벨을 달아 두라. 불필요하면 닫습니다.
등록된 서비스인데 미등록으로 표시돼요.
관리됨 판정은 같은 인스턴스에 infr_service가 그 포트로 있어야 성립합니다. 서비스가 다른 호스트에 있거나 포트가 다르면 매칭되지 않습니다. 범위 포트는 시작 포트 기준으로만 매칭합니다.
위험 노출은 있는데 공인·치명은 0 이에요.
치명 포트가 열린 호스트들이 모두 공인 IP(ip_public) 없이 내부 전용이라는 뜻입니다 — 노출 반경이 작아 상대적으로 안전합니다. 그래도 내부 위협·측면 이동을 고려해 좁히는 것이 좋습니다.
값이 실시간이 아니에요. LIVE 가 PAUSED 이거나 탭이 백그라운드일 수 있습니다. 대시보드는 서버에서 30초 캐시되므로 [fw]에서 룰을 바꾼 직후 최대 30초는 이전 값이 보일 수 있습니다.
포트를 여기서 닫을 수 있나요? 아니다. 이 화면은 읽기 전용 지도입니다. 실제 차단은 대상 호스트의 방화벽에서, 룰 원장 갱신은 Instances ▸ [fw]에서 합니다.
관련 항목
- Assets ▸ Instances ▸ [fw] — 방화벽 룰 원장 · 이 지도의 쓰기 쪽(수집·편집·import)
- 원격 에뮬레이트 · tlx.php 프로브로 오픈 포트 수집
- Service ▸ Catalog · 등록 서비스(관리됨 판정) · 논리 도달성
- Assets ▸ Instances · 인스턴스 메타(공인 IP·중요도)
- Security ▸ Overview · 보안 관제 랜딩(방어 퍼널)
- Administration ▸ 운영 정책 · FirewallLore 포트 카탈로그를 “감시 포트” 선택에 재사용
