게이트웨이는 IKEv2로 자신에 연결된 노트북을 향해 연결을 시작해야 하며, 그 클라이언트에 할당된 가상 주소를 사용해야 한다. 터널은 올라와 있고 클라이언트는 게이트웨이 뒤의 모든 것에 도달하지만, 반대 방향은 여전히 실패한다. 이런 비대칭은 정상이며, 협상된 정책은 어떤 주소가 서로 통신할 수 있는지를 설명할 뿐, 어느 쪽이 먼저 시작할 수 있는지는 말하지 않는다. 게이트웨이가 시작한 요청이 동작하려면 세 가지가 맞아야 한다.

터널은 출발지 주소를 고치지 않는다

CHILD SA는 트래픽 선택자 한 쌍을 다루며 각 측에 하나씩 있고, 그 쌍의 양방향 트래픽을 허용한다. 어느 피어가 IKE 교환을 먼저 열었는지는 말하지 않는다. 원래 터널을 기다리던 게이트웨이도 선택한 출발지와 목적지가 설치된 선택자 안에 있으면 첫 애플리케이션 패킷을 보낼 수 있다. 요청이 잘못된 인터페이스로 나가면 그 요청은 터널에 적합하지 않을 뿐이다.

클라이언트 쪽 라우팅은 필요하지만 충분하지 않다. 정책이 실제로 사용한 출발지를 허용해야 한다.

설치된 정책을 읽고, 설정 파일을 읽지 않는다

동적 할당은 커널에 설치되는 내용을 바꾸므로 활성 연결과 그 선택자에서 시작한다.

ipsec statusall
ip xfrm policy

상태 출력은 연결 이름, 할당된 가상 주소, 해당 피어에 현재 유효한 선택자를 보여 준다. 정책 덤프는 같은 선택자를 커널 상태로 보여 주며, 패킷 선택이 실제로 참조하는 것이 바로 이것이다. 게이트웨이 쪽 선택자를 애플리케이션이 사용할 출발지와 비교하면 불일치가 실패를 즉시 설명해 준다. VIP가 다시 할당되면 이전 정책이 무효가 되므로 클라이언트의 현재 주소를 읽고 이전 세션의 주소는 읽지 않는다.

클라이언트는 패킷이 도착하는 곳에서 대기해야 한다

서비스가 루프백에만 바인딩되면 완벽한 정책도 닫힌 포트에 도달한다. 리스너는 할당된 주소나 와일드카드 로컬 주소에 있어야 한다.

ss -ltnp 'sport = :9090'
iptables -S INPUT

소켓 목록은 포트가 가상 주소에 바인딩되었는지 보여 주고, 방화벽 규칙은 보호된 출발지에서 새 연결이 허용되는지 보여 준다. 설정된 연결용으로 작성된 규칙은 게이트웨이가 시작하는 연결을 허용하지 않는다. 터널을 통해 도착하는 것은 패킷이 어느 네트워크에서 왔는지만 확인해 주므로 서비스 자체의 인증은 그대로 둔다. 이 요청들은 기존 터널 안으로 다니므로 자체 NAT 뒤의 클라이언트도 인바운드 포트 포워딩이 필요 없다.

새 방향을 따로 시험한다

클라이언트에서 서버로 가는 정상 요청은 이 경로를 절대 거치지 않는다. 게이트웨이에서 요청을 만들어 양쪽 끝을 관찰한다.

ip route get 10.90.0.42 from 192.168.50.1
tcpdump -ni any host 10.90.0.42 and tcp port 9090

라우트 조회는 게이트웨이가 어떤 출발지와 인터페이스를 쓸지 답해 주며, 정책이 허용해야 하는 값이 바로 이것이다. 캡처에는 요청이 공용 인터페이스의 평문 TCP가 아니라 ESP 안에서 나가는 모습이 보여야 한다. 클라이언트에서는 복호화된 트래픽을 캡처해 도착 여부와 서비스 응답을 확인한다. 요청이 회선에서 ESP 없이 사라진다면 클라이언트 방화벽보다 출발지 주소를 먼저 의심한다.

VIP가 바뀔 수 있으므로 키 재협상이나 재접속 후에 테스트를 반복한다. 다음 세션까지만 동작하는 경로는 동작하는 경로가 아니다.

관련 글