HTTP 프록시, SSH 터널, VPN: 알맞은 계층 선택
프록시, SSH 터널, VPN은 서로 다른 트래픽을 나릅니다. 작업에 필요한 프로토콜과 이름 해석에 계층을 맞춘 뒤 경로를 검증하세요.
내부 서비스에 어떻게 접근하는지 엔지니어 세 명에게 물으면 웹 프록시, SSH 터널, 또는 완전한 VPN이라는 세 가지 설계가 나옵니다. 셋 다 원격 서비스를 손이 닿는 곳에 놓을 수 있고, 셋 다 트래픽이 다른 곳에서 오는 것처럼 보이게 할 수 있습니다. 차이는 나중에, 쓰는 프로토콜이 고른 도구가 가정한 것과 다를 때 드러납니다. 브라우저에서의 빠른 확인을 통과한 설계가 그 요청을 촉발한 애플리케이션에서는 일상적으로 실패합니다.
결정은 두 가지 사실에서 나옵니다. 어떤 프로토콜이 통과해야 하는지, 관련된 이름을 누가 해석할 수 있는지이고, 나머지는 취향입니다.
프록시는 이해하는 것만 옮긴다
웹 프록시는 자신을 위해 만들어진 프로토콜을 분석합니다. 클라이언트가 요청을 건네면 프록시는 그 요청을 다음으로 넘기므로, 프록시 설정이 없는 애플리케이션은 아예 참여하지 않습니다. HTTPS에서는 클라이언트에 불투명한 통로가 필요하고, 프록시는 요청을 읽는 대신 CONNECT를 통해 그것을 제공합니다.
SSH 동적 포워딩은 SOCKS를 말하는 로컬 포트를 열고, 그 포트는 TCP 스트림을 클라이언트가 지정한 임의의 목적지로 중계합니다. TCP 위에 지은 프로토콜은 대개 이를 통해 동작합니다. UDP는 도구가 지원을 명시적으로 더하지 않는 한 동작하지 않습니다. 로컬 포워딩은 더 좁아서 로컬 포트 하나를 고정된 호스트와 포트 하나에 매핑하며, 알려진 서비스 하나만을 위해 일합니다.
ssh -D 1080 user@bastion
ssh -L 8443:fileserver.internal:443 user@bastionVPN은 패킷을 옮깁니다. 클라이언트가 터널로 보내는 모든 것이 그곳을 지나며 UDP와 ICMP도 포함되므로, 단일 연결이 아니라 네트워크 요구에 맞습니다.
누군가는 이름을 해석해야 한다
대상 이름이 원격 네트워크의 DNS에만 존재한다면, 조회를 수행하는 기계가 그 영역을 볼 수 있어야 합니다. 웹 프록시는 스스로 조회하므로, 노트북이 이름을 전혀 해석하지 못해도 내부 이름은 프록시를 통해 동작합니다. SOCKS도 같은 방식으로 동작할 수 있지만, 클라이언트가 이미 해석한 주소로 접속하는 대신 이름을 그대로 넘길 때만 그렇습니다. 그 선택은 서버가 아니라 클라이언트에 있습니다.
curl은 이 분리를 분명히 보여 줍니다. 한 플래그는 호스트 이름을 프록시로 넘기고 다른 플래그는 먼저 로컬에서 해석하므로, 로컬 해석에서는 내부에만 있는 이름이 어떤 터널에도 닿기 전에 실패하고 그 오류는 사실 DNS 결정이었던 일을 프록시 탓으로 돌립니다.
VPN은 세 번째 길을 택해 경로 옆에 전용 리졸버와 검색 도메인을 설치합니다. 그것은 편리하고, 응답하지 않는 리졸버와 함께 존재하는 경로가 패킷이 반대편에 도달하고 있어도 죽은 터널과 똑같이 보인다는 익숙한 착각을 만들어 냅니다.
네트워크가 출구를 하나만 허용할 때
많은 기업 네트워크는 바깥으로 나가는 연결을 인증된 웹 프록시를 통해서만 허용합니다. OpenVPNOpenVPN과 SSH는 둘 다 그곳에서 동작하게 할 수 있으며, 전자는 자체 전송을 프록시로 터널링하고 후자는 작은 CONNECT 도우미를 실행하는 프록시 명령을 씁니다.
TCP 위에 지은 터널은 그 제약을 견디고 UDP 기반 VPN은 견디지 못해서, 집에서는 되고 사무실에서는 안 되는 설정이 아주 많습니다. 두 번째 비용은 놓치기 쉬운데, 프록시를 거치는 TCP 연결 안에 실린 TCP 터널은 이제 재전송하는 계층을 둘 갖게 되고 손실 아래에서 그 조합은 어느 한 계층도 혼자 만들지 않는 방식으로 멈춥니다.
중개자를 사슬로 잇는 것은 계층을 고르는 것과 다른 문제입니다. 두 번째 프록시나 Tor를 더하면 누가 무엇을 관찰하는지가 달라지고, 사슬에서의 위치가 어느 홉이 암호문을 보는지를 결정합니다.
순서는 홉 수보다 중요합니다. 바깥 홉은 암호화된 흐름을 보지만 안쪽 홉은 그것이 나르는 평문을 봅니다. 그래서 사슬은 가장 부주의한 고리만큼만 사적입니다. 홉 사이에서 프로토콜을 섞는 것이 그것을 자동으로 낫게 하지는 않고, 대개는 실패 양식을 생각하기 어렵게 만들 뿐입니다.
위조한 주소는 선택지 가운데 하나가 아니다
남의 출발지 주소로 패킷을 만들어도 쓸모 있는 것은 없습니다. 응답은 진짜 소유자에게 가고 대부분의 네트워크는 그 트래픽을 그냥 버리므로, 중개자가 필요한 까닭은 출발지를 지어낼 수 없기 때문이며 그것이 세 설계 모두의 정직한 근거입니다.
그것은 각각이 무엇을 주장할 수 있는지의 한계이기도 합니다. 특정 주소에서 시작된 것처럼 보이는 것은 그 주소가 어디에 정당하게 할당되었고 누가 그것을 라우팅할 수 있는가의 문제이지, 어느 도구가 헤더를 위조할 수 있는가의 문제가 아닙니다. 설계가 반대로 가정한다면 그 가정은 그것을 걸러 내는 첫 사업자에서 무너집니다. 가정을 적어 두면 실패가 닥쳤을 때 알아볼 수 있습니다.
프로토콜과 이름으로 결정하라
웹 클라이언트 하나가 웹 서비스 하나를 필요로 하고 프록시 설정이 있다면 프록시를 고르세요. 알려진 TCP 서비스 몇 개면 충분하고 SSH 접근이 이미 있다면 SSH 터널을 고르세요. 여러 애플리케이션, TCP가 아닌 트래픽, 전용 DNS, 재사용 가능한 경로가 요구의 일부라면 VPN을 고르세요.
그다음 실제 클라이언트와 실제 이름으로 검증하세요. 프록시로 페이지를 불러오는 것은 UDP에 대해 아무것도 가르쳐 주지 않고, 도구 하나를 SOCKS로 동작시키는 것은 시스템 리졸버에 대해 아무것도 가르쳐 주지 않습니다. 프로세스가 어느 로컬 주소에 묶였고 어느 리졸버가 응답했는지 읽어 보세요. 그것이 동작하는 경로와 한 번 우연히 동작했던 경로의 차이입니다.