Skip to content

필사 모드: 리눅스 방화벽과 접근 제어 완전 가이드: nftables, firewalld, ufw를 잠기지 않고 다루기

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

들어가며

방화벽 작업의 진짜 위험은 규칙을 잘못 쓰는 것이 아닙니다. 원격에서 규칙을 적용한 순간 자기 자신이 차단되어 되돌릴 수단이 없어지는 것입니다. 데이터 센터에 갈 수 없고 콘솔 접근 수단도 없다면 그 서버는 사실상 잃은 것입니다.

그래서 이 글은 규칙 문법보다 절차를 앞세웁니다. 무엇을 어떤 순서로 적용하고, 실수했을 때 어떻게 자동으로 되돌아오게 만드는지가 핵심입니다. 문법은 그다음입니다.

다루는 범위는 세 층입니다. 커널의 netfilter 위에 nftables가 있고, 그 위에 firewalld와 ufw 같은 관리 도구가 있습니다. 어느 도구를 쓰든 최종적으로는 같은 커널 훅에 규칙이 들어간다는 점을 이해하면 도구 간 이동이 쉬워집니다.

기준은 nftables 1.0 이상, firewalld 1.x, ufw 0.36 이상입니다. RHEL 계열 8 이상은 firewalld가 기본이고 백엔드는 nftables입니다. Debian/Ubuntu는 ufw가 관례이며 역시 nftables 위에서 동작합니다. iptables 명령이 남아 있는 배포판에서도 대개 nftables로 변환해 처리하는 호환 계층입니다.


1. 자신을 잠그지 않는 절차

기술적인 내용에 앞서 이 절차를 먼저 몸에 익히세요. 순서가 전부입니다.

절차 1 — 되돌리기 예약을 먼저 겁니다. 규칙을 적용하기 전에 "일정 시간 뒤 자동으로 원복"을 예약해 둡니다. 접속이 끊기면 예약이 살아나 원래 상태로 돌아옵니다.

# nftables: 현재 상태 저장 후 10분 뒤 자동 복구 예약
sudo nft list ruleset > /root/nft-backup-2026-08-15.nft
echo "nft -f /root/nft-backup-2026-08-15.nft" | sudo at now + 10 minutes

at이 없는 환경이라면 백그라운드 셸로도 같은 일을 할 수 있습니다.

sudo setsid bash -c 'sleep 600; nft -f /root/nft-backup-2026-08-15.nft' >/dev/null 2>&1 &

절차 2 — 검증한 뒤 적용합니다. nftables는 파일 전체를 문법 검사만 할 수 있습니다.

sudo nft -c -f /etc/nftables/main.nft

-c는 문서에 따르면 적용하지 않고 유효성만 확인합니다. 반드시 거치세요.

절차 3 — 접속을 확인합니다. 기존 세션을 닫지 말고 새 터미널에서 접속해 봅니다.

절차 4 — 확인이 끝나면 예약을 취소하고 영구 저장합니다.

atq
sudo atrm 3
sudo systemctl enable --now nftables

firewalld에는 이 절차가 기능으로 들어 있습니다. --timeout을 주면 지정 시간 뒤 규칙이 자동으로 사라집니다.

sudo firewall-cmd --zone=public --add-port=8080/tcp --timeout=5m

문서에 따르면 --timeout--permanent와 함께 쓸 수 없습니다. 런타임 규칙에만 적용되기 때문입니다. 이 조합이 firewalld를 쓰는 가장 큰 실무적 이유 중 하나입니다.

긴급 상황용 명령도 알아 두세요.

sudo firewall-cmd --panic-on
sudo firewall-cmd --panic-off

--panic-on은 문서 표현대로 모든 수신·송신 패킷을 버립니다. 침해 대응 시 즉시 격리하는 용도이며, 원격에서 실행하면 그 즉시 접속이 끊깁니다. 콘솔 접근이 확보된 상태에서만 쓰세요.


2. nftables의 구조 — 테이블, 체인, 규칙

