VPN 라우트와 방화벽 규칙, 패킷을 떨어뜨리는 쪽은 어느 것인가
라우트는 경로를 고르고 필터는 허용을 결정한다. 방화벽 규칙을 넓히기 전에 같은 소스, 목적지, 방향으로 둘 다 확인한다.
같은 패킷에 두 가지 독립적인 결정이 일어나며, 둘 중 어느 쪽이든 요청을 조용히 끝낼 수 있다. 라우트 조회는 인터페이스와 다음 홉을 고르고, 그다음 패킷 필터가 그 조합이 허용되는지 결정한다. 타임아웃은 둘 중 하나가 거부했다는 것만 알려 주고 어느 쪽인지는 알려 주지 않는다. 단계를 순서대로 따라가면 수리는 대개 추측이 아니게 된다.
두 결정, 하나의 패킷, 두 주인
라우트 조회는 먼저 정책 규칙을 살피고, 그다음 그것이 가리키는 테이블을 보며, 목적지와 일치하는 가장 구체적인 프리픽스를 고른다. 터널 라우트를 설치한 클라이언트가 그 결정의 주인이며, 방화벽 규칙의 어떤 것도 그것을 대신할 수 없다. 조회가 예상 밖의 곳을 가리키면 이후의 모든 단계는 잘못된 패킷을 다룬다.
필터링은 별개다. Linux 호스트에서 netfilter 훅은 패킷이 누구를 위한 것인지에 따라 트래픽을 나눈다. 출력은 머신을 떠나고, 입력은 그 위에서 끝나며, 포워드는 그것을 통과한다. VPN 클라이언트를 받아 LAN으로 라우팅하는 게이트웨이에는 포워드 경로가 필요하며, 그것이 바로 대부분의 기본 구성이 비워 두는 체인이다.
소스 선택도 같은 결정에 속하며, 대부분의 불일치가 여기에 숨어 있다. 커널은 라우트가 하나를 지정하지 않는 한 출력 인터페이스에서 소스 주소를 고르므로, LAN 서브넷을 위해 작성된 필터 규칙은 터널 주소로 나가는 패킷과 결코 일치하지 않는다.
조회가 실제로 무엇을 골랐는지 읽는다
추측하는 대신 결정을 출력한다. 아래 명령은 커널이 그 목적지에 사용할 라우트를 인터페이스와 선택할 소스까지 포함해 해석한다.
ip route get 10.8.0.5 ip route get 10.8.0.5 from 192.0.2.44 ip rule show ip route show table all | sed -n '1,40p'
VPN 클라이언트는 흔히 메인 테이블보다 낮은 우선순위에 정책 규칙을 설치하므로, 깨끗한 메인 테이블은 그 자체로 아무것도 증명하지 못한다. 규칙의 우선순위를 그것이 선택하는 테이블과 비교하고, 터널 라우트가 한 번 수동으로 추가되는 대신 재연결 후에도 살아남는지 확인한다.
정책 기반 IPsec은 라우팅이 다루지 않는 세 번째 일치 단계를 더한다. strongSwan의 포워딩 노트가 터널 및 전송 구성에 대해 설명하는 대로다. 보안 정책은 프리픽스와 프로토콜로 트래픽을 고르고, 라우트는 보호되지 않은 패킷이 어디로 갈지만 결정한다. 라우팅되지만 일치하는 선택자가 없는 서브넷은 설정에 따라 보호되지 않은 채 남거나 버려지며, 어느 결과도 방화벽 문제처럼 보이지 않는다. 정책을 출력하고 그 선택자를 터널이 실어 나를 것으로 기대한 프리픽스와 비교한다.
필터링은 라우트가 아니라 훅에서 적용된다
VPN 리스너를 허용하는 규칙은 게이트웨이 자체로 향하는 트래픽에 대한 규칙이다. 그 게이트웨이 뒤의 호스트에 도달하는 클라이언트에 대해서는 아무 말도 하지 않는다. 포워드된 트래픽은 다른 체인을 지나기 때문이다. 규칙 집합을 하나의 평평한 목록으로 읽는 것이 올바르게 보이는 규칙이 결코 발동하지 않는 흔한 이유다.
카운터가 질문을 빠르게 정리한다. 패킷 수가 영인 규칙은 도달된 적이 없으며, 이는 잘못된 체인, 잘못된 인터페이스 또는 이전의 드롭을 가리킨다. 드롭 정책 아래에서 카운터가 늘어나는 규칙이 찾던 경계이며, 패킷은 잘못 라우팅되는 대신 버려지고 있다.
클라이언트가 쓰는 경로로 프로브를 보낸다
게이트웨이 자체에서 실행한 테스트는 게이트웨이 자신의 소스 주소로 출력과 입력을 지난다. 그것은 클라이언트의 포워드 요청과 다른 경로이므로, 성공한 로컬 curl은 보이는 것보다 적게 증명한다. 실패하는 머신에서 시험하거나 인터페이스와 소스를 명시적으로 고정한다.
nc -vz -w 3 10.8.0.5 443 ping -c 3 -W 1 10.8.0.5 tcpdump -ni any host 10.8.0.5 and port 443 iptables -vnL FORWARD --line-numbers nft list ruleset | sed -n '1,60p'
양 끝에서의 캡처가 나머지 경우를 가른다. 클라이언트를 떠나 결코 도착하지 않는 SYN은 라우팅, 암호화 또는 상류 접근 목록을 뜻한다. 도착했지만 응답이 없는 SYN은 서비스 또는 그 호스트 필터를 뜻하며, 터널은 문제가 아니었다.
반환 트래픽은 따로 볼 가치가 있다. 비대칭 라우팅과 역경로 필터링은 잘못된 인터페이스로 도착한 응답을 버리며, 이는 차단된 포트가 아니라 단방향 연결로 나타난다. 방화벽이 일으키지 않은 증상의 책임을 물기 전에 sysctl 값을 확인한다.
로깅은 첫 단계가 아니라 두 번째 의견으로 작동한다. 포워드 체인의 임시 로그 문은 그곳에 닿은 인터페이스와 주소를 알려 주며, 나중에 쉽게 제거할 수 있다. 영구히 남겨 두면 답 대신 로그 볼륨 문제를 만든 셈이다.
각 변경을 재연결 후에도 남는 곳에 둔다
ip route add로 추가한 라우트는 인터페이스가 내려갈 때까지 산다. 대신 연결 프로필에 저장한다. NetworkManager는 연결에 추가 라우트를 받아들이고, netplan은 부팅 사이에 그것을 유지한다. 같은 규칙이 클라이언트 측 방화벽 예외에도 적용되며, 그것은 다음 재로드 후 사라진다.
서버 측 규칙은 서비스가 시작할 때 읽는 구성 파일에 속하고, 닫으면 끝나는 대화형 세션에 속하지 않는다. 규칙을 쓰고 재로드한 뒤 카운터가 움직였는지 확인한다. 구문을 거부한 재로드는 예전 규칙 집합을 조용히 그대로 두기 때문이다.
그다음 원래 애플리케이션 요청을 처음부터 끝까지 반복하고 어느 계층이 바뀌었는지 기록한다. 필터 변경도 필요했던 라우트 수정은 여전히 실패하며, 첫 번째가 사라졌음을 알면 두 번째 실패는 훨씬 읽기 쉽다. 결과 옆에 날짜와 클라이언트 버전을 적는다. 라우팅과 필터링의 기본값은 릴리스 사이에 모두 움직이기 때문이다. 그 메모를 티켓에 남겨 다음 사람이 두 단계 여정을 반복하지 않고 멈춘 곳에서 시작하게 한다.