Iptables 를 알아보기 전에 먼저 Netfilter 에 대해 알아보죠 !
Netfilter 와 Iptables
AWS EC2 인스턴스를 생성할 때 Security Group 이라는 것을 설정합니다. 이름 그대로 외부로 들어오는 트래픽을 조절할 수 있게 해주는 방화벽 기능이죠. EC2 인스턴스 앞단에 이를 처리해주는 아마 물리적인 기계가 있어서 어떤 트래픽은 허용하고, 어떤 트래픽은 거부하겠죠.
Security Group 이 하드웨어 방화벽 이라면 Netfilter 는 소프트웨어 방화벽이라고 생각하면 이해하기 쉽습니다.
Netfilter 는 다음과 같은 특징이 있습니다.
- 소프트웨어 방화벽
- 패킷 필터링
- 리눅스 커널 내부의 프레임워크
- 포트 주소, 변환, 포트 포워딩 및 패킷 변경
- 라우팅 전후에 데이터 및 IP 패킷 헤더 변경
그치만 위와 같은 기능을 사용할 때 Netfilter 에 직접 접근하지 않고, 어떤 소프트웨어를 사용해서 변경하는데 이때 사용하는 것이 바로 Iptables 입니다.
즉, Iptables 는 Netfilter 를 컨트롤하는 소프트웨어라고 생각하면 됩니다.
헷갈리시다면, Iptables 과 Netfilter 를 동일시 생각해도 크게 이 글을 이해하는데 지장은 없을 겁니다 😀
Netfilter Chains
Netfilter 에는 다음과 같이 5 개의 Chains 라는 것이 존재합니다.
Input
- 들어오는 패킷을 허용하거나 거부(Drop)
- 호스트로 들어오는 모든 패킷은 예외없이 Input 규칙을 따름
- Input 규칙을 건너뛸 수 있는 패킷은 없음
$ iptables -t filter -A INPUT -p icmp -j DROP
# 들어오는 모든 icmp 를 DROP 한다
# ping 을 iptables 를 적용한 호스트로 보내면 응답이 오지 않는다
Output
- 나가는 패킷을 허용하거나 거부(Drop)
- 호스트가 Source 가 됨
$ iptables -t filter -A OUTPUT -d netfilter.org -j DROP
# 호스트에서 netfilter.org 로 나가는 모든 패킷은 드롭된다
이외 Prerouting, Forward, PostRouting 가 존재하는데 이는 좀 더 뒤에서 다루도록 하죠 🧐
Netfilter Tables
Netfilter 에선 Chain 말고 Table 라는 것을 사용하는데 총 4가지가 존재합니다.
Iptables 에서 생성한 룰을 정의하는 Table 이죠.
filter
- iptables 에서 가장 널리 사용되는 테이블
- 모든 작업이 일반적으로 방화벽과 연결되는 곳
- 여기서 패킷을 허용할지 거부할지 정함
$ iptables -A INPUT -p tcp --dport 22 -s 5.3.6.6 -j ACCEPT
$ iptables -A INPUT -p tcp --dport 22 -j DROP
# 체인은 등록된 순서로 작동한다
# 5.3.6.6:22 의 패킷만 허용된다
# 하지만 두번째 체인에서 22 포트로 오는 패킷은 어떤 IP 든 드롭된다
nat
- DNAT, SNAT 관련 룰을 정의함
나머지 mangle 과 raw 테이블은 다루지 않겠습니다.. 사용했던 적이 없어요.. 😅
기본적인 Command
Iptables 를 사용하기 위해선 iptables 라는 명령어를 사용합니다. 아래와 같이 말이죠.
$ iptables -vnL
핵심 Command 만 한번 알아보죠 !
참고: iptables 명령어는 root 계정만 가능합니다
참고: -t nat 와 같이 table 을 지정하지 않으면 자동으로 filter 를 사용합니다
L 옵션
iptables 에 존재하는 Rule 을 리스트합니다.
$ iptables -L
# 리스트를 보여줌
$ iptables -vnL
# 더 자세하게 보여줌
# -v : verbose
# -n : numberic
A 옵션
iptables 에 Rule 을 추가하는 옵션입니다.
$ iptables -A INPUT -p tcp --dport 80 -j DROP
# 80 포트로 들어오는 패킷을 드롭함
$ iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
# 8080 포트로 들어오는 패킷은 허용함
$ iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# 규칙은 위에서 아래로 적용되기 때문에 첫번째 규칙에 의해 DROP 되어
# 이 규칙은 사실상 무의미함
I 옵션
A 옵션과 똑같이 규칙을 추가하지만 A 옵션 같은 경우는 뒤에서 추가하고, I 옵션 같은 경우는 첫번째에서 추가합니다.
다음 이미지를 보면 이해하기 쉽습니다.
현재 80 포트를 DROP 하는 규칙이 한개 있습니다. 이때 I 옵션을 사용한다면 DROP 규칙 아래가 아닌 위에 생성되게 됩니다.
$ iptables -A INPUT -p tcp --dport 80 -j DROP
$ iptables -I INPUT -p tcp --dport 80 -j ACCEPT
아래가 아닌 위에 생긴 것을 볼 수 있습니다.
전에 이야기했지만 규칙은 위에서 아래로 적용되기 때문에 이런 경우 80 포트는 들어오는 트래픽은 무조건 허용됩니다.
F 옵션
그럼 위에서 추가한 규칙을 다 삭제해보죠!
$ iptables -F
규칙이 다 삭제(Flush) 된 것을 볼 수 있습니다.
그럼 이제 예제를 통해 지금까지 배운 걸 활용해보죠 😎
기본 예제
Case 1) 80 포트로 들어오는 트래픽을 모두 거부하자!
현재 Host 에서 80 포트는 Nginx 프로세스입니다.
Client 에서 curl 를 이용해서 Host 의 Nginx 에 접근해보죠 !
무리없이 응답을 받고 있습니다. 그럼 이를 거부하는 Rule 을 추가해보죠!
Host 로 이동해서 아래와 같은 명령어를 실행합니다.
$ iptables -A INPUT -p tcp --dport 80 -j DROP
# -p : protocol
# 포트는 L4 이후부터 가능하므로 -p tcp 라는 옵션을 추가해주어야 함
80 포트로 들어오는 모든 트래픽을 DROP 했기 때문에 curl 을 해도 응답이 오질 않습니다.
그럼 다시 이를 ACCEPT 할 수 있게 새로운 규칙을 추가해보죠! 어떤 옵션을 쓰면 될까요?
Case 2) -F 를 사용하지 않고 80 포트를 다시 허용해주자!
감이 오시나요? 맞습니다. I 옵션을 사용하면 됩니다.
$ iptables -I INPUT -p tcp --dport 80 -j ACCEPT
그럼 다시 curl 를 보내볼까요?
DROP 되는 규칙이 있긴 하지만 계속 이야기하다시피 규칙은 위에서 아래로 읽기 때문에 ACCEPT 가 되는 걸 알 수 있습니다 🤟
그럼 좀 더 심화된 기능을 알아보죠 !
DNAT 과 SNAT 그리고 MASQUERADE
iptables 의 핵심 기능이라고 볼 수 있습니다.
DNAT 과 SNAT 을 이해하기 위해선 우선 NAT 이라는 개념을 알아야 합니다.
NAT 은 Network Address Translation 의 약자로 이름 그대로 Network 주소를 변환하는 기술을 말합니다.
NAT 에 관한 글은 아니니 자세한 건 여기를 참고해주세요 !
DNAT 의 D 는 Destination, SNAT 의 S 는 Source 를 의미하며 DNAT 은 Destination 의 주소를 변환하고, SNAT 은 Source 의 주소를 변환합니다.
DNAT 은 항상 PREROUTING 체인 규칙을 사용해야하며, SNAT 은 항상 POSTROUTING 체인 규칙을 사용해야 합니다.
그럼 이제 MASQUERADE 에 대해 알아보죠!
MASQUERADE 는 SNAT 의 일종이며 SNAT 과 다르게 동적으로 소스 IP 를 처리할 수 있도록 해줍니다.
때문에 보통 SNAT 보단 MASQUERADE 를 통해서 규칙을 지정하는게 편리합니다.
이제 이해가 잘안되신다구요?
그럼 예제를 통해 한번 알아보죠!
심화 예제 - iptables 을 이용하여 로드밸런서를 만들어보자!
iptables 를 사용하면 로드밸런싱을 쉽게 구현할 수 있습니다. 그럼 바로 가보죠! 🤟
기능은 아주 간단합니다. Load Balancer 에 3000 포트로 접근하면 Server A 로 가고, 3010 포트로 접근하면 Server B 로 갑니다.
그럼 우선 Server A 와 Server B 에 요청을 보내면 무슨 응답이 오는지 확인해보죠.
둘 다 ok 가 응답으로 오는 아주 간단한 서버입니다.
그럼 이제 직접 Server A 와 Server B 에 요청하는 것이 아닌 Load Balancer 를 통해 요청을 보내보죠!
그 전에 우선 Route 기능을 활성화해줍니다.
echo "1" > /proc/sys/net/ipv4/ip_forward
이후 다음과 같이 Load Balancer 용도의 Host 에 추가합니다.
$ iptables -t nat -A PREROUTING -p tcp --dport 3000 -j DNAT --to-destination 54.180.126.167:9090
# 3000 으로 들어오는 트래픽은 54.180.126.167:9090 로 나감
$ iptables -t nat -A PREROUTING -p tcp --dport 3010 -j DNAT --to-destination 54.180.126.167:4040
# 3010 으로 들어오는 트래픽은 54.180.126.167:4040 로 나감
$ iptables -t nat -A POSTROUTING -j MASQUERADE
# Host 를 나갈 때 Source IP 또한 MASQUERADE 로 자동으로 변환함
모든 준비는 끝났습니다. 그럼 한번 Load Balancer 에 접근해보죠 😎
성공적입니다!
사실 Load Balancer 라고 하기에 기능이 많이 부족하지만 좀 손보면 충분히 만들 수 있을거 같습니다.
지금까지 긴 글 읽어주셔서 감사합니다 😄
'겉핥기 시리즈' 카테고리의 다른 글
[겉핥기 시리즈] k8s의 리소스를 위해 치얼스 - Helm 편 (0) | 2022.12.21 |
---|