systemd-networkd를 사용하면 WireGuard VPN을 쉽게 구축할 수 있다. 먼저 최소 요구사항으로 리눅스 5.6, systemd 237 이상의 버전이 필요하다. 리눅스 5.6부터 WireGuard가 메인라인 커널에 들어왔고 systemd 237부터 WireGuard를 systemd-networkd로 설정가능하기 때문이다. 그리고 키를 생성하기 위해 wg 명령이 필요하다. Arch Linux에서는 wireguard-tools 패키지로 제공되고 있다.
WireGuard는 기본적으로 서버란 개념이 없다. P2P처럼 IP 주소와 포트 번호, 미리 교환된 공개키를 알고 있으면 연결이 가능하다. 물론 한 피어를 고정된 IP와 포트 번호를 사용하여 마치 서버처럼 사용하는게 가능하다. 보통 하나를 서버로 사용하여 나머지 기기들을 연결하는 경우가 많으므로 아래에서는 서버와 클라이언트로 설명할 것이다.
여기서 설정할 VPN은 172.16.0.0/20 네트워크를 사용할 것이고 서버 주소는 172.16.0.1, 클라이언트 주소는 172.16.0.2로 할당할 것이다.
먼저 사용할 비밀키와 공개키를 생성해야 한다. 서버용 키 한 쌍과 클라이언트용 한 쌍을 생성한다. 클라이언트용 키는 클라이어트 쪽에서 생성하여 공개키만 서버에 넘기는게 안전하지만 여기서는 설명의 편의를 위해 한번에 생성하였다:
$ wg genkey > server.private $ wg pubkey < server.private > server.public $ wg genkey > client.private $ wg pubkey < client.private > client.public
위의 명령을 실행하면 server.private, server.public, client.private, client.public 파일이 생성된다.
systemd-networkd가 WireGuard 인터페이스를 만들기 위해 netdev 설정파일을 만들어야 한다. 아래와 같이 /etc/systemd/network/ 디렉토리에 wg.netdev 파일을 생성한다:
[NetDev] Name=wg0 Kind=wireguard [WireGuard] PrivateKey={server.private 파일 내용} ListenPort={server port}
이렇게하면 wg0라는 인터페이스가 생성된다.
이번에는 클라이언트들의 정보가 저장될 /etc/systemd/network/wg.netdev.d/ 디렉토리를 만든다:
# mkdir /etc/systemd/network/wg.netdev.d/
systemd는 이렇게 설정파일 이름에 .d가 붙은 디렉토리가 있으면 그 안의 .conf 파일도 로드하니 참고하면 좋다. 앞으로 클라이언트를 추가하려면 이 디렉토리에 아래의 설정파일과 같은 형식으로 추가하면 된다.
위에서 만든 디렉토리 안에 클라이언트 정보가 들어있는 설정파일 client1.conf를 생성한다:
[WireGuardPeer] PublicKey={client.public 파일 내용} AllowedIPs=172.16.0.2/32
Allowed IPs에 대해서는 이전 글에 자세히 다루었으므로 참고하기 바란다. WireGuard의 Allowed IPs 설명
인터페이스를 만들었으니 이 인터페이스에 IP를 할당하기 위해 network 설정파일을 만들어야 한다. 아래와 같이 /etc/systemd/network/ 디렉토리에 wg.network 파일을 생성한다:
[Match] Name=wg0 [Network] Address=172.16.0.1/20 IPForward=yes
서브넷 마스크를 /20으로 설정하여 이 대역에 포함된 주소에 대한 라우팅 정보를 암시적으로 생성하고 IPForward를 설정하여 클라이언트가 다른 클라이언트에게 패킷을 보낸 경우 포워딩하여 통신이 가능하게 한다.
이제 클라이언트의 설정을 할 차례이다. 클라이언트도 크게 다르지 않다. 단지 서버의 entrypoint를 추가하여 연결할 수 있도록 할 뿐이다. 서버 때처럼 /etc/systemd/network/ 디렉토리에 wg.netdev를 생성한다:
[NetDev] Name=wg0 Kind=wireguard [WireGuard] PrivateKey={client.private 파일 내용} [WireGuardPeer] PublicKey={server.public 파일 내용} AllowedIPs=172.16.0.0/20 Endpoint={서버 공인 IP}:{server port} PersistentKeepalive=60
클라이언트 쪽에서는 여러 피어를 넣을 일이 없기 때문에 wg.netdev.d/ 디렉토리를 만들지 않고 wg.netdev 파일에 바로 피어 정보를 넣었다. 그리고 서버와 달리 Endpoint와 PersistentKeepalive라는 설정이 추가되었다. 클라이언트의 IP는 계속 바뀔 수 있지만 서버의 주소는 그렇지 않기 때문에 클라이언트만 Endpoint 설정을 넣어서 서버로 접속하도록 한다. 또한 PersistentKeepalive 설정으로 지속적으로 서버에 keepalive 패킷을 보내서 연결을 계속 유지시키는 것도 가능하다. 이 설정 값은 초 단위다. 이건 필요없다면 없애도 무방하다.
/etc/systemd/network/ 디렉토리에 wg.network를 생성한다:
[Match] Name=wg0 [Network] Address=172.16.0.2/20
이제 systemd-networkd를 재시작하면 인터페이스와 IP가 생성되어 있을 것이다.
# systemctl restart systemd-networkd
서버에 핑을 보내보면 응답이 오는걸 확인할 수 있다.