12 min read

Site to Site VPN 구축하기

기본적으로 VPN은 point to point 토폴로지이다. 서버와 클라이언트가 마치 이더넷 케이블로 직접 연결된 것처럼, 내가 보내는 패킷은 모조리 상대방에게만 전달된다.

지난 글에서 hub and spoke (a.k.a. star) 토폴로지 형태의 VPN을 구성했다. 클라우드에 서버를 한 대 두고, 이 서버에 연결하면 마치 다른 VPN 클라이언트와 허브로 연결된 것처럼 서로 통신할 수 있게 되는 구조이다.

사실 Wireguard는 L3에서 동작하고, 흔히 쓰는 스위칭 허브는 L2에서 동작하므로 정확하게 같은 기능을 수행하지는 않는다. L2TP나 OpenVPN tap모드, Softether VPN의 Virtual L2 switch가 이에 해당한다.

여하튼. 그렇게 서버로 전달된 패킷을 우리가 원하는 목적지로 보내려면 서버에서 패킷을 재차 어딘가로 전달해 주어야 한다. 이렇게 패킷을 던지고 던지고 던져서 목적지로 찾아가는 과정을 라우팅(Routing)이라고 한다. 영어단어 그대로 경로를 찾아가는 과정이다. 이 부분을 조금 더 손 볼 수 있다면 조금 더 재미있는 구성이 가능해진다.

위 토폴로지에서 서버와 연결된 클라이언트는 라우터이다. 라우터는 그 이름에서 알 수 있듯 패킷 라우팅을 수행해주는 장비이고, 따라서 위와 같은 경로로 두 대의 검정색 PC는 흰색 PC와 통신할 수 있다. 별도의 VPN 터널을 형성하지 않아도.

이러한 구성을 site-to-site VPN이라고 한다. 사실 point-to-site VPN과 site-to-site VPN이 뒤섞여 있다. 우측처럼 라우터 단에서 패킷을 중계하면서, 네트워크 전체가 투명하게 VPN에 접속하게 되는 경우 site-to-site VPN이라고 한다.

AllowedIPs 설정

Wireguard에서 라우팅은 [Peer] 섹션의 AllowedIPs 항목으로 제어한다. 이 항목은 방화벽의 AllowFrom 역할과 동시에 라우팅 테이블의 Route 역할을 한다.

예를 들면, Wireguard 설정에서 기본적으로 AllowedIPs = 10.10.0.0/24 식으로 잡곤 하는데,  VPN의 상대방 서버에서 보내오는 패킷의 src 주소가 10.10.0.0/24 서브넷일 때에만 패킷을 수신하겠다는 방화벽 설정이자, 동시에 내가 보내는 패킷의 dst 주소가 10.10.0.0/24 서브넷이면 상대방 서버로 보내겠다는 라우트 테이블의 역할을 같이 하는 것이다. 양방향 통신을 전제하므로 이렇게 하나의 세팅으로 퉁치는 것이 가능하게 된다.

spoke에 해당하는 개별 클라이언트는 서브넷 전체를 잡아야 하고, hub에 해당하는 서버에서는 AllowedIPs = 10.10.0.8/32 식으로 개별 IP를 할당해 주어야 한다. 왜 그런지 이해가 된다면 네트워크 구성에 감각이 있는 것이다.

Site-to-site VPN 설정

위 예에서 흰색 PC와 라우터 서브넷 사이에서 site-to-site VPN을 구성하려면 어떻게 해야 할까? 설정이 조금 복잡해지므로 단계별로 알아보자.

네트워크 플래닝

우선 네트워크 플래닝부터 해야 한다. 어느 사이트(지점)에 어떤 IP를 깔아 줄 것인지를 미리 구성하고 최적화하는 것이다. 예를 들어 다음 그림처럼 3개의 site (원격접속 하고자 하는 사무실)와 1개의 개별 클라이언트 (아마도 카페에서 일하고 있을 독자의 노트북)가 존재하는 상황을 가정해 보자.