nftables는 세 계층으로 구성됩니다.

  • 테이블: 주소 패밀리별 컨테이너입니다. 패밀리는 ip, ip6, inet, arp, bridge, netdev입니다. inet은 IPv4와 IPv6를 함께 처리하므로 대부분의 경우 이것을 씁니다.
  • 체인: 규칙의 묶음입니다. 커널 훅에 붙는 베이스 체인과, 점프로만 도달하는 일반 체인이 있습니다.
  • 규칙: 매치 조건과 판정(verdict)의 조합입니다.

베이스 체인 선언에는 타입, 훅, 우선순위가 필요합니다.

sudo nft add table inet filter
sudo nft add chain inet filter input '{ type filter hook input priority filter; policy drop; }'
sudo nft add chain inet filter forward '{ type filter hook forward priority filter; policy drop; }'
sudo nft add chain inet filter output '{ type filter hook output priority filter; policy accept; }'

훅 이름은 prerouting, input, forward, output, postrouting, ingress, egress입니다. 우선순위는 키워드로 지정할 수 있으며 문서 기준 값은 raw(-300), mangle(-150), dstnat(-100), filter(0), security(50), srcnat(100)입니다.

기본 정책은 accept(기본값) 또는 drop입니다. policy drop을 선언하는 순간 그 훅으로 들어오는 모든 패킷이 막히므로, 반드시 허용 규칙을 먼저 넣고 정책을 바꾸는 순서를 지켜야 합니다.

규칙 추가는 다음과 같습니다.

sudo nft add rule inet filter input ct state established,related accept
sudo nft add rule inet filter input iif lo accept
sudo nft add rule inet filter input tcp dport 22 accept
sudo nft add rule inet filter input ip saddr 10.0.0.0/8 tcp dport 5432 accept
sudo nft add rule inet filter input ip protocol icmp accept
  • ct state established,related accept가장 먼저 와야 하는 규칙입니다. 이미 성립한 연결의 응답 패킷을 허용합니다. 이것이 없으면 서버가 밖으로 보낸 요청의 응답도 막힙니다.
  • iif lo accept는 루프백을 허용합니다. 이것이 빠지면 로컬 서비스 간 통신이 끊겨 원인을 찾기 어려운 장애가 납니다.
  • 판정은 accept, drop, reject, jump, goto입니다.

dropreject의 차이를 알아 두세요. drop은 응답 없이 버리므로 클라이언트가 타임아웃까지 기다립니다. reject는 거부 응답을 보내 즉시 실패합니다. 외부 노출 포트에는 스캔 대응상 drop이, 내부망에서는 진단 편의상 reject가 흔히 선택됩니다.

이 선택이 운영에 미치는 영향은 생각보다 큽니다. 내부 서비스 간 통신을 drop으로 막으면, 호출하는 쪽은 연결 타임아웃까지 스레드를 붙잡고 기다립니다. 타임아웃이 30초로 잡혀 있다면 그동안 커넥션 풀이 고갈되고, 결국 방화벽 규칙 하나가 서비스 전체의 지연으로 번집니다. 내부망에서는 빠르게 실패하는 편이 낫다는 원칙을 기억하세요.

주소와 포트를 집합으로 묶으면 규칙이 훨씬 간결해집니다. 집합은 별도로 정의해 여러 규칙에서 재사용할 수 있고, 내용만 갱신하면 규칙을 건드리지 않고 허용 대상을 바꿀 수 있습니다.

sudo nft add set inet filter admin_ips '{ type ipv4_addr; flags interval; }'
sudo nft add element inet filter admin_ips '{ 10.0.3.0/24, 10.0.9.7 }'
sudo nft add rule inet filter input ip saddr @admin_ips tcp dport 22 accept
sudo nft list set inet filter admin_ips

flags interval은 대역 표기를 허용합니다. 관리자 IP 목록이 바뀔 때 규칙이 아니라 집합만 갱신하면 되므로 운영 실수가 줄어듭니다.


3. nftables 조회와 수정

sudo nft list ruleset
sudo nft list table inet filter
sudo nft -a list ruleset
sudo nft list chain inet filter input

-a는 각 규칙에 핸들 번호를 붙여 보여 줍니다. 삭제는 핸들로만 정확히 지정할 수 있으므로 이 옵션이 필수입니다.

sudo nft -a list chain inet filter input
sudo nft delete rule inet filter input handle 5
sudo nft insert rule inet filter input position 4 tcp dport 443 accept

