리눅스 Wireguard VPN 구축하기

(Last Updated On: December 13, 2020)

Wireguard는 GRE와 같이 단순하게 터널을 구성하면서 암호화 까지 지원한다. UDP 캡슐화를 사용하기 때문에 UDP를 지원하는 모든 네트워크에서 사용할 수 있다. GRE와 마찬가지로 Stateless이지만 단순하면서도 IP ACL이 내장되어있다. Wireguard의 단점은 Point-To-Point기 때문에 서버의 입장에서도 단 1개의 연결만을 허용한다.

설치

Wireguard공식 홈페이지 ( https://www.wireguard.com/install/ ) 에 설치하는 방법이 있지만 이 포스트에서는 Debian 10 기준으로 작업을 하도록 한다.

apt update && apt upgrade

작업 전 항상 repository 업그레이드를 잊지 않도록 한다.

apt install wireguard

난관

[email protected]:~# apt install wireguard
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package wireguard

???????????????????????????????????

Users with Debian releases older than Bullseye should enable backports.

Debian 11 (Bullseye) 보다 구버전을 사용하는 사람은 backports (stable testing)를 활성화 시켜야 한다고 한다. 그 이유는 Wireguard는 리눅스 5.6에 포함되어있기 때문에 그렇다. 현재 Debian 10 (Buster)는 리눅스 4.19를 사용한다.

deb http://deb.debian.org/debian buster-backports main

해당 문구를 sources.list에 추가하는 방법으로 bullseye의 일부 패키지를 사용할 수 있다. 나는 다른 소프트웨어도 최신버전으로 사용하기 위해 main말고 기타 컴포넌트도 추가하겠다.

echo 'deb http://deb.debian.org/debian buster-backports main contrib non-free' > /etc/apt/sources.list.d/buster-backports.list

그 다음 repository를 업데이트 한 뒤 wireguard 패키지를 설치한다.

apt update && apt install wireguard
The following NEW packages will be installed:
.....linux-headers-4.19.0-13-amd64 linux-headers-4.19.0-13-common...

wireguard 모듈이 포함된 4.19 커널을 새로 받는 것을 볼 수 있다.

Wireguard 프로필 작성

기본적으로 wireguard 설치하면 /etc/wireguard 디렉터리가 생성된다. 딱히 이 폴더에 private key와 public key를 둘다 놓아도 상관없긴 하지만 내 경우 장기적으로 여러 인터페이스를 놓을 생각이 있기 때문에 이러면 혼란이 생길 우려가 있다고 판단하여 키 보관용 폴더를 보기 좋게 만들겠다.

cd /etc/wireguard
mkdir wg0
cd wg0

이곳에서 키를 생성하도록 한다.

umask 077

키를 안전하게 600 (rw——-) 퍼미션으로 생성하기 위해 umask 077 커맨드를 입력

wg genkey | tee privatekey | wg pubkey > publickey

해당 명령을 입력하면 privatekey와 publickey가 생성된다.

인터페이스 프로필 작성

wg-quick을 사용하여 wireguard를 서비스 형태로 사용할 수 있다.
wg-quick up interfacename 를 systemd의 [email protected] 형태로 사용한다.

wg-quick은 기본적으로 /etc/wireguard/INTERFACE.conf 프로필 경로를 사용한다.

양식(format)
[Interface]
Address = 10.0.0.1/24, fdc9:281f:04d7:9ee9::1/64
ListenPort = 51871
PrivateKey = PEER_A_PRIVATE_KEY

[Peer]
PublicKey = PEER_B_PUBLIC_KEY
PresharedKey = PEER_A-PEER_B-PRESHARED_KEY
AllowedIPs = 10.0.0.2/32, fdc9:281f:04d7:9ee9::2/128
Endpoint = peer-b.example:51902

[Peer]
PublicKey = PEER_C_PUBLIC_KEY
PresharedKey = PEER_A-PEER_C-PRESHARED_KEY
AllowedIPs = 10.0.0.3/32, fdc9:281f:04d7:9ee9::3/128
구성 상황 예
  • 서버 (45.76.***.***, 10.100.100.1) UDP 33333포트
  • 동적 IP 클라이언트 (데스크톱에서 접속, 10.100.100.2)
/etc/wireguard/wg0.conf
[Interface]
Address = 10.100.100.1/24
ListenPort = 33333
PrivateKey = sHrISuTxwuWhsXlkM+6M4qhex6YAFroI/qAEb6DIckY=

[Peer]
PublicKey = Vuw89x8GBMv8HVkcBXNkn5kOdnqagfs0v+M8j99m0SU=
AllowedIPs = 10.100.100.2/32
[Interface] PrivateKey는 /etc/wireguard/wg0/privatekey 의 데이터를 넣는다.
[Peer] PublicKey는 Peer측의 PublicKey 데이터를 넣는다.
이 때 peer 측의 Endpoint를 알 수 없기 때문에 생략한다.
PresharedKey 는 Client측의 별도의 키이며 이건 생략한다.

Client (Windows)
  • [Interface] PrivateKey는 인터페이스 생성시 자동으로 값이 생성 됨
  • [Peer] PublicKey는 Peer측 (서버)의 PublicKey이다.
  • [Peer] AllowedIPs는 ACL ( Windows 클라이언트 기준으로 0.0.0.0/0 로 설정한 것과 다르게 설정한 것과 default gateway 설정이 달라진다 )
  • [Peer] Endpoint는 서버의 UDP 주소
서버 시작
systemctl start [email protected]
???
[email protected]:/etc/wireguard# systemctl start [email protected]
Job for [email protected] failed because the control process exited with error code.
See "systemctl status [email protected]" and "journalctl -xe" for details.
Dec 13 05:11:37 tokyo systemd[1]: Starting WireGuard via wg-quick(8) for wg0...
Dec 13 05:11:37 tokyo wg-quick[21045]: [#] ip link add wg0 type wireguard
Dec 13 05:11:37 tokyo wg-quick[21045]: RTNETLINK answers: Operation not supported
Dec 13 05:11:37 tokyo wg-quick[21045]: Unable to access interface: Protocol not supported
Dec 13 05:11:37 tokyo wg-quick[21045]: [#] ip link delete dev wg0
Dec 13 05:11:37 tokyo wg-quick[21045]: Cannot find device "wg0"
Dec 13 05:11:37 tokyo systemd[1]: [email protected]: Main process exited, code=exited, status=1/FAILURE
Dec 13 05:11:37 tokyo systemd[1]: [email protected]: Failed with result 'exit-code'.
Dec 13 05:11:37 tokyo systemd[1]: Failed to start WireGuard via wg-quick(8) for wg0.

찾아보니 wireguard 모듈이 로드되지 않았다고 한다.
mobprobe wireguard 명령을 수행한다.

[email protected]:/etc/wireguard# modprobe wireguard
modprobe: FATAL: Module wireguard not found in directory 

FATAL: Module wireguard not found in directory
.. 일단 재부팅을 해보기로 한다.

reboot
[email protected]:~# lsmod | grep wireguard
wireguard             225280  0
ip6_udp_tunnel         16384  1 wireguard
udp_tunnel             16384  1 wireguard

정상적으로 로드 되었다.

systemctl start [email protected]
[email protected]:/etc/wireguard# ifconfig
wg0: flags=209<UP,POINTOPOINT,RUNNING,NOARP>  mtu 1420
        inet 10.100.100.1  netmask 255.255.255.0  destination 10.100.100.1
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 1000  (UNSPEC)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

인터페이스가 정상적으로 올라온 모습이다.

클라이언트 연결

activate 를 누르면 활성화 된다.

연결된 모습이다.

Linux 서버에 암호화 된 터널을 통한 핑도 정상적인 모습이다.

NAT을 통한 인터넷 사용

이전 까지는 10.100.100.1 만을 연결한 상황이었지만 Wireguard를 통해 인터넷을 연결하려면 설정을 조금 바꿔야 한다.

리눅스 IP Forwarding 활성화
echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
sysctl -p
/etc/wireguard/wg0.conf
[Interface]
Address = 10.100.100.1/24
ListenPort = 33333
PrivateKey = sHrISuTxwuWhsXlkM+6M4qhex6YAFroI/qAEb6DIckY=
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
PublicKey = Vuw89x8GBMv8HVkcBXNkn5kOdnqagfs0v+M8j99m0SU=
AllowedIPs = 10.100.100.2/32

PostUp과 PostDown은 인터페이스가 up또는 down 되고 실행할 명령을 입력한다. %i 는 wg-quick 프로그램이 자동으로 입력해주는 인터페이스다. 해당 인터페이스로 들어온 트래픽을 포워드 허용하겠다는 의미고, MASQURADE가 SNAT을 담당하겠다.
Debian 10의 경우 기본 방화벽이 설정되있지 않아서 FORWARD 허용을 적용하지 않아도 문제안되겠지만..

주의 : 내가 사용한 vultr 클라우드의 인터페이스는 eth0이 아니라 ens3 이었다.

클라이언트측 (Windows)
[Interface]
PrivateKey = cBM71K59+i+e2vMghQ0WJhAP8uRMxIdD0sKN4VRlAUs=
Address = 10.100.100.2/32

[Peer]
PublicKey = D8HDRZDmRATlT7gg4RpynokJbk9NipHLogRWAhr8pyQ=
AllowedIPs = 0.0.0.0/0
Endpoint = 45.76.*.**:33333

핵심은 AllowedIPs = 0.0.0.0/0 이다. 해당 인터페이스를 Default Gateway로 사용한다는 의미이다.

적용
systemctl restart wg-qu[email protected]
테스트

정상적으로 터널을 사용하여 1.0.0.1 에 도달하는 것을 확인할 수 있었다.

부팅 시 자동 실행

서버를 종료해야 할 일이, 또는 서버가 종료되면 새로 켜야되기 때문에 자동실행 되게끔 설정한다.

[email protected]:~# systemctl enable [email protected]
Created symlink /etc/systemd/system/multi-user.target.wants/[email protected] → /lib/systemd/system/[email protected]

마치며

Wireguard는 모 프로토콜IPSec과는 다르게 설정이 매우 간단하다. 비교적 최근에 나온 기술이기 때문에 구 네트워크장비에서는 지원하지 않을 지도 모른다. 그리고 너무 간단한 만큼 기능또한 최소화 되어있고 Layer-2 접속이 되지 않는 문제로 기존의 네트워크를 원격으로 확장하여 접속하여 접속되는 일이 되지 않는다. 멀티캐스트 트래픽을 전달하기에도 무리가 있어보인다. (GRE over Wireguard 라는 방법을?) 하지만 간단하게 원격지와 암호화하여 쓸 수 있고 퍼포먼스 또한 굉장하기 때문에 여러모로 응용하여 쓸 수 있을 것 같다.