[ 글의 목적: linux에서 사용되는 "시스템 방화벽"을 이해하고 "가볍게 활용"하는 방법에 대한 기록, netfilter, iptables, ufw, nftables의 "가볍게 활용"하는 데에 초점이 맞춰져 있다. 특히 netfilter & iptables 이 중심이다. ]
Linux 커널의 내부의 네트워크 스택 관련 프레임 워크
Netfilter
가 존재한다. 네트워크 패킷의 흐름을 관리하고 패킷 필터링 규칙을 통해 네트워크 트래픽을 허용하거나 차단하는 역할이 핵심이다. 이를 이용하기 위해iptables
등이 있으며, 이와 같은 시스템 방화벽에 대해 알아보자!
사전에 네트워크 계층에 대한 이해도가 조금 필요합니다! 여기서 다루는 내용은 physical layer가 아닌 L3(패킷)
& L4(세그먼트)
계층에서의 network filtering 입니다.
각각의 프로토콜은 "hooks"라는 것을 정의하며, 패킷 프로토콜 스택의 packet's traversal(네트워크에서 패킷이 전송되는 과정들)에 정의된 "포인터"를 의미한다.
이러한 포인터에서, 각각의 프로토콜은 패킷과 훅넘버(hook number)를 이용하여 넷필터 프레임웍을 호출하게 된다. 따라서 패킷이 넷필터 프레임 워크를 통과할 때, 누가 그 프로토콜과 훅을 등록했는지 확인하게 된다.
등록되어 있다면, 등록된 순서대로 패킷을 검사하고, 패킷을 무시하거나(NF_DROP
), 통과시키고 (NF_ACCEPT
), 또는 패킷에 대한 것을 잊어버리도록 넷필터에게 지시하거나(NF_STOLEN
), 사용 자 공간에 패킷을 대기시키도록 넷필터에게 요청한다(NF_QUEUE
). 그 흐름을 크게 보면 아래 사진과 같다.
[ 위 사진은 hooking이 되는 지점을 말하며, 곧 handler를 세팅할 수 있는 부분이다. ]
DNAT
과 같은 패킷 변환을 수행하는데 사용된다.SNAT
과 같은 패킷 변환을 수행하는데 사용된다.로컬 시스템에서 생성된 패킷이 네트워크로 전송되기 전에 처리되는 훅이다. 로컬 시스템이 패킷을 생성하여 네트워크로 보내기 전에 적용되며, SNAT
과 같은 패킷 변환을 수행하는데 사용된다.
위 5가지 hook point 위치에서 패킷이 지나가는 경우 handler를 구현해서 원하는 action(함수 등)을 실행할 수 있게 설정할 수 있다. 그리고 아래 5가지 값 중 하나의 값을 return 해서 다음 action을 취할 수 있다.
(1) NF_DROP
: 현재 패킷을 Drop 한다.
(2) NF_ACCEPT
: 현재 패킷을 accept하고 다음 step으로 넘긴다.
(3) NF_STOLEN
: 현재 패킷을 커널이 잊어버린다. 그러면 패킷의 소유권을 얻고 직접 처리를 해야한다.
(4) NF_QUEUE
: 스택을 타지 않고 사용자 공간에 올린다.
(5) NF_REPEAT
: hook을 다시 호출!
리눅스에서 위 netfilter
를 사용하여 네트워크 패킷을 필터링하고 컨트롤하는데 사용되는 사용자 도구가 바로 iptables 이다. 즉, iptables는 netfilter를 다루기 위한 명령어 기반의 인터페이스를 제공하는 도구이다.
기본 사용 형태는 아래와 같다.
iptables [-t 테이블] [액션] [체인] [매치] [-j 타겟]
iptables
의 전체 흐름을 도식화한 그림이다. (조금 오래된 사진이지만 여전히 교과서적인 사진으로 남아있다 :))"table" 과 "chain" 을 통해 netfilter에 등록된 패킷 제어 룰을 관리한다. 각 테이블들은 특수한 목적을 가지고 있으며, 룰의 성격에 따라 어떤 테이블에 등록될지 결정한다.
각 테이블에 포함된 모든 패킷 제어 룰은 체인이라 불리는 그룹으로 묶어서 관리한다. iptables에 내장된 대표적인 체인들은 위에서 언급한 netfilter hook과 1:1 대응 관계에 있다.
각 테이블은 한 개 이상의 체인으로 구성 되며, 테이블의 성격에 따라 등록되는 체인의 종류에 차이가 있다.
NIC
(Network Interface Card)를 거쳐 들어온 패킷은 가장 먼저 NF_INET_PRE_ROUTING
훅이 실행된다. 이때, NF_INET_PRE_ROUTING
훅과 연관된PREROUTING
체인이 실행된다. PREROUTING
훅이 등록된 모든 테이블 중 "raw 테이블이 가장 먼저 적용"되어, 연결 상태를 제어하고 패킷에 마킹을 남긴다. 그 후, mangle nat(DNAT)
테이블을 각각 거쳐 라우팅 여부가 결정된다.
패킷이 "로컬 시스템을 향하는 경우"에는, NF_INET_LOCAL_IN
훅과 연관된 INPUT
체인이 실행된다. mangle
, filter
테이블에 등록된 INPUT
체인이 순서대로 적용되어 최종적으로 허용/거부 여부가 결정 된다.
만약, 패킷이 외부 호스트로 포워딩 되는 경우에는 NF_INET_FORWARD
훅과 연관된 FORWARD
체인이 실행된다. FORWARD
체인은 INPUT
체인과 동일하게 mangle
, filter
테이블 순으로 적용된다. 이후, mangle
, nat(DNAT)
테이블에 등록된 POSTROUTING
체인들이 순서대로 적용된다.
로컬 호스트에서 출발하는 패킷에는 가장 먼저 OUTPUT
체인이 적용된다. PREROUTING
체인과 유사하게, raw 테이블을 거쳐 연결 상태가 가장 먼저 마킹되며, mangle
, nat(DNAT)
, filter
테이블에 등록된 OUTPUT 체인이 순서대로 실행된다.
이 후, mangle
, nat(SNAT)
테이블에 등록된 POSTROUTING
체인을 거쳐 최종적으로 NIC
(Network Interface Card)를 통해 외부로 나가게 된다.
iptables
은 테이블과 체인을 통해 netfilter
에 등록된 패킷 제어 룰을 관리한다. 각 테이블에 포함된 모든 패킷 제어 룰은 체인(chain)이라 불리는 그룹으로 묶여서 관리한다. 그리고 체인은 netfilter hook과 1:1 대응 관계에 있다. 다시 한 번 가볍게 정리하면 아래와 같다.PREROUTING
: NF_INET_PRE_ROUTING
훅이 실행될 때, 적용된다.INPUT
: NF_INET_LOCAL_IN
훅이 실행될 때 적용된다.FORWARD
: NF_INET_FORWARD
훅이 실행될 때 적용된다.OUTPUT
: NF_INET_LOCAL_OUT
훅이 실행될 때 적용된다.POSTROUTING
: NF_INET_POST_ROUTING
훅이 실행될 때 적용된다.filter 테이블은 iptables의 기본(default) 테이블이다. 즉, 명령어에서 특정 table을 명시하지 않으면 기본적으로 세팅되는 테이블이다!
filter 테이블은 등록된 룰에 따라 들어오거나(incoming) 나가는(outgoing) 패킷의 허용/거부 여부를 결정하는 방화벽의 역할을 수행 한다.
nat 테이블은 이름처럼 주소 변환(network address translation
)을 담당한다.
nat 테이블은 등록된 룰에 따라 패킷의 출발지(source
) 혹은 목적지(destination
)를 조작하여 패킷을 라우팅하는 역할을 한다.
예를 들어, mangle 테이블에 규칙을 등록하면 패킷의 TTL 헤더를 조작하여 패킷이 거칠 수 있는 네트워크 홉의 수를 줄이거나 늘리는 것이 가능하다.
mangle 테이블은 패킷에 커널 mark
를 남길 수 있다. mark
는 패킷에 "직접적인 영향을 주진 않지만" 다른 테이블들에서 패킷 제어를 위해 추가적인 정보로서 활용할 수 있다. 즉, magling을 통해 내부적으로만 체크 가능한 값을 남겨 특정 판단이 가능하다는 의미다.
위 세 가지 테이블과는 조금 다른 성격을 가지고 있다. iptables는 연결 추적 기능(connection tracking)을 제공한다. 이 기능을 통해 시스템은 각 패킷이 속한 연결의 현재 상태를 파악한다.
iptables에서 "모든 connection은 상태를 가지며", iptables에 등록된 모든 규칙은 연결 상태에 영향을 받는다. 이 상태에는 NEW, ESTABLISHED, RELATED, INVALID 등이 있고 해당 상태는 아래와 같다.
NEW
: 새로운 연결을 시작하는 패킷ESTABLISHED
: 이미 시작된 연결의 패킷RELATED
: 기존 연결과 관련된 새로운 연결의 패킷INVALID
: 알 수 없거나 예상치 못한 상태의 패킷INVALID
상태에 놓인 connection에서 오는 패킷은 "유효하지 않은 것으로 간주"된다. raw 테이블은 이러한 연결 상태를 제어하고, 연결 상태를 "패킷에 마킹하는 고유한 역할을 수행"한다. 따라서, 특수한 목적이 아니고서야 raw 테이블을 직접 제어할 일은 많지 않다.SELinux
내부적으로 패킷에 security context
를 마킹하는 역할을 한다. security 테이블을 거쳐 생성된 마크는, SELinux에서 패킷을 제어하는데 영향을 준다. SELinux란?chain과 table세팅에 우리(사용자)가 추가하는 것은 바로 "규칙, Rule" 이다. 그렇기에 각 테이블에 등록되는 체인들은 한 개 이상의 룰(Rule)을 가지고 있다.
"Chain Traversal Order" 에 따라 특정 체인이 실행될 때, 해당 체인에 속한 룰이 순서대로 적용되며 크게 "두 파트(Matching, Target)" 로 구분된다.
matching은 룰을 적용하기 위한 "조건(criteria)에 해당하는 파트" 로 if 절의 조건에 해당한다고 볼 수 있다.
만약, 특정 패킷이 현재 룰의 matching 조건에 부합한(equal) 경우, target에 등록된 구체적인 행동(action)이 적용된다. 자세한 조건 및 옵션은 실습 section에서 다시 확인해 보자.
ACCEPT
, DROP
, REJECT
등이 포함된다. 예를 들어, 패킷이 DROP
타겟을 만나면, 그 패킷은 즉시 버려지며, 해당 체인의 다른 규칙은 더 이상 검토되지 않는다.LOG
, MARK
및 "사용자 지정 체인(체인 이름)"
등이 포함된다. 예를 들어, 패킷이 LOG
타겟을 만나면, 그 패킷에 대한 정보가 로그에 기록되지만, 패킷은 체인의 다음 규칙에 따라 계속 체크 된다.iptables [-t 테이블(table)] [액션(action)] [체인(chain)] [매치(matching)] [-j 타겟(target)]
table
자리는 위에서 언급한 것과 같이 filter
, nat
, mangle
, raw
가 올 수 있다.action
자리는 기본적으로 아래와 같은 옵션값이 온다.-A
: APPEND: 정책 추가-I
: INSERT: 정책 삽입-D
: DELETE: 정책 삭제-R
: REPLACE: 정책 교체-F
: FLUSH: 모든 정책 삭제-P
: POLICY: 기본 정책을 설정-L
: LIST: 정책 나열chain
자리는 INPUT
, OUTPUT
, FORWARD
, PREROUTING
, POSTROUTING
과 같이 어떤 훅에 적용할지를 넣을 수 있다.match, matching
자리는 다음과 같은 옵션값이 온다.-s
: 출발지 매칭. 도메인, IP 주소, 넷마스크 값을 이용하여 표기(––source, ––src)-d
: 목적지 매칭. 도메인, IP 주소, 넷마스크 값을 이용하여 표기(––destination, ––dst)-p
: 프로토콜과 매칭. TCP, UDP, ICMP 와 같은 이름을 사용하고 대소문자는 구분하지 않음-i
: 입력 인터페이스와 매칭(––in-interface)-o
: 출력 인터페이스와 매칭(––out-interface)-j
: 매치되는 패킷을 어떻게 처리할지 지정 (--jump)target
자리는 다음과 같은 옵션값이 온다.ACCEPT
: 패킷을 허용한다.DROP
: 패킷을 버린다(패킷이 전송된 적이 없던 것처럼, 응답 자체가 없다는 의미다.)REJECT
: 패킷을 버리고 이와 동시에 적절한 응답 패킷을 전송한다.(icmp-port-unreachable)LOG
: 패킷을 syslog에 기록한다.SNAT --to [주소]
: 소스 IP를 변환(NAT)한다.DNAT --to [주소]
: 목적지 IP를 변환(NAT)한다.RETURN
: 호출 체인 내에서 패킷 처리를 계속한다.# 열람하기
iptables -L
# 또는
cat /etc/sysconfig/iptables
# 저장하기
service iptables save
# 입출력 제어를 통해 아래와 같이 사용 가능
iptables-save > firewall.sh
iptables-restore < firewall.sh
iptables -A(또는 -I) INPUT 192.168.10.0/24 -j DROP
: 192.168.10. 대역으로부터 들어오는 패킷들은 차단하는 정책을 추가
iptables -P FORWARD DROP
& iptables -A FORWARD -i eth1 -j ACCEPT
: 패킷은 거부 메시지 없이 무조건 거절한다. (DROP), 두 번째 이더넷카드(eth1)로 들어오는 패킷인 경우에만 포워딩을 허가하며 어떠한 방화벽도 설정되어 있지 않고 커널에서 포워딩을 허가한 상태이다.
iptables –t nat –A POSTROUTING -o eth0 –j SNAT --to 203.247.40.100
: 해당 시스템에는 이더넷 카드가 두 개가 장착되어 있는데, 첫 번째 이더넷 카드에서 나가는 패킷에 대해 공인 IP 주소인 203.247.40.100을 할당한다.
iptables -A SSH -p udp --dport 22 -m recent --update--seconds 60 --hitcount 15 -j drop
: 대상 프로토콜 SSH, 같은 IP 주소에서 60초 동안에 15번 이상 접속을 시도하면 DROP시키는 정책을 추가한다.
iptables -A INPUT -p tcp --dport 80 -m recent --update --seconds 1 --hitcount 10 --name HTTP -j DROP
: 1초동안 80포트에 똑같은 IP가 10번 이상의 SYN가 들어오면 드랍시킨다.
cat domain-access_log |awk '{print $1}'|sort |uniq |awk '{print "iptables -A INPUT -s "$1" -j DROP"}'|/bin/bash
: domain-access_log 파일에 있는 모든 ip의 모든 접속 포트를 막아라(DOS공격 방어시 사용)!
ps) 리눅스마스터 1급 필기 및 실기 실제 기출 문제라고 한다 ㅎ
# TCP packet의 특정 port로 요청이 올때 Logging
sudo iptables -A INPUT -p tcp --dport [PORT_NUMBER] -j LOG
# UDP packet의 특정 port로 요청이 올때 Logging
sudo iptables -A INPUT -p udp --dport [PORT_NUMBER] -j LOG
# 특정 source로 요청이 올때 Logging
sudo iptables -A INPUT -s [SOURCE_IP_ADDRESS] -j LOG
# source & port 동시 사용
sudo iptables -A INPUT -s [SOURCE_IP_ADDRESS] -p tcp --dport [PORT_NUMBER] -j LOG
iptables도 역시 저수준이고, 접근성이 엄청 좋지는 않다. 그래서 ubuntu에서는 iptables의 작업을 간편화해주는 S/W 인 Uncomplicated FireWall, "복잡하지 않은 방화벽" - UFW
가 등장했다.
즉 ufw
는 iptables을 이용한 Frontend tool에 가깝고, nftables
(nework filter tables)은 iptables을 대신하는 차세대 tool이라고 볼 수 있다. 유저가 사용하기 편한 형태로 구성되어 있다.
GPL(GNU General Public License)이 적용되며 파이썬(python)으로 개발되었다. ufw는 기본적으로 ubuntu 18.04 LTS 이후 버전에서 사용할 수 있다.
ufw를 세팅하면 기본적으로 모든 들어오는 연결을 차단하고, 모든 나가는 연결을 허용하는 정책을 적용한다.
# ufw 상태 조회
sudo ufw status verbose
# ufw 활성화 / 비활성화
sudo ufw enable / disable
# ufw default rules 조회
sudo ufw show raw
sudo cat /etc/ufw/user.rules # 이를 통해 세부룰에 대한 내용 확인 가능
# ufw default rules 허용 / 차단
sudo ufw default allow / deny
# TCP 8080 포트(port) 허용 / 차단
sudo ufw allow / deny 8080/tcp
# TCP 8080 port 차단 rule 삭제
sudo ufw delete deny 8080/tcp
# SSH service 허용 / 차단
sudo ufw allow / deny ssh
# 특정 IP address subnet(net mask) 허용
sudo ufw allow from 192.168.10.0/24
# 특정 IP address와 port 허용
sudo ufw allow from 192.168.10.20 to any port 22
# 특정 IP address와 port, protocol 차단
sudo ufw deny from 192.168.10.20 to any port 22 proto tcp
사실 nftables
는 ufw
와는 결이 조금 다르다. ufw
는 철저하게 쉬운 사용성이 초점이 맞춰져 있지만 nftables
는 Linux 3.13 이후의 커널에서 사용할 수 있는 패킷 분류 프레임워크이다.
즉 iptables
, ip6tables
, arptables
, 및 ebtables
의 후속 작업으로 개발되었으며, 이러한 도구들의 대체제로 설계되었다. 새로운 문법 및 향상된 기능 제공하며 맵, 집합, 연결 추적과 같은 고급 데이터 구조를 지원하는 특성을 가졌다. 그리고 현재 iptables를 메인테이닝하고 있는 것과 동일한 조직(단체)인 "Netfilter"에 의해 개발되었다. iptables의 문제점, 즉 확장성과 성능에 대한 해결책으로 만들어졌다.
그렇기 때문에 우린 netfilter
와 iptables
같은 태초에 가까운 프레임워크에 대해 이해를 해두는 것이 이런 새로운 프레임워크 및 툴에 익숙해지기 쉽다. 어짜피 "L3 & L4 이상에서 NIC를 거쳐 들어온 패킷을 netfilter
규칙하에 다룬다는 본질은 쉽게 변하지 않을 것" 이다.
레드헷 디벨로퍼: Benchmarking nftables 글을 보면 nftables 을 벤치마킹하여 상대적인 퍼포먼스 체크를 보여준다. 그리고 하기 내용은 대부분 레드헷: 10장. nftables 시작하기 에서 발췌 했다.
table
, chain
, rule
등과 같이 iptables
가 가지는 구성을 모두 가지고 있다. nft
이라는 "자체 문법", 새로운 전용 문법, 일관된 문법을 사용한다.가장 다르다고 느꼇던 부분은 바로 "table"에 대한 관점이다. nft 명령은 테이블 및 체인을 미리 만들지 않는다. 이는 사용자가 수동으로 생성한 경우에만 존재한다.
즉 기본적인 nftables
사용법은 아래와 같다.
nft add table ip mytable # mytable 이라는 사용자 커스텀 테이블 생성
# 생성한 table에 chin 추가
nft add chain ip mytable input { type filter hook input priority 0 \; }
# SSH 및 HTTP 트래픽을 허용하고 나머지는 차단
nft add rule ip mytable input tcp dport 22 accept
nft add rule ip mytable input tcp dport 80 accept
nft add rule ip mytable input drop
# 규칙 세트 확인
nft list ruleset
이렇게 세팅한 규칙은 "즉시 구성에 추가되며 동시에 네트워크 트래픽에 대한 패킷 필터링이 즉시 시작" 된다. 그렇기 때문에 모든 패킷을 막기전에 꼭 유의하는게 좋다.
위에서 iptables로 세팅한 "같은 IP 주소에서 60초 동안 15번 이상 SSH 접속을 시도하면 DROP" 규칙을 nftables
로 표현하면 아래와 같다.
# 테이블 생성
nft add table ip filter
# input 체인 추가
nft add chain ip filter input { type filter hook input priority 0 \; }
# SSH 접속 시도 제한 규칙 추가
nft add rule ip filter input tcp dport 22 ct state new ct rate 15/minute drop
# 그 외에 SSH 연결 허용
nft add rule ip filter input tcp dport 22 accept
ct rate 15/minute drop
부분이 실제로 연결 비율을 제한한다. 이 규칙은 새로운 SSH 연결 시도가 분당 15회를 초과하면 해당 패킷을 DROP한다고 세팅되어 있다.
릴리즈 되어 적용된게 2014년도 인데 생각보다 레퍼런스가 많지 않으며 특히 한국어 레퍼런스는 거의 전무한 것 같다. 아무래도 iptables에 너무 익숙하기도 하고, 대게 iptables 정도로 만족하면서 쓰기 때문이다. 더욱이 볼륨이 있는 기업이라면 찐퍼포먼스를 위해 오히려 Hardware level에서 Upgrade 하는 경우도 많기 때문에..
firewalld
세팅을 할 일이 있어 같이 정리를 하려고 했으나 내용이 꽤 방대해서 다음으로 미룬다..