add는 체인 끝에, insert는 앞쪽 또는 지정 위치에 넣습니다. 규칙은 위에서 아래로 평가되고 첫 매치에서 판정이 결정되므로 순서가 결과를 바꿉니다.

전체 초기화는 다음과 같습니다.

sudo nft flush ruleset

파괴적 명령 경고: 문서가 명시하듯 nft flush ruleset모든 테이블과 그 내용을 전부 제거합니다. 기본 정책이 drop인 체인이 사라지면 오히려 전면 개방 상태가 되고, 반대로 다른 도구가 관리하던 규칙까지 날아갑니다. 원격에서는 백업과 복구 예약 없이 절대 실행하지 마세요.

영구 설정은 파일로 관리하고 원자적으로 적용하는 것이 정석입니다.

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
  chain input {
    type filter hook input priority filter; policy drop;

    ct state established,related accept
    ct state invalid drop
    iif lo accept
    ip protocol icmp accept
    ip6 nexthdr ipv6-icmp accept

    ip saddr 10.0.0.0/8 tcp dport 22 accept
    tcp dport { 80, 443 } accept

    counter comment "dropped"
  }

  chain forward {
    type filter hook forward priority filter; policy drop;
  }

  chain output {
    type filter hook output priority filter; policy accept;
  }
}

이 파일을 /etc/nftables/main.nft로 두고 검사 후 적용합니다.

sudo nft -c -f /etc/nftables/main.nft
sudo nft -f /etc/nftables/main.nft
sudo systemctl enable nftables

nft -f파일 전체를 원자적으로 적용합니다. 중간에 실패하면 아무것도 적용되지 않으므로, 규칙 절반만 들어간 위험한 중간 상태가 생기지 않습니다. 이것이 명령을 한 줄씩 실행하는 것보다 안전한 이유입니다.


4. firewalld — 존 기반 관리

RHEL 계열의 기본 도구입니다. 인터페이스와 출발지를 존(zone) 에 배정하고, 존마다 허용 규칙을 둡니다.

sudo firewall-cmd --state
sudo firewall-cmd --get-default-zone
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --list-all
sudo firewall-cmd --zone=public --list-all

가장 중요한 개념은 런타임과 영구 설정의 분리입니다.

# 런타임에만 적용 (재기동 시 사라짐)
sudo firewall-cmd --zone=public --add-service=https

# 영구 설정에만 반영 (지금은 적용 안 됨)
sudo firewall-cmd --permanent --zone=public --add-service=https

# 영구 설정을 런타임에 반영
sudo firewall-cmd --reload

# 현재 런타임 상태를 영구로 저장
sudo firewall-cmd --runtime-to-permanent

--runtime-to-permanent는 문서 표현대로 현재 활성 런타임 설정을 영구 설정에 덮어씁니다. 안전 절차는 명확합니다. 먼저 런타임에만 적용해 접속을 확인하고, 확인이 끝난 뒤에 영구로 저장하는 것입니다. 처음부터 --permanent를 쓰고 --reload하는 방식은 검증 단계가 없어 위험합니다.

포트와 출발지 지정입니다.

sudo firewall-cmd --zone=public --add-port=8080/tcp
sudo firewall-cmd --zone=internal --add-source=10.0.0.0/8
sudo firewall-cmd --zone=public --remove-service=cockpit
sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="10.0.3.0/24" port port="5432" protocol="tcp" accept'

영구 설정의 문법 검사도 있습니다.

sudo firewall-cmd --check-config

--reload--complete-reload의 차이도 알아 두세요. 문서에 따르면 --reload는 상태 정보를 유지하고, --complete-reload는 netfilter 커널 모듈까지 다시 적재합니다. --complete-reload는 연결 추적 상태를 잃어 기존 연결이 끊길 수 있으므로 문제 해결 목적에서만 쓰세요.


5. ufw — 단순함이 필요한 곳

Ubuntu의 기본 관리 도구입니다. 규칙 수가 적고 서버 역할이 단순할 때 적합합니다.

sudo ufw status
sudo ufw status verbose
sudo ufw status numbered

순서가 절대적으로 중요합니다. 기본 정책을 거부로 바꾸기 전에 SSH를 먼저 허용해야 합니다.

