전체 터널 OpenVPN: 서버 쪽에 인터넷 출구 추가하기
기본 경로를 밀어 넣는 것은 전체 터널 서비스의 절반일 뿐이다. 서버에는 전달, 범위를 좁힌 전달 규칙, 풀로 돌아가는 경로도 필요하다.
클라이언트가 인증을 마치고 풀에서 주소를 받아 VPN 호스트의 서비스에 도달하지만, 모든 공용 목적지는 시간 초과로 끝난다. 출구가 없는 터널은 이렇게 보이며, 네 가지 별개의 조건이 갖춰질 때까지 그대로 유지된다. 클라이언트가 기본 경로를 받아들여야 하고, 서버가 전달해야 하며, 방화벽이 통과를 허용해야 하고, 응답이 풀로 돌아갈 경로가 있어야 한다. 네 가지 실패는 모두 같은 증상을 공유하므로, 시도마다 하나씩만 바꾸고 결과를 기록하자.
기본 경로를 밀어 넣고 클라이언트가 무엇을 설치했는지 확인한다
서버 쪽 한 줄은 짧고, 밀어 넣은 옵션을 받아들이는 클라이언트에만 영향을 준다. def1 형식은 기존 기본 경로를 지우는 대신 반쪽 기본 경로 두 개를 설치하므로, 현재 연결을 살려 두면서도 모든 목적지를 잡아낸다.
push "redirect-gateway def1"
다시 연결한 뒤에는 프로필을 믿지 말고 클라이언트의 라우팅 테이블을 읽는다. Linux에서는 두 개의 /1 항목이 원래 기본 경로 옆에 나타나고, Windows는 같은 쌍을 0.0.0.0/1과 128.0.0.0/1로 보여 준다. 밀어 넣은 옵션을 무시하는 클라이언트, 또는 이를 거부하도록 설정된 클라이언트는 예전 기본 경로를 그대로 두고 인터넷 트래픽을 터널로 보내지 않는다. 서버 쪽 어떤 규칙도 이를 메울 수 없으므로, 서버에서 무엇이든 바꾸기 전에 이 문제를 정리하자.
전달은 서버 설정이지 VPN 설정이 아니다
라우팅을 건드리기 전에 전달 플래그를 읽는다. 그 값이 영이면 커널이 클라이언트의 패킷을 받고도 넘겨주지 않는다는 뜻이며, 이는 먼 쪽에서 본 방화벽 차단과 똑같이 보인다. 값은 시스템 설정 디렉터리를 통해 지정해 재부팅 후에도 남게 한다.
sysctl net.ipv4.ip_forward
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-vpn-forward.conf
sudo sysctl --system
다음으로 호스트 자체가 인터넷 출구로 가는 동작하는 경로를 갖는지 확인한다. 서버 셸에서 보낸 요청은 상위 경로가 쓸 만하다는 것만 증명하고 클라이언트 패킷의 전달에 대해서는 아무 말도 하지 않으므로, 둘을 별개의 시험으로 다루자. 서버가 목적지에 닿지 못하면 전달 설정을 아무리 더해도 소용없다.
의도한 통과만 허용하고 그 밖의 것은 허용하지 않는다
전달된 패킷은 forward 경로를 지나고, VPN 호스트 자체로 향하는 트래픽은 input 경로를 지난다. 이는 서로 다른 결정이며, input 경로를 여는 것이 기기를 통과하는 일을 허용하지는 않는다. 둘을 뒤섞는 것이 방화벽이 모든 것을 허용하는 것처럼 보이는데도 클라이언트가 계속 시간 초과에 빠지는 가장 흔한 이유다.
최소 정책은 풀에서 출구 인터페이스 쪽으로 가는 새 연결을 허용하고, 이미 성립된 흐름에 속한 응답을 허용한다. 부팅할 때마다 중복 규칙을 덧붙이지 말고, 배포판이 쓰는 규칙 집합 관리 지점에 넣자. 중복 규칙은 쌓이고 카운터는 의미를 잃는다.
sudo iptables -A FORWARD -i tun0 -o eth0 -s 10.90.0.0/24 -j ACCEPT
sudo iptables -A FORWARD -i eth0 -o tun0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
모든 체인을 허용으로 바꾸면 시험은 통과하지만 방화벽이 존재할 이유가 사라진다. 범위는 풀과 출구 인터페이스로 좁히고, 무관한 전달은 그대로 두자.
응답이 돌아갈 곳을 마련한다
풀 주소는 사설이므로 공용 서버가 응답을 직접 전달할 수 없다. VPN 호스트가 나가는 방향에서 출발지 주소를 변환하거나, 상위 장치가 풀로 돌아가는 경로를 갖는다.
sudo iptables -t nat -A POSTROUTING -s 10.90.0.0/24 -o eth0 -j MASQUERADE
변환 계층은 정확히 하나만 더한다. 더 위에 두 번째 NAT를 두면 첫 번째가 가려지고, 나중에 문제가 생겼을 때 양쪽 로그가 거의 쓸모없어진다. 상위 라우터가 이미 풀을 되돌려 보내고 있다면 호스트에서 변환을 더하는 것은 군더더기이며, 그때 귀환 경로는 내 설정이 아니라 그 라우터의 설정에 달린다.
클라우드 인스턴스는 관문을 하나 더 둔다. 일부 플랫폼은 출발지 주소가 인스턴스 자신의 것이 아닌 패킷을 그 검사를 풀지 않는 한 버리기 때문이다. 이 설정은 게스트 밖에 있고, 로컬 시험 장비가 잘 돌아갈 때 잊기 쉽다.
서버 셸이 아니라 클라이언트에서 증명한다
먼저 숫자 IPv4 요청, 다음 이름 조회, 마지막으로 애플리케이션 순서로 시험한다. ping은 전달과 변환을 증명할 뿐,이름 해석에 대해서는 아무것도 증명하지 못한다. DNS 옵션은 클라이언트 통합이 이를 설치할 때에만 효력이 생기기 때문이다.
curl -4 -m 5 http://198.51.100.10/
dig +short example.com
변경 사항과 되돌리는 절차를 그때그때 기록해, 시험이 실패할 때 출구 정책을 한 동작으로 되돌릴 수 있게 하자. 이 방법은 IPv4만 다룬다. 배포가 모든 트래픽을 나른다고 주장하기 전에 IPv6을 별도로 조사하자.