TT Lab
블로그 시작하기
배우기 러닝패스 코스

서버를 처음부터 잠근다

기본 거부가 뒤집는 그림

TT Lab 에서 이어서 보기

한 줄 요약

기본 거부(default-deny) 방화벽은 "명시적으로 연 것만 닿는다" 로 그림을 뒤집습니다. nftables 로 세울 때 가장 위험한 함정은 자기가 연결된 통로마저 끊는 것입니다.

왜 이게 필요했나

방화벽이 없는 서버는 듣고 있는 모든 포트가 노출됩니다. 관리용 API, 디버그 포트, 임시로 띄운 서비스, 개발자가 잊은 포트까지 전부입니다. 어느 하나에 약점이 있으면 그 포트가 입구가 됩니다. 기본 거부는 이 목록을 "열어야 할 소수" 로 줄입니다.

어떻게 동작하나

nftables 는 테이블·체인·규칙으로 이루어집니다. 입력 트래픽을 다루는 체인을 hook input 에 걸고 policy drop 으로 두면, 명시적으로 accept 하지 않은 패킷은 버려집니다.

규칙의 순서가 중요합니다. 기본 거부를 켜기 전에 반드시 먼저 허용해야 하는 것이 셋입니다.

먼저 허용 이유
루프백(iif lo) 로컬 프로세스끼리의 통신이 끊기면 서비스가 깨진다
established/related 이미 맺은 연결의 응답 패킷이 끊기면 지금 당신의 세션도 죽는다
관리 통로(SSH 등) 이게 없으면 기본 거부를 켠 순간 서버에 다시 들어갈 수 없다

세 번째가 이 실습에서 가장 중요합니다. 원격 서버에서 policy drop 을 켜는 것은 자기가 앉은 나뭇가지를 자르는 일과 같습니다. 관리 통로를 규칙에 넣지 않고 기본 거부를 켜면 연결이 끊기고, 콘솔 접근이 없으면 되살릴 방법이 없습니다. 실무에서는 새 규칙을 "몇 분 뒤 자동 롤백" 과 함께 적용하거나, 콘솔을 띄워 둔 채 바꿉니다.

서비스 포트를 열 때는 출발지도 좁힐 수 있습니다. 공개 웹 포트는 모두에게 열지만, 관리용 API 는 ip saddr 10.50.0.0/24 처럼 사내 대역에서만 받게 합니다. 마지막으로 규칙을 /etc/nftables.conf 에 저장하고 nftables 서비스를 켜야 재부팅을 넘깁니다 — 메모리에만 올린 규칙은 재부팅에 사라집니다.

현장에서 만나는 모습

가장 흔한 사고는 established 규칙을 빠뜨리고 기본 거부를 켜 원격 세션이 통째로 멈추는 것입니다. 둘째는 규칙을 올리기만 하고 저장하지 않아, 재부팅 뒤 방화벽이 통째로 사라지는 것입니다. 셋째는 나가는(output) 방향까지 기본 거부로 잠가 DNS·갱신·모니터링이 끊기는 것입니다 — 들어오는 방향부터 다루고, 나가는 쪽은 신중하게 따로 설계합니다.

English corner

다음 실습에서 할 것

방화벽이 없는 서버에 nftables 로 기본 거부 입력 방화벽을 세웁니다. 웹 포트는 모두에게, 관리 포트는 사내 대역에만 열고, 채점 통로를 살려 둔 채 정상 서비스와 차단을 양쪽으로 확인한 뒤 저장합니다.

한 걸음 더 — 상태 추적과 로깅

nftables 의 ct state 는 연결 추적(conntrack)에 기댑니다. 연결 추적은 패킷이 아니라 '흐름' 을 기억해, 밖으로 나간 요청의 응답을 알아보고 들여보냅니다. 그래서 상태 기반 방화벽은 들어오는 새 연결만 규칙으로 판단하면 되고, 응답은 established 한 줄이 처리합니다. 이 원리를 모르면 '왜 80 을 안 열었는데 밖에 나간 요청의 응답은 들어오지?' 를 오해하게 됩니다.

버리는 패킷을 기록 하고 싶으면 log 구문을 drop 앞에 둡니다. 다만 공개 서버는 버려지는 패킷이 많아 로그가 폭주하므로, 레이트 리밋(limit rate)을 함께 걸거나 특정 포트만 기록합니다. 무엇을 막았는지 보이지 않으면 방화벽이 과하게 막고 있는지, 공격을 받고 있는지 알 수 없습니다.

점검 순서

  1. policy drop 을 켜기 전에 루프백·established·관리 통로가 먼저 들어갔는가.
  2. 공개 포트와 제한 포트(출발지 제한)가 의도대로 갈렸는가.
  3. 정상 접근과 차단을 양쪽으로 확인했는가.
  4. 규칙을 저장하고 서비스를 켜 재부팅을 넘기는가.