사이트 두 곳, 서브넷 하나, WireGuard 허브 하나: 동작하게 만들기
두 LAN 모두 10.10.7.0/24에 있어 허브가 목적지로 사이트를 고를 수 없습니다. 서비스마다 에일리어스를 주고 그 게이트웨이에서 변환하십시오.
두 사이트가 같은 LAN 범위를 사용하며, 설계를 실제로 망가뜨리는 것은 중복이 아닙니다. 허브는 목적지 주소만으로 사이트를 골라야 하고, 목적지가 같으면 고를 근거가 없습니다. 터널에 맞추기 위해 작동하는 사무실의 번호를 다시 매기는 것은 대개 터널이 실어 나를 수 있는 별도 주소를 각 공개 서비스에 주는 것보다 나쁜 거래입니다. 아래 설계는 사이트마다 HTTPS 서비스 하나만 공개하고 그 외에는 아무것도 공개하지 않습니다.
중복이 진짜 문제가 아닌 이유
WireGuard는 목적지로 전달합니다: peer의 AllowedIPs가 어떤 peer가 패킷을 받을지 결정합니다. 두 peer가 동시에 10.10.7.0/24를 광고하면 둘 중 하나가 모든 조회에서 이기게 됩니다. 이는 터널이 아니라 peer 표의 성질이므로, 여기서 해법은 라우팅 요령이 아니라 주소 계획입니다.
계획은 LAN 광고를 완전히 멈추는 것입니다. 대신 서비스마다 에일리어스를 광고하고, 사이트마다 주소 하나를 주고, 각 사이트의 게이트웨이가 그 에일리어스를 실제 애플리케이션으로 변환하게 하십시오.
사용자는 고유한 주소 두 개를 라우팅하고, 모호한 접두사를 결코 보지 않으며, 두 사무실 어디에서도 아무것도 바뀌지 않습니다. 이것은 경계도 정직하게 말합니다: 각 사이트에서 HTTPS 서비스 하나를 공개하는 것이지 두 네트워크를 합치는 것이 아닙니다. 뒤따르는 규칙이 작게 유지되는 것은 그 진술이 좁기 때문입니다. 더 넓은 진술에는 더 넓은 규칙이 필요하며, 이런 설계가 복잡해지는 방식이 바로 그것입니다.
각 사이트에 사용자가 라우팅할 수 있는 에일리어스를 주십시오
사용자 기기, 허브, 두 LAN 어디와도 충돌하지 않는 범위에서 주소를 고르십시오. 여기서 허브는 10.66.0.1, 사용자는 10.66.0.10, 게이트웨이는 10.66.0.21과 10.66.0.22, 두 에일리어스는 10.77.1.20과 10.77.2.20입니다. 허브는 각 에일리어스를 그것을 소유한 peer를 통해 광고하므로, 한 에일리어스로 향하는 나가는 패킷은 해당 사이트를 통해서만 나갈 수 있습니다:
[Interface]
Address = 10.66.0.1/32
ListenPort = 51820
PrivateKey = HUB_KEY
[Peer]
PublicKey = USER_PUBLIC_KEY
AllowedIPs = 10.66.0.10/32
[Peer]
PublicKey = SITE_A_PUBLIC_KEY
AllowedIPs = 10.66.0.21/32, 10.77.1.20/32
[Peer]
PublicKey = SITE_B_PUBLIC_KEY
AllowedIPs = 10.66.0.22/32, 10.77.2.20/32
사용자 쪽에는 두 에일리어스만 필요하므로 클라이언트 구성이 두 LAN 접두사에서 자유롭습니다. 그 구성 어디에도 실제 LAN은 언급되지 않습니다:
[Interface]
Address = 10.66.0.10/32
PrivateKey = USER_KEY
[Peer]
PublicKey = HUB_PUBLIC_KEY
Endpoint = hub.example.net:51820
AllowedIPs = 10.77.1.20/32, 10.77.2.20/32
PersistentKeepalive = 25
각 게이트웨이는 허브와 사용자 출발지만 광고하고 그 외에는 아무것도 광고하지 않으므로, 한 사이트가 다른 사이트의 LAN을 알지 못합니다. Keepalive는 사이트 업링크에서 NAT 매핑을 유지하며, 트래픽을 허가하지 않고, 무엇을 받아들일지는 여전히 방화벽이 결정합니다. 한 게이트웨이의 구성을 다른 쪽으로 복사해도 개인 키, 인터페이스 주소, 에일리어스가 모두 바뀐다면 문제없습니다.
허브가 두 peer 사이에서 허용해야 하는 것
허브는 자기 peer 두 개 사이에서 패킷을 전달하며, 이는 forward 체인의 결정이지 입력 결정이 아닙니다. 플랫폼의 일반적인 방식으로 IPv4 전달을 켠 다음, 설계에 필요한 쌍만 정확히 허용하십시오.
아래 규칙은 사용자가 에일리어스 하나와 포트 하나에 접근하도록 허용하고, 연결 추적을 통해 반환 트래픽을 허용합니다. forward 경로의 나머지는 모두 버리며, 바로 그것이 핵심입니다:
nft add table inet hub_transit
nft add chain inet hub_transit forward '{ type filter hook forward priority 0 ; policy drop ; }'
nft add rule inet hub_transit forward ct state established,related accept
nft add rule inet hub_transit forward iifname wg0 oifname wg0 tcp dport 443 ip saddr 10.66.0.10 ip daddr 10.77.1.20 accept
두 가지 세부 사항은 조용한 실패를 일으키므로 언급할 만합니다. 한 기본 체인의 accept는 다른 체인의 drop을 덮어쓰지 않으므로, 이것을 기존 정책과 합치고 나란히 적재하지 마십시오. 그리고 출발지 주소는 사람이 아니라 기기를 식별하므로, 애플리케이션 인증은 네트워크 허용과 분리하십시오.
에일리어스가 실제 주소가 되는 곳
사이트 A는 10.77.1.20에 대한 요청을 받고, 목적지를 실제 애플리케이션으로 다시 쓰고, 출발지를 자기 LAN 주소로 다시 써서 응답이 터널로 가는 경로 없이 돌아올 수 있게 합니다. 두 변환을 한곳에서 하면 나머지 네트워크는 에일리어스를 모릅니다. 아래 규칙이 전체 메커니즘입니다:
nft add table ip site_a_nat
nft add chain ip site_a_nat pre '{ type nat hook prerouting priority -100 ; policy accept ; }'
nft add chain ip site_a_nat post '{ type nat hook postrouting priority 100 ; policy accept ; }'
nft add rule ip site_a_nat pre iifname wg0 tcp dport 443 ip saddr 10.66.0.10 ip daddr 10.77.1.20 dnat to 10.10.7.20:443
nft add rule ip site_a_nat post iifname wg0 oifname lan0 tcp dport 443 ip saddr 10.66.0.10 ip daddr 10.10.7.20 snat to 10.10.7.2
그다음 사이트 A의 forward 정책이 변환된 흐름을 터널 인터페이스에서 LAN 인터페이스로, 그리고 반환 방향까지 허용해야 합니다. forward 훅은 목적지 변환 후, 출발지 재작성 전에 목적지를 보므로 규칙이 실제 애플리케이션 주소를 지목합니다. 규칙이 아무것도 맞지 않는 것처럼 보일 때마다 이 두 훅을 이 순서로 읽으십시오. 에일리어스에 맞서 작성한 forward 규칙은 그 훅에서 에일리어스가 더 이상 존재하지 않으므로 결코 일치할 수 없습니다.
사이트 B는 자기 에일리어스와 자기 키로 이것을 반복합니다. 두 peer가 하나의 신원을 공유하는 것은 보기 어렵고 파일을 복사해 만들기 쉬운 구성 오류이므로, 사이트 A의 개인 키를 재사용해서는 안 됩니다. 두 게이트웨이 문서는 달라야 하는 값만 제외하고 동일하게 유지해 검토에서 차이가 드러나게 하십시오. 복사한 파일이 그 결함의 흔한 원인입니다.
출발지 재작성에는 대가가 있습니다. 애플리케이션은 게이트웨이를 자기 클라이언트로 보므로, 로그에 어느 사용자가 접속했는지 더 이상 나오지 않습니다. 게이트웨이의 감사 추적은 유지하고, 변환이 지운 네트워크 신원을 보상하려고 애플리케이션 로그인을 약화시키지 마십시오.
공개한 두 이름이 응답함을 증명하는 방법
변환은 리디렉션이나 내장된 절대 URL을 다시 쓰지 않으므로, 각 에일리어스에 DNS 이름을 주고 그 이름으로 애플리케이션과 인증서를 구성하십시오. 사이트마다 이름 하나를 사용해 인증서 불일치가 라우팅 결함으로 오해되지 않게 하십시오.
실제 클라이언트에서 시험하고, 어느 사이트가 응답했는지 확인하고, 허용되지 않은 포트도 시험하십시오. NAT을 변경한 뒤에는 확립된 상태가 옛 매핑을 유지하므로 새 연결을 사용하십시오:
wg show wg0 allowed-ips
sudo nft list ruleset
curl -sS -o /dev/null -w "%{http_code}\n" https://site-a.example.net/
첫 명령에서 에일리어스가 비었거나 예상과 다르면 어떤 방화벽 규칙이 문제가 되기 전에 peer 선택이 틀린 것입니다. 에일리어스가 맞는데도 이름이 여전히 실패하면 문제는 DNS와 인증서로 옮겨간 것입니다. 두 이름이 모두 응답하고 세 번째 포트가 닫혀 있으면, 설계는 주장한 대로 동작합니다: 좁게 공개된 두 서비스이지, 합쳐진 두 LAN이 아닙니다.