두 VPN 클라이언트는 나란히 실행될 수 있지만, 각자의 kill switch가 하나의 정책으로 합쳐지지는 않습니다. 각 클라이언트는 자기 터널을 위한 규칙만 설치하고, 상대가 존재한다는 사실을 모릅니다. 제가 겪은 경우는 업무용 클라이언트가 먼저 연결된 상태였습니다. 두 번째 앱은 핸드셰이크를 끝내지 못하고 „Connecting“에서 십 분을 멈춰 있었고, 첫 번째 터널이 조용히 모든 것을 실어 날랐습니다. 두 번째 앱이 보호되는지는 세 가지 조건에 달려 있고, 두 아이콘이 모두 연결됨이라고 표시되는지와는 무관합니다.

kill switch가 실제로 미치는 범위

운영체제에 단일한 kill switch 플래그라는 것은 없습니다. 이를 지원한다고 광고하는 클라이언트는 규칙 집합을 설치합니다. 내 터널로 나가지 않는 것은 모두 버리고, 터널이 사라지면 fail closed로 동작하는 경우가 많습니다. Linux에서는 보통 nftables나 iptables 체인, Windows에서는 Windows Filtering Platform 필터 집합, Android와 iOS에서는 터널 서비스 자체의 라우팅에 VPN 없이 연결되는 것을 막는 시스템 설정이 더해집니다. Android VPN 가이드에 이 서비스 모델이 설명되어 있습니다. 플랫폼 관점이 궁금할 때 참고하세요.

중요한 것은 적용 범위입니다. „wg0 출력 인터페이스의 패킷만 허용“ 같은 규칙은 두 번째 터널이 있는지 신경 쓰지 않습니다. 다른 클라이언트가 wg1을 올리면, 첫 번째 클라이언트의 규칙은 그 패킷을 평범한 트래픽으로 취급합니다. 대개 버리고, 가끔 통과시킵니다. 어느 쪽이든 결정하는 것은 첫 번째 클라이언트이며, 두 번째 앱이 기다리고 있다는 사실은 전혀 모릅니다.

누가 보호받는지를 결정하는 세 가지 조건

모든 조합을 세어 볼 필요는 없습니다. 세 가지 질문이면 몇 분 안에 정리됩니다.

  1. 플랫폼이 두 번째 터널을 허용하는가. 대부분의 Android 휴대폰과 iPhone은 사용자 프로필당 활성 VPN 서비스를 하나만 받아들입니다. 따라서 두 번째 앱은 터널을 가질 수 없고 아무것도 강제하지 못합니다. 정책은 하나만 남고, 자리를 차지한 앱의 것입니다.
  2. 기본 경로를 소유한 프로세스는 무엇인가. Windows, macOS, Linux는 두 개의 터널을 문제없이 감당합니다. 기본 경로는 마지막으로 설정한 클라이언트, 또는 메트릭이 더 좋은 클라이언트의 것이 되고, 다른 쪽은 연결된 채 대기합니다. Linux에서 wg-quick의 기본 경로 모드는 전용 테이블과 fwmark 규칙을 쓰는 정책 라우팅을 사용하므로, 두 번째 wg-quick 터널은 첫 번째를 대체하지 않고 경쟁 규칙을 추가합니다.
  3. 두 번째 클라이언트가 자기 서버에 도달할 수 있는가. 첫 번째 kill switch가 기본 거부라면, 두 번째 앱의 외부 엔드포인트는 그냥 버려지는 목적지입니다. 조용히 다시 시도하고 오류를 보고하지 않습니다.

지원 스레드용 짧은 버전입니다:

SetupWhat you actually get
Second client cannot hold a tunnelOne active policy; the other app only reports that it is waiting
Both tunnels up, second took the default routeThe first kill switch blocks traffic it never meant to touch; the connection dies, or leaks if its rules are broad
First kill switch allows only its own endpoint and interfaceSecond client never connects; first tunnel unaffected
Both up, DNS written by whichever client ran lastName resolution breaks for one side when either tunnel drops

그중 두 행은 트레이 아이콘으로는 똑같아 보이므로, 여기서 아이콘은 가장 나쁜 증거입니다.

먼저 무엇이 깨지는가, 그리고 어떻게 보이는가

