Devin.KR

서비스와 방화벽 분리

130분 안팎

학습 목표

VM 콘솔을 확보한 뒤 실습망 출발지만 허용하는 방화벽 규칙을 적용하고 접속 결과를 비교합니다.

개념

서비스가 정상인데 클라이언트만 실패합니다

서버 콘솔의 /items 조회와 허용 클라이언트 조회는 성공하는데 다른 실습 출발지는 timeout이라고 가정합니다. 서비스 상태를 바꿔야 하는지 방화벽 정책을 확인해야 하는지 판단하려면 관측 위치를 나눠야 합니다. 이번 목표는 실행 계정·리스너·출발지 정책을 각각 확인하고 새 연결의 허용과 차단을 비교하는 것입니다. 정상 앱을 재설치하거나 모든 포트를 열기 전에 같은 대상에 대한 두 클라이언트의 원문을 확보합니다.

패킷 허용과 앱 실행은 별도 책임입니다

systemd의 active는 관리 상태이고 ss의 LISTEN은 소켓 상태이며 nftables의 규칙은 패킷 처리 조건입니다. active라고 실습망 주소에 리스너가 있다는 뜻은 아니고 규칙에 accept가 있다고 요청이 앱까지 도달했다는 뜻도 아닙니다. 다른 체인의 정책, 반환 경로, 서버 응답이 결과에 영향을 줍니다. 서버 콘솔·허용 클라이언트·차단 클라이언트의 비교표에 이 세 관측을 별도 열로 적습니다.

이번 실습은 nftables의 별도 inet bootcamp_access 테이블을 사용합니다. 기존 전체 규칙을 flush하지 않습니다. input 체인은 이 서버로 들어오는 패킷을 다루며 서버가 라우터로 전달하는 forward 체인과 목적이 다릅니다. inet 계열은 IPv4·IPv6를 함께 다룰 수 있지만 ip saddr의 조건은 IPv4입니다. IPv4 허용 규칙만 쓰고 IPv6의 같은 서비스 포트를 그대로 두면 의도한 출발지 제한과 실제 노출이 달라질 수 있습니다.

조건과 순서로 규칙을 읽습니다

먼저 loopback을 허용해 서버 내부 점검을 유지하고 established·related 상태를 허용합니다. 다음으로 실습 IPv4 출발지 192.168.56.0/24와 목적지 TCP 포트 22·18080을 함께 조건으로 둡니다. 뒤에서 같은 두 포트의 나머지 입력을 drop합니다. 주소 조건만 있으면 원하지 않은 포트까지 열 수 있고 포트 조건만 있으면 원하지 않은 출발지까지 열 수 있습니다. 허용 규칙과 나머지 차단 규칙의 범위를 함께 읽습니다.

이 테이블의 policy accept는 다른 서비스 포트를 전부 최소 권한으로 통제하는 구성이 아닙니다. 목표는 앞 프로젝트의 SSH·HTTP 두 포트의 새 연결을 실습망으로 제한하는 것입니다. 일반 서버의 전체 기본 차단 정책으로 소개하지 않습니다. ICMP와 IPv6 ICMP 허용은 진단과 제어 통신을 불필요하게 막지 않기 위한 실습 선택이며 더 좁은 운영 정책은 별도 요구 분석이 필요합니다. 대상 포트로 들어오는 새 IPv6 연결은 마지막 drop 규칙에 걸립니다.

established 허용은 기존 정상 흐름의 후속 패킷을 처리하지만 이미 성립한 비허용 출발지 연결도 유지할 수 있습니다. 그래서 정책 적용 전의 SSH 세션이 살아 있다는 사실을 새 접속 허용의 근거로 쓰지 않습니다. 차단 시험은 새 TCP 연결과 새 SSH 명령으로 수행합니다. 공유 접속 설정을 배제한 수집기는 별도 클라이언트 프로세스를 사용합니다. 기존 연결 보존과 신규 연결 제한이라는 서로 다른 결과를 기록해야 정책의 의도를 설명할 수 있습니다.

콘솔 복구 경로를 먼저 확보합니다

원격 SSH 하나만 의지한 채 SSH 포트 차단을 바꾸면 실수 후 같은 경로로 복구하기 어렵습니다. VM 관리 콘솔을 실제로 열고 일반 관리 로그인으로 명령을 실행할 수 있는지 확인합니다. 이전 설정 사본과 해당 파일의 소유권·모드를 보관합니다. 실습에서는 네트워크 NIC나 기본 경로를 내리지 않습니다. prepare.sh는 CONSOLE_READY=yes 확인을 요구하지만 이 문자열이 실제 콘솔 접근을 보증하지는 않으므로 학습자가 직접 접근 증거를 남깁니다.

nft -c -f access.nft는 적용하지 않고 규칙을 검사합니다. 문법 검사가 통과해도 원하는 출발지 주소가 실제 클라이언트 주소와 같은지는 알 수 없습니다. 먼저 ip route get 결과의 src와 NAT 유무를 확인합니다. 규칙을 적용한 뒤 nft list table로 실제 테이블을 다시 읽습니다. 다른 방화벽 관리자가 같은 호스트를 관리하면 추가 체인 때문에 accept 이후에도 차단될 수 있으므로 격리 VM의 정책 소유자를 먼저 정리합니다.

차단 클라이언트도 서버까지 경로가 있어야 합니다