# 1. 먼저 SSH 허용
sudo ufw allow 22/tcp

# 2. 그다음 기본 정책 설정
sudo ufw default deny incoming
sudo ufw default allow outgoing

# 3. 마지막에 활성화
sudo ufw enable

파괴적 명령 경고: 이 순서를 뒤집으면, 즉 SSH 허용 없이 default deny incoming 상태에서 ufw enable을 실행하면 원격 접속이 즉시 끊깁니다. ufw enable은 SSH 세션에서 실행할 때 경고를 보여 주지만, 확인 없이 진행하면 그대로 잠깁니다.

규칙 문법입니다.

sudo ufw allow 80/tcp
sudo ufw allow from 10.0.0.0/8 to any port 22 proto tcp
sudo ufw limit ssh/tcp
sudo ufw deny 3306
sudo ufw delete 3
sudo ufw insert 1 allow from 10.0.3.10
sudo ufw --dry-run allow 8080/tcp
  • --dry-run은 실제로 적용하지 않고 어떤 변경이 일어날지 보여 줍니다. 적용 전에 반드시 거치세요.
  • ufw limit은 속도 제한입니다. 문서에 따르면 한 IP가 30초 안에 6회 이상 연결을 시도하면 거부합니다. SSH 무차별 대입에 대한 간단한 완화책입니다.
  • sudo ufw delete NUM으로 지울 때는 먼저 status numbered로 번호를 확인해야 합니다. 번호는 규칙을 지울 때마다 재배열되므로, 여러 개를 지울 때는 큰 번호부터 지우세요.

로깅과 초기화입니다.

sudo ufw logging on
sudo ufw logging medium
sudo ufw reload
sudo ufw reset

파괴적 명령 경고: ufw reset은 모든 규칙을 지우고 설치 기본값으로 되돌립니다. 원격에서 실행하면 접속이 끊길 수 있습니다.


6. 규칙이 적용되지 않을 때 — 진단 순서

"규칙을 넣었는데 여전히 막힌다" 또는 "막았는데 여전히 들어온다"의 진단은 계층별로 내려갑니다.

1단계 — 실제 커널 규칙을 확인합니다. 관리 도구의 출력이 아니라 nftables 자체를 봐야 합니다.

sudo nft list ruleset
sudo iptables -L -n -v --line-numbers
sudo iptables-save | head -40

firewalld나 ufw를 쓰더라도 최종 규칙은 nft list ruleset에 나타납니다. 관리 도구가 의도한 대로 변환했는지 여기서 확인합니다.

2단계 — 규칙에 패킷이 걸리는지 셉니다. 카운터를 붙이면 확실합니다.

sudo nft add rule inet filter input tcp dport 8080 counter accept
sudo nft list chain inet filter input

카운터가 0이면 그 규칙까지 패킷이 도달하지 못한 것입니다. 앞선 규칙에서 이미 판정되었거나, 패킷이 애초에 도착하지 않는 것입니다.

3단계 — 순서와 중복을 확인합니다. 앞쪽에 더 넓은 drop 규칙이 있으면 뒤의 accept는 평가되지 않습니다.

4단계 — 도구 충돌을 확인합니다. firewalld와 ufw를 동시에 켜거나, Docker가 만든 규칙과 섞이면 예측이 어려워집니다.

systemctl is-active firewalld ufw nftables iptables
sudo nft list tables

Docker는 자체적으로 규칙을 삽입합니다. 그리고 그 규칙은 호스트 방화벽의 입력 체인이 아니라 다른 체인에 들어가므로, 호스트 방화벽으로 막았다고 생각한 포트가 컨테이너를 통해 열려 있는 상황이 생깁니다. 컨테이너 포트 공개 정책은 방화벽과 별도로 검토해야 합니다.

5단계 — 상위 계층을 확인합니다. 클라우드라면 보안 그룹이나 네트워크 ACL이 먼저 막고 있을 수 있습니다. 호스트에 도달조차 하지 않는다면 호스트 방화벽은 무고합니다.

sudo tcpdump -ni eth0 'tcp port 8080' -c 20

