서비스를 통신사급 NAT 뒤의 노트북에 두고, 그 노트북을 VPN을 통해 VPS로 향하게 하면 외부에서는 아무도 접근할 수 없습니다. VPS에 목적지 NAT 규칙을 추가하면 침묵보다 나쁜 것을 얻습니다. 연결은 열리지만 곧 멈춥니다. 응답이 없는 것이 아니라 클라이언트 자신의 기본 경로로 빠져나가고 있어, 서버는 그 응답을 결코 보지 못합니다. 이 다섯 가지 점검을 순서대로 수행하고 처음으로 성립하지 않는 곳에서 멈추세요.

서버가 애초에 전달할지 확인하세요

번역을 한 줄이라도 쓰기 전에 이 칸을 표시하세요. 커널이 전달을 거부하는 패킷에 대한 DNAT 규칙은 규칙 파서가 받아들이고 나서 전달 경로가 버리므로, 방화벽 문제처럼 보이는 시간 초과가 생깁니다.

sysctl net.ipv4.ip_forward
sysctl -w net.ipv4.ip_forward=1

실행 중인 커널에서 설정하는 것과 재부팅을 넘겨 설정하는 것은 같지 않습니다. net.ipv4.ip_forward=1 을 /etc/sysctl.d/ 아래 파일에 쓰고, sysctl --system 을 실행한 다음, 파일이 반영되었다고 믿는 대신 값을 다시 읽으세요. 자체 네트워크 네임스페이스를 관리하는 컨테이너는 호스트뿐 아니라 그 네임스페이스 안에서도 같은 값이 필요합니다.

다시 읽어도 여전히 영이라면 여기서 멈추세요. 아래쪽은 아무것도 동작하지 않습니다.

어떤 규칙이 참조하기 전에 터널 주소를 고정하세요

풀은 연결 순서대로 주소를 나눠 주므로 오늘의 임대를 위해 쓴 규칙이 다음 주에는 조용히 다른 클라이언트를 가리킬 수 있습니다. 주소를 도착 순서가 아니라 인증서 신원에 묶으세요.

client-config-dir /etc/openvpn/ccd
ifconfig-push 10.77.0.14 10.77.0.13

그 쌍은 지점 간 터널의 클라이언트 끝과 피어 끝이며, 서버는 인증서의 공통 이름에 키가 맞춰집니다. 서브넷 토폴로지에서는 두 번째 값이 대신 넷마스크로 읽히므로 사용 중인 토폴로지에 맞는 형식을 쓰세요. 그런 다음 클라이언트를 다시 연결하고 주소는 클라이언트 자체에서 읽으세요. 서버가 풀을 보는 시점은 클라이언트가 설정한 내용의 증거가 아닙니다.

다시 연결한 뒤 주소가 바뀐다면 멈추세요. 움직이는 목표를 따라가는 NAT 규칙은 간헐적으로 실패하며 아무것도 가르쳐 주지 않습니다.

양방향으로 변환하세요

목적지 변환은 들어오는 패킷을 클라이언트로 보냅니다. 출발지 변환이야말로 클라이언트가 원래 보낸 이가 아니라 서버에 응답하게 만드는 것이며, 사람들이 빠뜨리는 규칙입니다.

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 29443 -j DNAT --to-destination 10.77.0.14:29443
iptables -t nat -A POSTROUTING -d 10.77.0.14 -p tcp --dport 29443 -j SNAT --to-source 10.77.0.13

두 번째 규칙이 없으면 클라이언트는 ISP 상향 링크로 응답하므로, 원격 피어는 한 번도 대화한 적 없는 출발지 주소를 보게 되고 서버에는 응답에 대한 추적 항목이 남지 않습니다. 외부 관찰자는 절반만 완료되는 핸드셰이크를 보게 되며, 그것이 바로 존재하지 않는 방화벽 버그를 찾아 나서게 만드는 증상입니다.

iptables -t nat -S 으로 두 규칙을 다시 읽고 인터페이스 이름이 공용 주소를 지닌 것인지 확인하세요. 이미 nftables로 필터링하는 호스트에서는 도구를 섞는 대신 해당 주소 체계의 nftables NAT 체인에 변환을 쓰세요.

필터 테이블을 통과시키세요

NAT 테이블은 헤더를 다시 쓰지만 허가를 주지는 않습니다. 기본 DROP 정책에서는 전달되는 흐름에 자체 허용이 필요하고, 되돌아오는 방향은 대부분의 정책이 이미 established,related 규칙으로 덮고 있습니다.

iptables -A FORWARD -i eth0 -o tun0 -p tcp --dport 29443 -m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

무엇이든 추가하기 전에 FORWARD 체인의 정책을 확인하세요. 이른 DROP의 순서가 당신의 규칙이 조회될지를 결정하기 때문입니다. 필터링이 nftables에 있는 호스트에서는 동등한 규칙을 inet 테이블의 forward 훅에 추가하고, 기본 체인이 로컬 입력만이 아니라 전달 트래픽을 실제로 보는지 확인하세요. 새 규칙의 패킷 카운터가 영에 머무는데 NAT 카운터가 오른다면, 패킷은 당신의 규칙 앞에서 버려지고 있습니다. 그것은 체인 순서를 읽으라는 신호이며, 같은 규칙을 두 번째로 복사해 넣으라는 신호가 아닙니다.

외부 네트워크에서 증명하세요

무관한 네트워크에서 시험하세요. 같은 LAN의 다른 머신에서 보낸 검사는 헤어핀 NAT 지원을 통과할 수 있고 원격 클라이언트가 쓰는 경로를 한 번도 지나지 않으므로, 그곳의 초록 결과는 틀린 것을 증명합니다.

tcpdump -ni any port 29443
conntrack -L | grep 29443

서버와 클라이언트에서 동시에 캡처를 실행하세요. 서버 캡처는 변환된 패킷이 터널 쪽으로 나가는지 보여 주고, 클라이언트 캡처는 요청이 도착하는지와 응답이 어디로 향하는지 보여 줍니다. conntrack -L 의 변환 항목은 규칙이 일치했음을 증명하고, 그 부재는 패킷이 NAT 체인에 도달하지 않았음을 증명합니다.

포트 스캐너는 약한 증거입니다. 애플리케이션이 바인딩되어 대기할 때까지 포트를 닫힌 것으로 보고하므로 실제 서비스에 실제 연결을 사용하세요. 마침내 동작하면 노출은 그 하나의 포트로 유지하세요. 첫 규칙이 어색했다고 SSH나 관리 패널까지 전달하는 것은 서비스를 게시하는 것보다 훨씬 큰 결정입니다.

관련 글