차단 클라이언트는 192.168.57.20/24를 사용하며 실습 라우터를 통해 서버 망과 양방향 통신 경로를 갖습니다. NAT를 쓰면 서버가 본 출발지가 달라지므로 이번 비교에서는 사용하지 않습니다. 원래 경로가 없는 장비의 timeout을 방화벽 차단 성공으로 제출하면 실험이 잘못된 것입니다. 적용 전 두 클라이언트의 TCP 도달을 확인하고 적용 뒤 새 연결만 비교합니다. 차단 출발지는 게이트웨이와 서버 반환 경로까지 구성도에 적습니다.

drop 카운터의 증가를 차단 클라이언트 요청 시각과 연결합니다. 카운터는 그 규칙에 일치한 패킷 관측이며 HTTP 사용자 한 명이나 요청 수와 같은 단위가 아닙니다. 다른 트래픽이 섞인 상태의 증가만으로 특정 요청을 확정하지 않습니다. 격리 실습에서 전후 값과 시험 시각을 함께 남기고 필요하면 허가된 범위의 패킷 관측으로 좁힙니다. timeout 단독보다 카운터·경로·리스너·정상 클라이언트 비교가 원인 판단을 뒷받침합니다.

새 정책과 복원을 모두 검증합니다

허용 클라이언트는 HTTP 200과 기존 데이터 JSON, SSH의 bcops 출력을 제출합니다. 차단 클라이언트는 새 TCP·HTTP·SSH의 실패 원문을 제출합니다. 두 장비의 이름 해석이 같은 서버를 가리키는지도 확인합니다. 허용 클라이언트가 잘못된 키로 접속했을 때는 timeout이 아닌 publickey 오류가 나와야 인증 계층까지 도달한 비교가 됩니다. 이 네 가지 결과를 같은 실패 문자열로 뭉치지 않습니다.

미션 check.sh는 서버의 live 리스너·관리 상태·설치된 환경 파일과 두 클라이언트가 수집한 JSON을 검사합니다. JSON은 학습자가 수집한 증거이며 검증기가 독립적으로 원격 접속한 결과는 아닙니다. 보고서의 시각과 경로 src를 확인해 다른 출발지나 오래된 성공을 줄입니다. 이름 오타·리스너 없음·복구 후 응답의 설명 품질은 사람이 검토합니다. 자동 검사에서 통과했다는 사실과 모든 운영 위험이 검토됐다는 주장을 구분합니다.

앱이 자연 종료하면 restore.sh로 이전 앱·환경을 복원하고 본 모듈의 테이블만 삭제합니다. 다른 테이블을 지우지 않습니다. 다음 m04 기동에서 loopback /items의 상태·본문을 확인하고 복구 시각을 적습니다. 파일 복사 성공만으로 복구가 끝났다고 적지 않습니다. 로컬 allow 함수 실습은 허용 출발지·두 포트·상태·IPv6 경계의 논리만 검사합니다. 실제 규칙 작성 원리는 nftables 공식 위키와 더 읽기로 이어갑니다.

따라하기

판정에 사용할 작은 모델 실행

아래 코드는 제공된 고정 입력의 계산만 실행합니다. VM 관측 출력과 구분해 읽습니다.

from ipaddress import ip_address, ip_network
network = ip_network('192.168.56.0/24')
for source, port in [('192.168.56.20',22),('192.168.56.20',5432),('192.168.57.20',18080)]:
    print(source, port, ip_address(source) in network and port in (22,18080))

실행 결과

192.168.56.20 22 True
192.168.56.20 5432 False
192.168.57.20 18080 False

콘솔과 정책 검토

미션 ZIP 폴더에서 실행합니다. 콘솔 접근과 설정 사본을 확인하고 다른 방화벽 관리자의 존재를 검토합니다. 이 단계는 적용 성공이나 원격 접속 성공 출력이 아닙니다.

sudo nft list ruleset
sudo nft -c -f access.nft

별도 실습 테이블 설치와 유한 기동

미션 solution의 검토한 파일 또는 완성한 starter를 VM 콘솔에서 사용합니다. README의 라우팅·키·이름 해석 준비를 끝낸 뒤 실행합니다. 기존 서비스는 inactive여야 하며 prepare.sh는 사본 생성과 설치만 합니다. 기동 후 20초 안에 두 클라이언트의 관측을 수집합니다.

CONSOLE_READY=yes bash prepare.sh
sudo systemctl start bootcamp-systems.service

새 연결 비교와 복구

nft 조회는 적용 후 서버에서, allowed·denied 수집은 각각 해당 클라이언트에서 수행합니다. 미션 README의 실행 순서에 따라 보고서를 모으고 자연 종료 뒤 restore.sh와 다음 기동 응답을 기록합니다.

sudo nft list table inet bootcamp_access
python3 collect-client.py allowed
python3 collect-client.py denied

경계 사례까지 로컬 검사

새 출발지·포트·상태의 조합과 IPv6 입력을 검사합니다.

bash check.sh

확인 문제

실습

task.py의 allow를 완성합니다. 새 IPv4 실습망의 TCP 22·18080과 established/related만 허용합니다. 로컬 자동 검사는 고정 입력의 논리만 확인합니다. VM에서의 실제 실행과 기록은 따라하기 및 external 미션으로 확인합니다.

시작 코드·테스트 내려받기

실행 명령

bash check.sh

기대 결과

unittest의 모든 사례 OK, 종료 코드 0

모범 답안모범 답안 내려받기

더 읽기

면접 질문

  • SSH 접속이 실패할 때의 확인 순서를 설명합니다.