network / knowledge
기본 정책을 DROP으로 두는 iptables 구성
VPN 서버는 공인 IP로 열려 있다. 필요한 것만 열고 나머지는 막는 쪽이 낫다. 규칙을 하나씩 막는 게 아니라 기본을 막아두고 필요한 것만 여는 순서로 짰다.
# 기본 정책
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# Loopback
iptables -A INPUT -i lo -j ACCEPT
# 이미 성립된 연결
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# WireGuard 포트
iptables -A INPUT -p udp --dport 51820 -j ACCEPT
# 터널 안 트래픽만 포워딩 허용
iptables -A FORWARD -i wg0 -s 10.7.0.0/24 -j ACCEPT
iptables -A FORWARD -o wg0 -d 10.7.0.0/24 -j ACCEPT
# NAT
iptables -t nat -A POSTROUTING -s 10.7.0.0/24 ! -d 10.7.0.0/24 -j MASQUERADE
# 걸린 것 기록
iptables -A INPUT -j LOG --log-prefix "INPUT DROP: "
iptables -A FORWARD -j LOG --log-prefix "FORWARD DROP: "
순서가 곧 규칙이다
iptables는 위에서부터 훑다가 처음 걸리는 규칙에서 끝난다. 그래서 순서가 의미를 바꾼다.
loopback을 맨 앞에 둔다. 이걸 빼먹고 INPUT을 DROP으로 두면 서버 자기 자신에게 붙는 것들이 전부 죽는다. 로컬에서 도는 서비스끼리의 통신도 여기 걸린다.
conntrack이 그 다음이다. 이미 성립된 연결에 속하는 패킷은 뒤의 규칙을 볼 필요 없이 통과시킨다. 나가는 요청에 대한 응답이 여기서 걸러지므로, OUTBOUND에 대응하는 INPUT 규칙을 일일이 쓰지 않아도 된다. 앞쪽에 둘수록 뒤의 규칙을 덜 훑으니 성능에도 낫다.
FORWARD를 출발지/목적지까지 붙여 좁혔다. 앞선 구성에서는 -i wg0 만으로 열었는데, 여기서는 -s 10.7.0.0/24 를 함께 걸었다. wg0으로 들어오되 출발지가 터널 대역인 것만 통과시킨다는 뜻이다. 조건이 하나 더 있으면 그만큼 덜 열린다.
LOG는 맨 마지막에
iptables -A INPUT -j LOG --log-prefix "INPUT DROP: "
앞의 규칙 어디에도 안 걸린 패킷이 여기까지 온다. 그 다음 기본 정책 DROP으로 떨어진다. 그래서 이 LOG에 찍히는 건 곧 버려진 것들이다.
--log-prefix 로 태그를 붙여두면 syslog에서 골라내기 쉽다. 뭔가 안 될 때 여기부터 본다. 규칙을 빠뜨렸으면 그 패킷이 여기 찍힌다.
로그가 계속 쌓이므로 문제를 잡고 나면 빼거나 rate limit을 거는 편이 낫다.