본문 바로가기
Operating System

iptables에서 nftables로 방화벽 규칙 마이그레이션하기 - iptables-translate 변환과 nft 검증

강철지그·2026년 8월 14일·조회 3

RHEL 9와 최신 데비안 계열로 서버를 올리다 보면 방화벽 백엔드가 이미 nftables로 넘어가 있다. iptables 명령은 여전히 먹지만 실제로는 nftables 위에서 도는 호환 계층이다. 그래서 오래된 iptables-save 규칙 뭉치를 그대로 두느냐, 이참에 nftables 문법으로 다시 쓰느냐를 한 번쯤 결정하게 된다. 이 글은 그 변환 작업을 도구로 처리하고 nft로 검증하는 방법을 순서대로 정리한다.

결론부터 말하면, 한 줄짜리 규칙은 iptables-translate로 즉석 변환하고, 규칙 뭉치 전체는 iptables-save | iptables-restore-translate -f -.nft 파일을 만든 뒤 nft -c -f로 문법 검사하고 nft -f로 적재한다. set과 map처럼 iptables의 ipset이나 여러 규칙으로 흩어져 있던 구조는 자동 변환이 매끄럽지 않아 nftables의 named set, map, verdict map으로 손봐 다시 쓰는 편이 낫다.

nftables와 변환 도구가 무엇인지 먼저

nftables는 iptables, ip6tables, arptables, ebtables를 하나로 대체하는 리눅스 커널의 패킷 필터 프레임워크다. 사용자 공간 명령은 nft 하나로 통일되고, 규칙은 테이블(table) 안에 체인(chain)을 두고 그 안에 규칙을 넣는 구조다.

변환 도구는 iptables 패키지에 같이 들어 있다. iptables-translate는 iptables 명령 한 줄을 받아 대응하는 nft add rule 문자열을 출력하고, iptables-restore-translateiptables-save 형식의 규칙 파일 전체를 nftables 스크립트로 바꾼다. 두 도구는 규칙을 실제로 적용하지 않는다. 변환 결과 텍스트만 내놓는다.

여기서 자주 나오는 두 용어를 미리 풀어 둔다. set은 IP나 포트 같은 값의 묶음으로, iptables의 ipset에 해당한다. map은 키에 값을 대응시키는 자료구조이고, 값이 accept나 drop 같은 판정이면 verdict map(vmap)이라 부른다. 아래에서는 한 줄 변환, 전체 변환과 검증, set과 map 재작성, 자주 걸리는 오류를 차례로 살펴본다.

1. 준비 확인

변환 도구가 있는지, nftables가 백엔드인지부터 본다. 버전 번호는 배포판 상태에 따라 다를 수 있다.

$ nft --version
nftables v1.0.4 (Lester Gooch)

$ iptables --version
iptables v1.8.8 (nf_tables)

$ which iptables-translate iptables-restore-translate
/usr/sbin/iptables-translate
/usr/sbin/iptables-restore-translate

RHEL 9 계열은 iptables 명령 뒤에 (nf_tables)가 붙어 나온다. 이미 nftables 위에서 돈다는 뜻이다. 도구가 없으면 dnf install iptables-nft(RHEL 9 호환), 데비안 계열은 apt install iptables로 설치한다.

2. 한 줄 규칙은 iptables-translate로

가장 간단한 형태다. iptables 명령을 그대로 iptables-translate 뒤에 붙이면 된다.

$ iptables-translate -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
nft add rule ip filter INPUT tcp dport 22 ct state new counter accept

왼쪽 iptables 표현이 오른쪽 nft 문법으로 1:1 대응된다. -m conntrack --ctstate NEWct state new로, -j ACCEPTcounter accept로 바뀐 점을 눈여겨보면 나머지 변환도 감이 온다.

IPv6는 ip6tables-translate를 쓴다. 여기서 실제 출력을 그대로 옮기면, 멀티포트 매칭 앞에 프로토콜 매칭 meta l4proto udp가 붙는다.

$ ip6tables-translate -A FORWARD -i eth0 -o eth3 -p udp -m multiport --dports 111,222 -j ACCEPT
nft add rule ip6 filter FORWARD iifname eth0 oifname eth3 meta l4proto udp udp dport { 111,222} counter accept

처음엔 meta l4proto udp가 군더더기처럼 보여 지웠다가, 멀티포트 매칭이 프로토콜 확정을 전제로 동작한다는 점 때문에 도구가 일부러 붙인다는 걸 알게 됐다. 손으로 규칙을 옮겨 적을 때 이 부분을 빼먹지 않도록 도구 출력을 그대로 복사하는 편이 안전하다.

3. 규칙 전체는 iptables-restore-translate로

운영 서버에는 규칙이 수십 개씩 쌓여 있다. 한 줄씩 옮기는 대신 현재 규칙을 통째로 덤프해서 변환한다. 먼저 iptables-save로 백업 겸 입력 파일을 만든다.

