리눅스에서 iptables를 사용하면서 필요한 부분입니다.
iptables?
리눅스상에서 방화벽을 설정하는 도구로서 리눅스 2.4버전 이전에 사용되던 ipchains를 대신하는 방화벽 도구입니다.
커널상에서의 netfilter 패킷필터링 기능을 사용자 공간에서 제어하는 수준으로 사용할 수 있습니다.
시나리오
제가 겪었던 이슈는 두 가지로 다음과 같습니다.
- 서비스 포트를 변경하여도 이전 포트가 계속 접속이 됨
- 서비스 포트를 변경하고 lwp request로 서비스가 살아있는지 체크하면 connection refused를 받게 됨
원인파악
-
서비스 포트를 변경하여도 이전 포트가 계속 접속이 됨
- 예를 들어, 앱을 구동시키면 떠있는 디폴트 포트가 8443이라고 합시다. 저의 경우는 서비스상에서 포트번호 변경서비스가 있기 때문에 포트번호를 8445로 변경합니다. 그러면 iptables에서 8445로 접속되는 포트는 8443으로 redirect시키게 됩니다. 실제로 포트번호를 변경하는게 아니라 톰캣을 재구동할 필요없이 redirect시켜서 8445포트로만 접속되게 하는 방법입니다. 완벽하게 포트번호를 변경한거첨 보이려면 오로지 8445로만 접속이 되게 8443은 더이상 접속되지 않아야 하겠죠? 하지만 기존 스크립트에서는 iptables nat테이블에서 8443을 DROP시키고 있었습니다. 그리고 iptables의 기본 정책은 nat 테이블은 필터링을 위해 사용되지않기 때문에 DROP 사용은 금지되고 있습니다.
-
서비스 포트를 변경하고 lwp request로 서비스가 살아있는지 체크하면 connection refused를 받게 됨
- 서비스를 헬스체크하는 모니터링 기능이 있는 경우, 내부에서 lwp request를 보내 서비스가 살아있는지 확인하게 됩니다. 기존 iptables에서는 외부 인터페이스의 8445로 들어오는 패킷들을 8443으로 redirect 시킬수 있었지만, 내부에서 8445포트로 쏘는 패킷들은 redirect하지 않는것을 발견했습니다.
해결
우선 포트번호를 변경하였을 때, iptables에서 redirect할 수 있는 명령어를 보겠습니다.
기존 디폴트 포트가 8443이고 변경 포트가 8445인 경우
iptables -t nat -A PREROUTING -p tcp -d 195.33.1.38 --dport 8445 -j REDIRECT --to-ports 8443
위와 같이 명령어를 작성하면 iptables의 nat에 PREROUTING chain에 추가된 정책을 볼 수 있습니다.
위의 정책이 nat테이블에 추가되면 이제 8445 포트로도 접속이 가능합니다. 하지만 문제는 8443으로도 계속 접속이 가능한 것이었습니다. 이 문제를 해결하기 위해 다음과 같은 명령어가 필요합니다.
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 8443 -j MARK --set-mark 1
iptables -A INPUT -m mark --mark 1 -j DROP
간단히 설명하면 mangle 테이블에 8443으로 들어오는 패킷들을 mark 하는 정책을 추가하고
filter 테이블에서 마크 되어있는 패킷들을 DROP시킵니다.
iptables에서 table 순서는 크게 보면 nat > mangle > filter 순서로 적용됩니다. 그리고 각 테이블은 등록된 정책과 들어온 패킷들을 비교하며 순차적으로 확인하면서 내려갑니다. 따라서 저희가 추가한 정책들로 보자면 8443이 들어왔을 때 mangle table에 추가된 8443포트로 들어오는 패킷들에 마크를 하라는 정책에 따라 패킷들이 마킹됩니다. 그 후, filter table에서 마킹된 패킷들을 DROP하라는 정책에 따라 그 패킷들을 DROP시킵니다. 결국, 사용자는 8445포트로만 서비스를 이요할 수 있게 됩니다.
다음은 내부에서 lwp request를 보낼 시에 connection refused가 나오는 상황을 해결하기 위한 명령어입니다.
iptables -t nat -A OUTPUT -p tcp -o lo --dport 8445 -j REDIRECT --to-ports 8443
nat table에 ouput 정책을 추가합니다. -o 옵션은 OUTPUT일 때만 쓸 수 있는 옵션인데 lo로 지정해 놓으면 loopback 인터페이스로 들어오는 모든 패킷을 검사할 수 있습니다. 리눅스 서버를 목적지로 삼는 모든 패킷은 INPUT chain을 통과하고 리눅스 서버에서 생성되어 보내지는 모든 패킷은 OUTPUT Chain을 통과하기 때문에 OUTPUT chain에 정책을 추가해야 합니다. 따라서 내부에서 보내지는 패킷들도 모두 검사하여 REDIRECT해줍니다.
그 외
옵션과 기본 명령어
- -N : 새로운 체인을 만듬
- -L : 새로운 규칙을 출력
- -X : 비어 있는 체인 삭제
- -P : 기본 정책을 변경
- -F : 체인의 모든 규칙을 삭제
- -A : 새로운 규칙을 추가(맨 아래에 추가됨)
- -I : 새로운 규칙을 삽입(맨 앞쪽에 삽입됨)
- -R : 새로운 규칙을 교체
- -D : 규칙을 삭제
- -C : 패킷을 테스트
간단한 iptables 조회
iptables -nvL
table의 리스트를 보여줌
iptables -t nat -L
iptables -t mangle -L
iptables -t filter -L
각 룰셋의 적용순서까지 확인 가능
iptables -nL --line-numbers
정책 순서
모든 방화벽은 순차적 실행으로 등록 순서가 중요합니다.
등록 순서에 있어서 먼저 등록한 부분에 대해서 효력이 유효하기 때문에 등록시에 순서가 중요합니다. 즉, 모든 입출력 패킷에 대해 거부하는 설정이 먼저 등록되면 그 이후에 포트를 열어주는 설정을 하여도 효과가 없습니다. 그러므로 허용하는 정책을 먼저 정의한 다음 거부하는 정책을 허용하는 것이 좋습니다.
packet flow diagram
network상에서 패킷이 iptables의 table과 chain들을 어떻게 지나가는지에 대한 flow diagram입니다.