Wg로 구축할 VPN은 관습적으로 10.10.0.0/24 서브넷을 사용한다. 나는 여기에 몇 가지 룰을 추가하여 IP를 할당하였다. 물론 이는 내 상황에 맞추어 임의로 설정한 것이므로, 네트워크 설정을 할 줄 안다면 굳이 이 룰을 따를 이유는 없다.

  • 허브가 되는 중앙 VPN서버는 관례상 10.10.0.1 을 사용한다.
  • 중앙 VPN서버에 단독으로 접속하는 개별 클라이언트는 10.10.0.[2-127] 을 사용한다. 따라서 최대 126개 클라이언트가 접속할 수 있다.
  • 다른 서브넷을 대표하여 접속하는 site VPN 클라이언트는 10.10.0.[192-207] 을 사용한다. 따라서 최대 16개 site가 붙을 수 있다.
  • site VPN 클라이언트에 연동되는 지점망은 192.168.[192-207].0/24 서브넷을 사용하며, 관리 편의를 위해서 의도적으로 지점망 서브넷의 세 번째 자리와 VPN IP의 네 번째 자리를 같은 값으로 사용한다.

단독 클라이언트

이제 서버와 각 클라이언트 마다 AllowedIPs 항목을 설정해 주어야 한다. 우선 단독 클라이언트부터 생각해 보기로 하자.

단독 클라이언트는 VPN터널 너머로 큰 테두리 안에 있는 네트워크 전체와 통신하고 싶을 것이다. 그렇다면 단독 클라이언트의 AllowedIPs 항목을 어떻게 설정해야 할까.

우선 VPN 클라이언트 사이의 통신을 위해 10.10.0.0/24 는 들어가야 함은 명백하다.그리고...

  • 첫 번째(M=192) 지점망 내부의 PC와 통신하기 위해서 192.168.192.0/24 서브넷이 추가되어야 한다.
  • 두 번째(M=193) 지점망 내부의 PC와 통신하기 위해서 192.168.193.0/24 서브넷이 추가되어야 한다.
  • ...
  • 16번째(M=207) 지점망 내부의 PC와 통신하기 위해서 192.168.207.0/24 서브넷이 추가되어야 한다.

총 16개 설정이 주루룩 추가되어야 한다. 그런데 잘 보니 해당 서브넷들은 서로 연달아 붙어 있는 특정한 범위에 포함된다. 해당 서브넷을 계산해 보면 192.168.[192-207].0/24 범위로 표기되는데, 이는 192.168.192.0/20 서브넷과 정확하게 일치한다. 따라서 위의 16개 설정은 단순히 하나의 설정으로 통합할 수 있다. 이를테면 CIDR 의 prefix aggregation을 고려해서 M의 범위를 할당해 주어야 한다는 것이다.

최종적으로 단독 클라이언트의 AllowedIPs = 10.10.0.0/24, 192.168.192.0/20 으로 계산할 수 있다.

Site VPN 클라이언트

다음으로 site VPN 클라이언트의 경우를 살펴보자. 예를 들어 N=193으로 가정해 보자.

단독 클라이언트와 별반 다르지 않다. VPN 클라이언트 사이의 통신을 위해 10.10.0.0/24 는 들어가야 함은 명백하다. 그리고...

  • 첫 번째(M=192) 지점망 내부의 PC와 통신하기 위해서 192.168.192.0/24 서브넷이 추가되어야 한다.
  • 두 번째(M=193) 지점망 내부의 PC와 통신하기 위해서 192.168.193.0/24 서브넷이 추가되어야 한다. 어 잠깐만?
  • 세 번째(M=194) 지점망 내부의 PC와 통신하기 위해서 192.168.193.0/24 서브넷이 추가되어야 한다.
  • ...
  • 16번째(M=207) 지점망 내부의 PC와 통신하기 위해서 192.168.207.0/24 서브넷이 추가되어야 한다.