패킷이 전혀 보이지 않으면 네트워크 경로 문제이고, 보이는데 응답이 없으면 호스트 안의 문제입니다. 이 한 번의 확인이 조사 범위를 절반으로 줄입니다.

6단계 — 로그를 봅니다. 버려지는 패킷을 기록하도록 규칙을 추가할 수 있습니다.

sudo nft add rule inet filter input limit rate 5/minute log prefix '"nft-drop: "' drop
sudo journalctl -k -f -g 'nft-drop'

limit rate를 함께 쓰지 않으면 로그가 폭주해 디스크를 채웁니다. 반드시 제한을 거세요.


7. 접근 제어의 나머지 계층

방화벽만으로 접근 제어가 완결되지 않습니다. 계층을 나눠 정리합니다.

계층수단특징
네트워크 경계클라우드 보안 그룹, ACL호스트에 도달 전 차단
호스트 방화벽nftables, firewalld, ufw포트와 출발지 단위
서비스 설정바인드 주소, 애플리케이션 ACL가장 확실한 차단
인증키, 인증서, 토큰누구인지 확인
권한사용자·그룹, SELinux, sudo무엇을 할 수 있는지

가장 효과적인 접근 제어는 방화벽이 아니라 바인드 주소입니다. 서비스가 루프백에만 바인드되어 있으면 방화벽 규칙이 없어도 외부에서 접근할 수 없습니다.

sudo ss -tlnp

0.0.0.0:5432처럼 모든 인터페이스에 열려 있는 서비스를 찾아, 정말 외부 접근이 필요한지 검토하세요. 필요 없다면 설정에서 127.0.0.1이나 내부 인터페이스 주소로 제한하는 것이 방화벽 규칙 한 줄보다 확실합니다.

sudo 권한도 접근 제어의 일부입니다.

sudo -l
sudo visudo -c
sudo visudo -f /etc/sudoers.d/deploy

visudo를 반드시 쓰세요. 문법 오류가 있는 sudoers 파일은 sudo 자체를 못 쓰게 만들며, 이것도 일종의 자기 잠금 사고입니다. visudo는 저장 전에 문법을 검사해 이 사고를 막아 줍니다. -c는 기존 파일의 문법만 검사합니다.

SSH 접근 제한과 방화벽을 함께 설계하는 방법은 SSH 운영 완전 가이드를 참고하세요.


퀴즈: 실력을 확인해 보세요

퀴즈 1: 원격 서버의 방화벽 규칙을 크게 바꿔야 합니다. 첫 번째로 할 일은?

정답: 현재 규칙을 저장하고 일정 시간 뒤 자동 복구를 예약합니다

설명: 규칙 작성보다 되돌리기 준비가 먼저입니다.

sudo nft list ruleset > /root/nft-backup-2026-08-15.nft
echo "nft -f /root/nft-backup-2026-08-15.nft" | sudo at now + 10 minutes

firewalld라면 --timeout 옵션이 같은 역할을 합니다.

sudo firewall-cmd --zone=public --add-port=8080/tcp --timeout=5m

접속이 끊겨도 시간이 지나면 원래 상태로 돌아오므로, 최악의 경우에도 서버를 잃지 않습니다.

퀴즈 2: ufw로 기본 거부 정책을 적용하려 합니다. 올바른 순서는?

정답: SSH 허용을 먼저 넣고, 기본 정책을 바꾸고, 마지막에 활성화합니다

설명: 순서를 뒤집으면 활성화되는 순간 접속이 끊깁니다.

sudo ufw allow 22/tcp
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw --dry-run enable
sudo ufw enable

--dry-run으로 적용될 규칙을 미리 확인하는 습관을 들이세요. 무차별 대입 완화가 필요하면 ufw limit ssh/tcp도 고려할 수 있습니다. 문서에 따르면 30초 안에 6회 이상 연결을 시도하는 IP를 거부합니다.

퀴즈 3: nftables 입력 체인에서 반드시 앞쪽에 있어야 하는 두 규칙은 무엇이고 왜인가요?

정답: 연결 상태 허용과 루프백 허용입니다

설명: 이 두 규칙이 없으면 정상 통신이 광범위하게 깨집니다.

sudo nft add rule inet filter input ct state established,related accept
sudo nft add rule inet filter input iif lo accept