한쪽은 멀쩡한데 다른 쪽이 „Connecting“에 멈춰 있다면 거의 항상 엔드포인트 기아입니다. 돌아가는 kill switch가 두 번째 클라이언트에서 자기 서버로 가는 핸드셰이크를 버리고 있습니다. 값싸게 확인하려면 첫 번째 클라이언트의 차단 규칙을 한 번만 잠시 멈춰 보세요. 두 번째가 곧바로 연결되면 답은 나온 것입니다.

두 번째는 DNS입니다. 클라이언트는 자기 인터페이스용 리졸버 설정을 넣고, 일부는 전역 목록을 그대로 덮어씁니다. 두 터널이 모두 올라와 있으면 질의가 한쪽으로 나가는데 리졸버는 다른 쪽에 속하는 상황이 생깁니다. 어느 한 앱을 끊으면 남은 쪽은 도달할 수 없는 네임서버를 붙들고 있게 됩니다. 페이지가 일 분쯤 멈췄다가 다시 풀리고, VPN은 여전히 연결됨으로 표시됩니다.

세 번째는 경로 흔들림입니다. 재연결이 기본 경로를 다시 정렬하고, 인터페이스에 묶인 kill switch는 그것을 따라가지 않습니다. 방금까지 터널 안에 있던 트래픽이 이제 버리기 규칙에 걸립니다. 사용자 쪽에서는 VPN이 이따금 제멋대로 멈추는 것처럼 보입니다.

어떤 정책이 실제로 유효한지 확인하기

무해한 트래픽으로 하고, 잃고 싶지 않은 것으로는 시험하지 마세요.

Linux에서는 커널에 누가 이기는지, 방화벽이 무엇에 묶여 있는지 물어보세요. ip -4 route show default은 출구를 가진 터널을 알려 줍니다. ip rule show는 정책 라우팅이 개입하는지 보여 줍니다. sudo nft list ruleset | grep -n oifname은 버리기가 인터페이스 이름에 묶였는지, 마크에 묶였는지, 아니면 출력 체인 전체에 묶였는지 보여 줍니다.

Windows에서는 같은 이야기가 경로 메트릭과 필터 목록에 있습니다. Get-NetRoute -DestinationPrefix "0.0.0.0/0" | Sort-Object RouteMetric와 Get-NetFirewallRule -Enabled True | Where-Object DisplayName -match "VPN"입니다. macOS라면 netstat -rn -f inet | head -5와 scutil --dns | head -20입니다.

그다음 대부분이 건너뛰는 단계를 하세요. 터널을 일부러 멈추고, 실패해야 할 트래픽이 정말 실패하는지 확인하는 것입니다. 연결됨 아이콘은 UI 상태일 뿐 강제가 아닙니다.

두 클라이언트가 잘못된 설계일 때

두 번째 앱 뒤에 있는 요구가 „보호를 더 받고 싶다“뿐이라면 그것을 빼세요. 서로 상호작용하는 두 개의 차단 정책은 하나보다 예측하기 어렵고, 재연결할 때마다 어느 벤더도 시험해 보지 않은 상태로 떨어질 기회가 생깁니다.

정말로 연쇄가 필요하다면, 예를 들어 상용 홉을 거쳐 기업 게이트웨이에 닿는 구성이라면 강제 지점이 하나뿐인 설계를 고르세요. 보통은 그 연쇄를 지원하는 라우터나 단일 클라이언트를 뜻하며, 같은 기본 경로를 두고 다투는 데스크톱 앱 두 개가 아닙니다. 관리되는 기기에서는 승인된 클라이언트를 남기고 나머지는 범위 밖으로 취급하세요. 트레이에 무엇을 표시하든 마찬가지입니다.

둘 다 유지하기 전 점검 목록

위에서부터 순서대로 진행하고, 처음 실패한 항목을 고치세요.

  • 기본 경로와 리졸버를 가진 클라이언트가 정확히 하나인지 확인하기.
  • 두 번째 클라이언트를 올려 두려면 그 서버의 엔드포인트를 명시적으로 허용하고, 클라이언트를 업데이트할 때마다 다시 확인하기.
  • 어느 한 터널이 끊길 때의 예상 결과를 적어 두고, 그 경우만 시험하기.
  • 재부팅 후 실패 경로를 확인하기. 시작 순서가 달라질 때 특히 그렇다.
  • 관리되는 프로필에서는 무언가를 추가하기 전에 멈추고 소유자에게 물어보기.

세 단계가 실패하면 정직한 답은 정책을 주는 클라이언트가 하나뿐이라는 것입니다. 어느 쪽을 신뢰할지 정하고 다른 쪽은 놓아주세요.

관련 글