상태 기반 방화벽
130분 안팎
학습 목표
실습 라우터의 nftables에서 신규 연결·응답·기본 차단 규칙을 구성합니다.
개념
왜 응답 규칙이 필요한가
학생의 TCP SYN은 서버 8080으로 전달됐지만 화면이 열리지 않습니다. 요청 허용만 적으면 응답이 학생의 임시 포트로 돌아오는 과정에서 기본 차단에 걸릴 수 있습니다. 응답 포트를 모두 열기보다 커널이 추적한 흐름에 속한 패킷을 처리합니다. 이번 목표는 라우터 자신의 input과 중계 forward에 신규 요청·상태 응답·기본 차단을 구성하고, 실제 애플리케이션 응답으로 왕복을 검증하는 것입니다.
연결 추적과 소켓 상태를 구별합니다
ct state는 Netfilter 연결 추적이 보는 상태이며 ss의 TCP ESTAB 표시와 동일한 표가 아닙니다. new는 아직 응답 방향이 확인되지 않은 흐름 등에 쓰이고 established는 추적된 양방향 흐름에 속한 패킷을 가리킵니다. TCP만 대상이라고 생각하지 않습니다. UDP도 요청과 응답의 튜플과 시간 제한으로 추적될 수 있습니다. 교육 DNS 응답이 돌아오는 이유를 TCP handshake로 설명하면 프로토콜을 혼동한 것입니다.
related와 invalid
related는 기존 추적 흐름과 관련된 별도 패킷이나 흐름의 상태입니다. 관련 ICMP 오류가 한 예이며 임의의 서버가 보내는 새 요청을 전부 뜻하지 않습니다. invalid는 연결 추적이 유효한 상태로 분류하지 못한 패킷입니다. 생성한 체인은 invalid drop을 앞에 두고 established,related accept를 다음에 둡니다. 이 순서는 신규 서비스 허용을 간결하게 유지하지만 전송 보안·사용자 인증·애플리케이션 권한까지 해결하는 규칙은 아닙니다.
체인의 목적지를 결정합니다
학교 서버 10.20.30.11 요청은 라우터가 받아 다른 망으로 전달하므로 forward입니다. DNS 10.20.30.1은 r1 자신의 주소에 있는 서비스라 input입니다. 라우터의 v30 주소로 요청한다고 forward 규칙에 넣으면 DNS와 일치하지 않습니다. DNS 서버를 다른 장비로 옮기는 변경에서는 hook도 다시 검토해야 합니다. 설정 파일 이름이 방화벽이라고 같아도 어느 장비의 어느 방향에서 적용되는지가 행마다 달라집니다.
생성기에서 읽어야 할 부분
compile_policy.py는 filter-config.json과 policy.csv를 읽어 school_filter라는 inet 테이블만 만듭니다. input과 forward base chain은 type filter, hook 이름, priority filter, policy drop을 선언합니다. 학생 DHCP 예외와 CSV 행에는 counter와 comment를 붙여 자료 이름과 연결합니다. 마지막에 이름 있는 default drop을 두어 기본 차단 카운터를 읽을 수 있습니다. 체인 자체 policy도 drop이므로 마지막 행을 제거해도 암묵 허용으로 바뀌지 않습니다.
신규 허용 조건을 좁힙니다
학생 웹은 ip saddr 학생 /24와 ip daddr 학교 서버 /32, tcp dport 8080, ct state new를 같이 씁니다. 교직원 관리도 같은 형식으로 출발지와 포트만 업무 범위에 맞게 제한합니다. 이미 추적된 응답은 앞 상태 규칙에서 처리하고 신규 요청은 해당 역할 규칙에서 처리합니다. conntrack 상태가 established라는 사실을 특정 사용자의 인증 성공이라고 해석하지 않습니다. 주소 기반 네트워크 정책과 계정 기반 권한은 서로 다른 검증 대상입니다.
DHCP 예외는 입력 인터페이스까지 제한합니다
학생 DHCP 요청은 v10에서 라우터로 들어오는 UDP 68→67입니다. 아직 주소가 없는 0.0.0.0 또는 학생 /24, 브로드캐스트 또는 학생 게이트웨이 목적지를 허용합니다. 이를 established 규칙만으로 처리할 수는 없습니다. 최초 요청이 신규이기 때문입니다. 생성기의 student-dhcp 행은 input에서 처리하고 라우터 응답은 이번 구성의 제한 없는 output 경로를 사용합니다. DHCP를 모든 인터페이스에서 열었다고 확대 해석하지 않습니다.
NAT와 필터를 따로 관리합니다
이번 파일에는 DNAT이 없고 forward/filter 뒤 postrouting/srcnat에서 가상 외부 목적지에 대해서만 출발지를 변환합니다. firewall-nat.nft는 school_policy_nat 테이블을 별도로 추가해 게스트 /24를 포함합니다. 원래 m06 nat.nft를 덮어쓰지 않습니다. NAT만 추가하면 게스트 응답 경로가 생겨도 학교 내부 접근을 제한하지 않습니다. 필터는 서비스 범위를 정하고 SNAT은 가상 WAN의 응답이 라우터로 돌아올 주소를 제공한다는 역할을 나누어 설명합니다.
syntax check와 적용의 차이
Linux VM에서 ip netns exec bcnet-r1 nft --check --file firewall.nft를 실행하면 문법과 커널이 받는 규칙을 검사하지만 실제 정책을 설치하지 않습니다. 그 다음 같은 공간에서 --file로 적용합니다. 이 레슨의 output에는 아직 실행하지 않은 VM 출력이 없습니다. 실제 실행에서 syntax error가 뜨면 줄 번호와 토큰을 확인하고, Operation not permitted면 권한과 네임스페이스 준비를 먼저 확인합니다. 문법 통과가 서비스 성공의 증거는 아닙니다.
기존 테이블과의 충돌
상속 진단은 실험용 diagnosis 테이블을 제거한 뒤 이 모듈로 넘어옵니다. 새로운 school_filter가 이미 있다면 중복 이름으로 적용이 실패할 수 있습니다. 남의 테이블까지 지우는 flush ruleset을 사용하지 않습니다. 자신의 이전 실행 소유 기록과 실패 단계부터 확인합니다. 실제 장비에는 다른 base chain이 존재할 수 있어 여기서 accept한 패킷이 뒤에서 drop될 수 있습니다. 실습처럼 단일 소유 공간인지 전체 ruleset을 읽어 적용 범위를 확인합니다.
이미 열린 연결로 시험하면 헷갈립니다
상태 응답 허용은 established 흐름을 계속 통과시킬 수 있습니다. 새 서비스 허용을 없앤 뒤 기존 브라우저 탭의 재사용 연결로만 시험하면 정책 변경이 안 된 것처럼 보일 수 있습니다. 이번 실행기는 curl과 UDP 클라이언트를 매번 새로 띄워 별도 소켓을 사용합니다. 도구가 바뀌면 연결 재사용 여부와 튜플을 확인합니다. 상태를 지우는 실험은 별도 범위와 복구 계획이 필요하며 호스트 전체 추적 표를 비우지 않습니다.
학교 서버의 응답으로 판정합니다
허용 검사에서는 연결 종료 코드만 보지 않고 school ready 또는 policy service ready 본문, DNS의 10.20.30.11 답을 대조합니다. 규칙의 counter가 증가하면 그 규칙에서 패킷이 처리됐다는 단서를 얻지만 최종 HTTP 성공을 보장하지 않습니다. reply 규칙 카운터 증가도 여러 흐름이 합쳐진 값입니다. 각 행의 요청과 응답 자료를 같이 남겨 “해당 신규 요청과 후속 응답이 통과했습니다”라고 범위를 정해 설명합니다.
복원은 정책의 일부입니다
firewall_run.py는 자신의 필터와 NAT만 finally에서 제거하고 임시 서비스의 자체 종료를 wait합니다. 새 WAN 네임스페이스는 프로세스가 남지 않았을 때 지웁니다. 상속 검사기는 앞 주소·경로·서비스·NAT·진단 회귀를 실행하고 호스트 snapshot 전후를 비교합니다. 서비스 최대 수명은 복사본에서 240초로 늘렸으며 종료까지 기다릴 수 있습니다. 권한 오류나 환경 준비 실패를 차단 성공으로 처리하지 않고 실제 증거가 없으면 대기 상태를 유지합니다.
구현 완료의 기준
starter는 guest-web을 잘못 허용하고 stateful을 false로 둡니다. 이 둘을 요구와 맞게 고친 뒤 python3 compile_policy.py를 실행해 설정과 생성 파일을 동기화합니다. python3 test_policy.py는 원본 사건 기록·정책 동작·상태와 기본값·생성 일치·NAT 범위를 검사합니다. 이 검사는 문서 계약이므로 Linux의 실제 패킷 처리까지 증명하지 않습니다. VM check.sh에서 DHCP·DNS·웹 응답과 차단 카운터를 확인한 뒤 설정 파일과 관측 자료를 함께 제출합니다.
상태와 hook 순서는 nftables 공식 매뉴얼에서 확인합니다. 본문은 이 학교망을 위해 작성했으며 명령 예제를 복제한 자료가 아닙니다.
따라하기
상태 응답과 잘못된 허용 고치기
network-stateful-filter starter 루트에서 다음 검사를 실행합니다. guest-web 동작과 stateful 설정의 실패 원인을 읽고 각각 drop·true로 고칩니다. 기존 진단 기록은 보존합니다.
python3 test_policy.py설정 파일 다시 생성
policy.csv와 filter-config.json을 고친 뒤 다음 명령을 실행합니다. 생성 결과와 입력 일치 검사를 통과시킵니다. 맥의 문서 검사는 실제 패킷 처리 검사와 구별합니다.
python3 compile_policy.py
python3 test_policy.py상태 기반 정책 적용과 관측
Linux VM에서 다음 명령을 실행합니다. 실행기는 nft --check 뒤 소유 r1에 적용합니다. evidence/firewall/counters.json에서 reply·student-dhcp와 각 허용 행 packets를 확인하고 DNS 답·HTTP 본문 자료를 읽습니다. 실제망 출력은 VM에서 생성합니다.
sudo bash check.sh확인 문제
실습
filter-config.json의 stateful과 policy.csv의 guest-web을 요구대로 고치고 compile_policy.py로 생성합니다. input DNS/DHCP와 forward 서비스, 상태 응답·기본 차단을 설명합니다. 맥에서 python3 test_policy.py, Linux VM에서 sudo bash check.sh를 실행합니다. README에 검사 대상과 자체 종료·정리 절차가 있습니다. 관측하지 않은 출력을 증거로 쓰지 않습니다.
실행 명령
sudo bash check.sh
기대 결과
문서 검사 통과 후 실제 DHCP 포함 허용 8건·차단 6건, 대조·카운터·복원 검사와 호스트 상태 동일성 확인. 실제망은 external 대기입니다.
모범 답안
모범 답안 내려받기더 읽기
면접 질문
- 방화벽 정책을 검증하는 실습 방법을 설명합니다.