Raspberry Pi VPN 게이트웨이: NIC 하나 또는 전용 클라이언트 포트
Pi 포트 하나로 선택한 클라이언트를 수용할 수 있고, 두 번째 포트로 기기를 안에 가둘 수 있다. 격리, 폴백 정책, DNS 소유자에 따라 구성을 고르자.
Pi 하나, 동작하는 아웃바운드 VPN 프로필 하나, 그리고 그것을 통해 인터넷에 나가야 하는 기기 두 대가 있다. 전체 구성을 결정하는 질문은 어떤 안내서를 따를지가 아니라 얼마나 격리할지다. 포트 하나면 Pi가 그 기기 옆에서 라우터의 LAN에 놓여 추가 게이트웨이 역할을 하고, 두 번째 포트가 있으면 Pi가 유일한 출구인 세그먼트에 기기를 둘 수 있다. 이 선택 이후의 모든 것 — DHCP, 방화벽 범위, DNS, 단절 시의 동작 — 은 여기서 나온다.
두 구성이 실제로 무엇이 다른가
두 설계 모두 라우팅을 한다. 차이는 누가 더 케이블에 붙어 있는지와 정책이 틀렸을 때 무슨 일이 일어나는지다.
| Layout A: Pi on the ISP LAN | Layout B: dedicated client port | |
|---|---|---|
| Cabling | One Ethernet port, existing switch port | Two interfaces: uplink plus a separate LAN port |
| Can a client bypass the Pi? | Yes, by using the ISP router as its gateway | No, unless the device has another radio or link |
| Who hands out addresses | The ISP router, with a per-client setting or a DHCP option | The Pi, on its own LAN interface only |
| Blast radius of a mistake | Any LAN host, if a rule is too broad | The attached segment |
| Good fit for | One laptop, a console, a temporary test client | Appliances, always-on boxes, untrusted devices |
진짜 축은 격리이며, 구성 A는 권고에 불과하다. DHCP가 준 게이트웨이를 무시하고 라우터를 고르는 기기는 암호화되지 않은 채로 계속 동작한다. 구성 B는 고를 수 있는 다른 다음 홉이 없기 때문에 토폴로지로 강제된다.
구성 A: 기존 LAN에서 추가 게이트웨이로서의 Pi
ISP 라우터가 192.168.50.1, Pi가 192.168.50.2이고 선택한 클라이언트가 Pi를 가리킨다고 하자. 중요한 것은 서로 다른 두 패킷 흐름이 케이블 하나를 공유한다는 점이다. 클라이언트의 안쪽 패킷은 Pi에 도착해 터널로 나가야 하고, Pi 자신의 암호화된 패킷은 VPN 상대를 향해 같은 케이블로 라우터 쪽으로 나가야 한다. 둘은 같은 인터페이스를 반대 방향으로 흐르며 다른 처리가 필요하다.
Pi의 주소는 설치된 네트워크 관리자로 주고, 기기를 두고 그와 다투는 옛 인터페이스 파일 레시피로 주지 않는다. 그다음 클라이언트를 설정하는데, 한 기기에 정적 게이트웨이를 두거나 192.168.50.2를 라우터로 배포하는 DHCP 예약을 쓴다. 기기 두 대 때문에 라우터의 DHCP 전체 범위를 바꾸지 말고, 클라이언트가 그 옵션을 존중한다고 가정하지 말고 확인한다.
약점은 구조적이며 고칠 수 없다. 그 세그먼트의 어떤 클라이언트든 192.168.50.1을 가리켜 평문으로 나갈 수 있고, 두 번째 인터페이스나 셀룰러 라디오가 있는 기기는 강제 경로를 완전히 벗어난다. 그 문장이 해당 기기에 받아들일 수 없다면 답은 이미 나와 있으니 구성 B를 쓰자.
구성 B: 전용 포트가 기기를 안에 가둔다
여기서 Pi는 업링크에서 게이트웨이 192.168.50.1과 함께 192.168.50.2를 유지하고, 두 번째 인터페이스에서 연결된 기기를 위해 10.20.0.1/24를 가져간다. 이제 Pi는 두 네트워크를 가진 라우터이고, 연결된 세그먼트의 출구는 정확히 하나다.
약속하기 전에 범위를 터널 자체의 서브넷, 다른 사이트 간 프리픽스, VPN으로 닿는 모든 것과 맞춰 확인한다. 원격 LAN과 충돌하는 10.20.0.0/24는 진단에 저녁 하나를 쓰게 하는 반쯤 동작하는 결과를 낳는다. 두 번째 포트가 USB 어댑터라면 지원되는지 확인하고, 재부팅 후 순서가 바뀌어도 LAN 주소가 움직이지 않도록 이름을 네트워크 관리자에 고정한다.
DHCP 리스너는 그 인터페이스에서만 돌린다. 업링크에서 응답하는 서버는 ISP 라우터와 경쟁하고 여러분 세그먼트의 주소를 집안 나머지에 나눠 준다. LAN 인터페이스에 묶고, 선언한 범위로 제한하고, Pi 자신의 주소는 풀 밖에 둔다.
포워딩, 변환, 그리고 실패 시 닫는 규칙
네 가지는 흔히 하나로 설명되지만 하나가 아니다. 포워딩을 켜는 것(net.ipv4.ip_forward=1)은 커널이 인터페이스 사이로 패킷을 옮겨도 된다고 알릴 뿐이며, 그 자체로는 아무것도 허용하지 않고 어떤 경로도 보장하지 않는다. 출구를 고르는 것은 라우팅 결정이다. 패킷을 허용하는 것은 forward 체인의 정책 결정이다. 그 출발지를 다시 쓰는 것은 postrouting 결정이다. 첫 번째만 하는 구성은 클라이언트 트래픽을 업링크 밖으로 기꺼이 포워딩하는 Pi를 만든다.
허용을 의도한 출발지와 트래픽이 써야 할 인터페이스로 제한하고, 되돌아오는 경로와 Pi 자신에게 필요한 목적지도 포함한다. 그다음 제공자가 LAN 프리픽스를 이쪽으로 되돌려 라우팅하지 않으면 터널 출구에서 변환한다. nftables 설명서는 포워딩, 로컬 출력, 출발지 변환을 별개의 연산으로 다루는데, 여기서 옳은 사고 모델이다.
흔한 실패는 물리 인터페이스에 넓은 masquerade 규칙을 두는 것이다. 그러면 트래픽은 ISP 경로로 인터넷에 나가는데, 클라이언트 쪽에서는 동작하는 VPN과 똑같이 보인다. 그것은 아무것도 증명하지 않는다. 변환은 선언한 출구에 묶어 두고, 규칙은 호스트가 이미 쓰는 방화벽에 두며, 공유 postrouting 체인을 비우는 경쟁 규칙 세트를 더하지 않는다.
다음으로 터널이 없을 때를 다룬다. 넓은 기본 경로를 설치하는 클라이언트 프로필은 터널이 끊기면 평범한 기본 경로가 돌아와 클라이언트 트래픽이 조용히 업링크로 돌아간다는 뜻이기도 하다. 평문으로의 폴백을 받아들일 수 없는 경우, forward 정책은 VPN 경로가 사라진 상태에서 클라이언트에서 업링크로 가는 트래픽을 명시적으로 거부해야 한다. 그것은 가정이 아니라 거부 규칙으로 쓴다. Pi 자신의 VPN 상대에 대한 암호화된 전송은 별도의 local-output 흐름이며 허용된 채로 남아야 한다, 그렇지 않으면 터널은 다시 돌아올 수 없다.
DNS와 IPv6는 각자의 답이 필요하다
클라이언트가 Pi를 리졸버로 쓰면 로컬 리스너에 닿고 Pi가 새 질의를 시작한다. 그 업스트림 질의는 클라이언트용으로 쓴 forward 규칙이 아니라 Pi 자신의 경로를 따르므로, 터널로만 가는 클라이언트 경로에 직접 나가는 리졸버를 더한 조합은 오류 메시지도 없는 유출이다. 의도해서 터널을 통해 닿는 리졸버로 할지 직접으로 인정하는 로컬 리졸버로 할지 정하고, Pi 자신의 출력 정책을 그 결정에 맞춘다.
IPv6는 또 별개의 사례다. IPv4용 forward 규칙은 IPv6에 관해 아무것도 제한하지 않고, 업링크의 라우터 광고는 Pi와 그것을 거치는 연결 세그먼트에 여러분 정책을 우회하는 두 번째 기본 경로를 줄 수 있다. 같은 원칙으로 IPv6에 자체 보호 경로를 주거나, 클라이언트 세그먼트에서 명시적으로 제한하고 그렇게 말하자.
믿기 전에 경계를 시험한다
설계는 매혹적인 단일 시험, 곧 클라이언트 하나에서 브라우저를 여는 일이 여러 깨진 상태에서도 통과하기 때문에 네 가지 별도 점검 뒤에만 받아들이자.
실제 클라이언트 하나가 터널로 인터넷에 닿는지 확인하고, 이어서 같은 클라이언트가 터널이 내려간 상태에서는 인터넷에 닿지 못하는지 확인한다. DNS 해석이 동작하고 질의가 의도한 곳에서 나가는지 확인한다. 터널을 다시 시작한 뒤에도 Pi 자신의 전송이 동작하고 복구에 기기 재부팅이 필요 없는지 확인한다. 마지막으로 선택하지 않은 기기를 확인하는데, 구성 A에서는 평소대로 계속 동작해야 하고 구성 B에서는 그 세그먼트에 존재해서는 안 된다.
- 포트 둘과 거부 규칙이 강제를 주고, 포트 하나와 DHCP 옵션이 조언을 준다.
- 잘못된 인터페이스에서의 변환은 성공처럼 보이고 성공이 아니다.
- Pi 자신의 트래픽, DNS, IPv6는 각각 결정이 필요하고 추측이 아니다.