$ sudo iptables-save > /root/rules.v4
$ cat /root/rules.v4
# Generated by iptables-save v1.8.8 on Fri Aug 14 10:26:40 2026
*filter
:INPUT ACCEPT [5166:1752111]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [5058:628693]
-A FORWARD -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
COMMIT

이 파일을 iptables-restore-translate -f로 넘긴다. -를 쓰면 표준 입력을 받으므로 파이프로도 연결할 수 있다.

$ iptables-restore-translate -f /root/rules.v4 > /root/ruleset.nft
$ cat /root/ruleset.nft
# Translated by iptables-restore-translate v1.8.8 on Fri Aug 14 10:26:59 2026
add table ip filter
add chain ip filter INPUT { type filter hook input priority 0; policy accept; }
add chain ip filter FORWARD { type filter hook forward priority 0; policy accept; }
add chain ip filter OUTPUT { type filter hook output priority 0; policy accept; }
add rule ip filter FORWARD tcp dport 22 ct state new counter accept

파이프 한 줄로 붙여도 결과는 같다.

$ sudo iptables-save | iptables-restore-translate -f - > /root/ruleset.nft

여기서 반드시 짚어야 할 점이 있다. 생성된 ruleset.nft의 첫 줄은 주석이고 이어서 add table로 시작한다. #!/usr/sbin/nft -f 같은 셔뱅은 붙지 않는다. 그래서 이 파일에 실행 권한을 줘서 직접 돌리는 방식은 통하지 않는다.

$ chmod +x /root/ruleset.nft
$ ./ruleset.nft
./ruleset.nft: line 2: add: command not found

셔뱅이 없으니 셸이 add table ...을 셸 명령으로 해석해 command not found로 실패한다. 이 파일은 반드시 nft -f로 읽혀야 한다. 직접 실행하고 싶다면 파일 맨 위에 #!/usr/sbin/nft -f 한 줄을 손으로 넣어 주면 된다. 도구가 넣어 주는 것으로 착각하지 않는 게 핵심이다.

4. nft로 문법 검사하고 적재하고 검증

변환 결과를 바로 커널에 밀어 넣지 말고 dry-run부터 한다. -c는 검사만 하고 적용하지 않는다.

$ sudo nft -c -f /root/ruleset.nft
$

아무 출력 없이 프롬프트가 돌아오면 문법 문제가 없다는 뜻이다. 문제가 있으면 줄 번호와 함께 에러를 찍어 준다. 검사를 통과하면 실제로 적재한다.

$ sudo nft -f /root/ruleset.nft
$ sudo nft list ruleset
table ip filter {
	chain INPUT {
		type filter hook input priority 0; policy accept;
	}
	chain FORWARD {
		type filter hook forward priority 0; policy accept;
		tcp dport 22 ct state new counter packets 0 bytes 0 accept
	}
	chain OUTPUT {
		type filter hook output priority 0; policy accept;
	}
}

nft list ruleset가 커널에 실제로 올라간 규칙을 그대로 보여 준다. 변환 전 iptables -L -n -v 출력과 규칙 개수, 정책, 포트를 대조하면 누락 여부를 확인할 수 있다. 재부팅 후에도 유지하려면 /etc/nftables.conf에 규칙을 넣고 systemctl enable --now nftables로 서비스를 켠다.

5. set 재작성 - 흩어진 IP 목록을 named set으로

iptables에서 여러 소스 IP를 각각 규칙으로 나열했거나 ipset을 쓰던 부분은 자동 변환이 깔끔하지 않다. nftables의 named set으로 다시 쓰는 게 관리가 쉽다. set은 만들어 두고 나중에 원소를 추가, 삭제할 수 있다.

$ sudo nft add set ip filter blackhole { type ipv4_addr\; }
$ sudo nft add element ip filter blackhole { 192.168.1.4, 192.168.1.5 }
$ sudo nft add rule ip filter INPUT ip saddr @blackhole counter drop

규칙에서 @blackhole처럼 @ 뒤에 set 이름을 적어 참조한다. 셸에서 중괄호 안 세미콜론은 \;로 이스케이프해야 한다. CIDR 범위를 담으려면 set 정의에 flags interval을 준다.

$ sudo nft add set ip filter allownet { type ipv4_addr\; flags interval\; }
$ sudo nft add element ip filter allownet { 10.0.0.0/8, 192.168.0.0/16 }

한 규칙에서만 쓸 값 묶음이라면 이름 없이 tcp dport { 22, 80, 443 }처럼 중괄호 인라인(anonymous set)으로 넣어도 된다. 다만 인라인 set은 나중에 원소를 못 고치므로, 운영 중 갱신할 목록은 named set으로 둔다.

6. map과 verdict map 재작성

포트별로 다른 내부 IP로 DNAT하던 규칙이 여러 줄로 흩어져 있다면 map 하나로 합칠 수 있다. map은 키에 값을 대응시키는 자료구조다.

$ sudo nft add map ip nat porttoip { type inet_service : ipv4_addr\; }
$ sudo nft add element ip nat porttoip { 80 : 192.168.1.100, 8888 : 192.168.1.101 }
$ sudo nft add rule ip nat PREROUTING dnat to tcp dport map @porttoip