첫 규칙이 없으면 서버가 밖으로 보낸 요청의 응답 패킷까지 막혀 패키지 설치나 API 호출이 전부 실패합니다. 둘째가 없으면 로컬 서비스 간 통신이 끊겨 원인을 찾기 어려운 장애가 납니다.

퀴즈 4: 방화벽으로 5432 포트를 막았는데 컨테이너의 데이터베이스에 외부에서 접속됩니다. 왜일까요?

정답: 컨테이너 런타임이 별도 체인에 자체 규칙을 삽입하기 때문입니다

설명: Docker 같은 런타임은 포트를 공개할 때 자체적으로 전달 관련 규칙을 넣습니다. 그 규칙은 호스트의 입력 체인과 다른 경로로 평가되므로, 입력 체인만 막아서는 차단되지 않습니다.

sudo nft list ruleset | grep -i -A5 'docker'
sudo ss -tlnp | grep 5432

근본 해결은 컨테이너 포트를 모든 인터페이스가 아니라 루프백에만 공개하는 것입니다. 포트 공개 정책은 방화벽과 별도로 검토해야 합니다.

퀴즈 5: 규칙을 넣었는데 여전히 접속이 막힙니다. 원인을 어떻게 좁히나요?

정답: 카운터로 패킷이 규칙에 도달하는지 확인하고, tcpdump로 패킷이 호스트에 오는지 확인합니다

설명: 두 확인으로 조사 범위가 크게 줄어듭니다.

sudo nft add rule inet filter input tcp dport 8080 counter accept
sudo nft list chain inet filter input
sudo tcpdump -ni eth0 'tcp port 8080' -c 20

tcpdump에 패킷이 전혀 보이지 않으면 호스트에 도달하지 않는 것이므로 클라우드 보안 그룹이나 경로 문제입니다. 패킷은 보이는데 카운터가 0이면 앞선 규칙에서 이미 판정된 것이므로 순서를 봐야 합니다.

퀴즈 6: 방화벽 규칙 대신 더 확실하게 서비스 노출을 막는 방법은?

정답: 서비스를 루프백이나 내부 인터페이스에만 바인드합니다

설명: 방화벽은 규칙이 실수로 지워지거나 도구가 충돌하면 뚫립니다. 반면 서비스가 애초에 외부 인터페이스에서 대기하지 않으면 규칙과 무관하게 접근할 수 없습니다.

sudo ss -tlnp

0.0.0.0이나 [::]로 열린 포트를 목록으로 뽑아 하나씩 검토하세요. 관리 도구, 메트릭 엔드포인트, 데이터베이스가 전체 인터페이스에 열려 있는 경우가 흔합니다. 방화벽은 그 위에 얹는 두 번째 방어선으로 두는 것이 맞습니다.


마치며

방화벽 작업에서 기억할 것은 문법이 아니라 순서입니다. 되돌리기를 먼저 예약하고, 검사하고, 런타임에만 적용하고, 새 세션으로 확인하고, 그다음에 영구 저장합니다. 이 다섯 단계를 지키면 잠기는 사고는 일어나지 않습니다.

그리고 도구를 고를 때는 규모에 맞추세요. 단일 서버에 규칙 열 줄이면 ufw로 충분하고, 존과 서비스 개념이 필요하면 firewalld가 낫고, 규칙을 코드로 관리하고 원자적으로 배포해야 하면 nftables 파일이 정답입니다. 어느 쪽을 고르든 최종 결과는 nft list ruleset에서 확인할 수 있다는 점을 기억하면 도구 사이를 오가기 어렵지 않습니다.

마지막으로 한 가지만 더. 방화벽은 마지막 방어선이 아니라 여러 겹 중 하나입니다. 바인드 주소, 인증, 권한이 함께 설계되어야 실제로 안전해집니다.


참고 자료


이어서 읽기

현재 단락 (1/226)

방화벽 작업의 진짜 위험은 규칙을 잘못 쓰는 것이 아닙니다. **원격에서 규칙을 적용한 순간 자기 자신이 차단되어 되돌릴 수단이 없어지는 것**입니다. 데이터 센터에 갈 수 없고 ...

작성 글자: 0원문 글자: 11,609작성 단락: 0/226