단독 클라이언트와 같은 라우팅 테이블 최적화 과정을 거치다 보니 문제가 발생한다. 지점망 내부의 라우팅 테이블과 Wg의 라우팅 테이블이 중복된다. 어떻게 해야 하지?

  • 확실한 방법은 Wg의 AllowedIPs 항목을 쪼개서 수동으로 기재해 주는 이다. 15개만 써 주면 된다.
  • 라우터 설정을 바꿀 수 있다면 라우팅 테이블의 우선 순위를 조절하는 방법을 택할 수 있다. 여러 라우팅 테이블의 항목이 겹친다면 Metric 값에 따라 우선 순위가 매겨진다. 내부 지점망의 Metric값을 더 큰 값으로 주어 우선 순위를 높여주면 된다.
  • 같은 Metric을 갖는 라우팅 테이블은 More Specific → Less Specific 순서로 적용된다. 지점망의 CIDR은 24이고 Wg의 CIDR은 20이므로 그냥 무대뽀로 적용해 본다.

네트워크의 안정성과 관리 편의성 사이에서 적절히 선택하자. 나는 세 번째를 선택했다. lol!

최종적으로 site VPN 클라이언트 또한 AllowedIPs = 10.10.0.0/24, 192.168.192.0/20 으로 계산할 수 있다.

VPN 서버

마지막으로 VPN 서버 설정도 해 주어야 한다.

위 예시를 기준으로 VPN 서버 입장에서 보면 4개의 Peer 항목이 존재할 것이다. 음...

각 Peer 사이에서는 겹치는 라우팅이 발생하면 안 된다. 이를테면 중앙 우체국에서 편지를 분류함에 있어서 혼란이 있으면 안 되니까.

우선 10.10.0.A 주소를 사용하는 단독 클라이언트부터 생각해 보자. 이 클라이언트에서 받고 싶은 발신인 주소, 그리고 이 클라이언트로 보내야 하는 수신인 주소는 딱 10.10.0.A 하나 뿐이다. AllowedIPs = 10.10.0.A/32 확정.

다음으로 10.10.0.M 주소를 사용하는 site VPN 클라이언트를 생각해보자. 이 클라이언트에서 받고 싶은 발신인 주소는? 10.10.0.M 과 더불어 192.168.M.0/24 서브넷이 포함된다. 지점망에 붙어 있는 모든 PC도 이 VPN을 쓸 수 있으니까. 이 클라이언트로 보내고 싶은 수신인 주소는? 동일하다. AllowedIPs = 10.10.0.M/32, 192.168.M.0/24 확정. 중복 문제는 발생하지 않는다.

이러한 기준으로 모든 Peer 섹션을 구성해 주면 된다.

패킷 포워딩 설정

Wg 설정 자체는 위 과정을 거치면 끝난다. 다만 몇 가지 추가 설정을 해 주어야 하는 부분이 남아 있다.

우선 지난 글에서 언급한 것처럼 VPN 서버에서 wg0 in - wg0 out 패킷에 대해서 포워딩 설정을 해 주어야 한다. 다음으로 각 site VPN 클라이언트에서도 eth0 - wg0 사이에 포워딩 설정을 해 주어야 한다. 이 설정을 하지 않으면 지점망 PC가 보낸 패킷이 라우터 단에서 드롭되므로 VPN 내부까지 전달되지 않는다.

이러한 설정은 각 라우터의 설정방법에 따라 진행하면 된다. OpenWRT의 경우, eth0wg0 을 같은 방화벽 구역(Zone)에 두고, Forward 설정을 accept 로 바꿔주면 된다.

Site VPN 클라이언트 기능을 지원하는 라우터

사실 이게 가장 구하기가 어려웠다. 국내에서 판매중인 공유기 중 VPN 클라이언트 기능을 지원하는 모델은 없다시피 하다. 그나마 최근 들어 ipTIME 제품 중 일부가 OpenVPN 클라이언트 기능을 지원하기 시작했다.

2022년 3월 현재 Wireguard를 지원하는 모델은 없다는 의미이다.

다행히도 OpenWRT를 올리면 Wireguard 클라이언트 확장기능을 설치할 수 있다. 그리고 ipTIME 제품 중 A1004ns를 포함해서 일부 제품에 OpenWRT를 설치할 수 있다. 나는 중고가 2만원 정도에 구매해서 그냥 펌웨어 엎어버렸다.