값이 accept나 drop 같은 판정이면 verdict map을 쓴다. 포트마다 허용, 차단을 다르게 줄 때 규칙 여러 개를 하나로 접을 수 있다.

$ sudo nft add rule ip filter INPUT tcp dport vmap { 22 : accept, 23 : drop }

set과 map은 iptables-translate가 대신 만들어 주지 않는다. 원본 규칙의 의도를 보고 손으로 설계해야 하는 부분이다. 변환 도구로 뼈대를 만든 뒤, 반복되던 규칙 묶음을 이렇게 set과 map으로 접는 순서로 작업하면 규칙 수가 눈에 띄게 줄어든다.

7. 자주 걸리는 오류와 해결

Error: Could not process rule: No such file or directory. 변환 파일이 존재하지 않는 테이블이나 체인에 규칙을 넣으려 할 때 난다. iptables-restore-translateadd tableadd chain을 앞에 만들어 주지만, 손으로 자른 조각 파일을 적용하면 테이블 생성 부분이 빠져 이 에러가 난다. 파일 맨 위에 add table ip filter가 있는지 확인한다.

기존 규칙 위에 겹쳐 쌓임. nft -f는 파일 내용을 기존 규칙에 더한다. 깨끗하게 다시 올리려면 파일 첫머리에 flush ruleset을 넣거나 sudo nft flush ruleset을 먼저 실행한다. 단, 원격 SSH 세션에서 flush ruleset은 접속을 끊을 수 있으니 콘솔이나 별도 세션을 열어 두고 작업한다.

add: command not found. 3절에서 본 셔뱅 함정이다. 생성 파일을 ./ruleset.nft로 직접 실행해서 나온다. nft -f /root/ruleset.nft로 읽히거나, 파일 첫 줄에 #!/usr/sbin/nft -f를 추가한다.

iptables와 nft가 동시에 보임. RHEL 9에서 iptables 명령은 nftables 백엔드에 규칙을 쓴다. 그래서 마이그레이션 도중 iptables -A로 넣은 규칙과 nft add rule로 넣은 규칙이 서로 다른 테이블에 공존할 수 있다. nft list ruleset으로 전체를 한눈에 보고, iptables 호환 명령은 변환이 끝난 뒤 쓰지 않는 것으로 정리한다.

정리

한 줄 규칙은 iptables-translate, 규칙 전체는 iptables-restore-translate.nft 파일을 만들고, nft -c -f로 검사한 뒤 nft -f로 적재하고 nft list ruleset으로 대조한다. 생성 파일은 셔뱅이 없으니 반드시 nft -f로 읽혀야 한다. ipset이나 반복 규칙은 자동 변환에 기대지 말고 named set, map, verdict map으로 다시 써서 규칙을 접는 것이 nftables로 넘어오는 실익이다.

자주 묻는 질문

iptables-translate로 변환하면 규칙이 바로 적용되나?

아니다. iptables-translate와 iptables-restore-translate는 변환 결과 텍스트만 출력할 뿐 커널에 규칙을 적용하지 않는다. 실제 적용은 출력을 nft add rule로 직접 실행하거나, 생성한 .nft 파일을 nft -f로 읽혀야 한다.

iptables-restore-translate가 만든 파일을 chmod +x로 직접 실행해도 되나?

안 된다. 이 파일의 첫 줄은 주석이고 이어서 add table로 시작하며 셔뱅(#!/usr/sbin/nft -f)이 없다. 직접 실행하면 셸이 add를 명령으로 해석해 'add: command not found'로 실패한다. nft -f 파일명으로 읽히거나, 파일 첫 줄에 셔뱅을 손으로 넣어야 한다.

ip6tables-translate 출력에 meta l4proto udp가 왜 붙나?

멀티포트 같은 포트 매칭은 프로토콜이 확정돼야 동작하기 때문에 도구가 meta l4proto udp를 udp dport 앞에 붙여 준다. 손으로 규칙을 옮길 때 이 부분을 빼면 실제 도구 출력과 달라지므로 출력을 그대로 복사하는 것이 안전하다.

적재 전에 문법만 검사할 수 있나?

nft -c -f 파일명을 쓰면 규칙을 적용하지 않고 문법만 검사한다. 아무 출력 없이 프롬프트가 돌아오면 문제가 없다는 뜻이고, 오류가 있으면 줄 번호와 함께 메시지를 출력한다.

ipset으로 관리하던 IP 목록은 어떻게 옮기나?

nftables의 named set으로 다시 쓴다. nft add set으로 set을 만들고 nft add element로 원소를 넣은 뒤 규칙에서 @set이름으로 참조한다. CIDR 범위를 담으려면 set 정의에 flags interval을 준다. 변환 도구가 set을 자동 생성하지는 않으므로 손으로 설계해야 한다.

관련 글

댓글 0

로그인 후 댓글을 남길 수 있습니다.

아직 댓글이 없습니다.