はじめに
プライベートネットワークへ外部からVPNで繋げるようにしてみた。
VPNには最近流行りのWireGuardを用いた。
WireGuard
WireGuardは比較的新しいL3VPNプロトコル。
UDPベースで速いのが特徴。
しかも、設定がSSHの設定と同じくらい簡単だと謳っている。
たしかに、wgとwg-quickのmanページを見ると、設定できるパラメータが少なくてシンプルなことがわかる。
環境
インターネット越しにプライベートネットワークへアクセスする。
詳細な構成は以下の通り。
- サーバー
- Ubuntu 18.04(Public IP付き)
- クライアント
- Ubuntu 18.04
- Android
アクセスしたいサーバーのアドレスは172.16.6.1/24
。
プライベートアドレスなのでインターネットから直接アクセスすることはできない。
せっかくなのでAndroidからの接続も試した。
設定
クライアントだけでなくサーバーも公開鍵を作り、お互いの公開鍵を事前に知っておく必要があるのがSSHと違うところ。
サーバー (Ubuntu 18.04)
まずはインストールから。
昔はPPAの設定が必要だったが今はいらない。
/etc/apt/sources.list
に以下のような記述があれば大丈夫。
universe
の前後にmain
, multiverse
, restricted
のような単語が入っていても問題ない。
該当箇所が見つからない場合は以下の内容を追記する。
deb http://jp.archive.ubuntu.com/ubuntu/ bionic-updates universe
リポジトリの設定ができたらインストール。
sudo apt update
sudo apt install wireguard
次は鍵の作成。
rootで作業する。
秘密鍵は/etc/wireguard/privatekey
に保存され、公開鍵は/etc/wireguard/publickey
に保存される。
cd /etc/wireguard
wg genkey | tee privatekey | wg pubkey > publickey
作った鍵を使ってサーバーのコンフィグ(/etc/wireguard/wg0.conf
)を作成
[Interface]
ListenPort = 51820
PrivateKey = [さっき作成したサーバーのPrivate Key]
Address = 10.0.1.1/24
PostUp = ufw limit proto udp from any to [サーバーのPublic IP] port 51820
PostUp = ufw route allow in on %i out on [プライベートネットワークと接続しているインターフェース名]
PostUp = iptables -t nat -A POSTROUTING -s 10.0.1.0/24 -d 172.16.6.0/24 -o [プライベートネットワークと接続しているインターフェース名] -j MASQUERADE
PostDown = ufw delete limit proto udp from any to [サーバーのPublic IP] port 51820
PostDown = ufw route delete allow in on %i out on [プライベートネットワークと接続しているインターフェース名]
PostDown = iptables -t nat -D POSTROUTING -s 10.0.1.0/24 -d 172.16.6.0/24 -o [プライベートネットワークと接続しているインターフェース名] -j MASQUERADE
[Peer]
PublicKey = [これから作成するUbuntuクライアントのPublic Key]
AllowedIPs = 10.0.1.2/32
[Peer]
PublicKey = [これから作成するAndroidクライアントのPublic Key]
AllowedIPs = 10.0.1.3/32
-
Address
- WireGuardの起動時に作成される
wg0
インターフェースに振るアドレス - 好きなPrivateアドレスを使えば良いが、NATの設定もそれに応じて変更する
- WireGuardの起動時に作成される
-
PostUp
,PostDown
- ファイアウォール
-
ufw limit proto udp from any to [サーバーのPublic IP] port 51820
- 外部からVPNサーバーにアクセスできるようにするための設定
-
- NAT
-
iptables -t nat -A POSTROUTING -s 10.0.1.0/24 -d 172.16.6.0/24 -o [プライベートネットワークと接続しているインターフェース] -j MASQUERADE
- プライベートネットワーク(この場合は172.16.6.0/24)で通信するときにちゃんと送信元アドレスをそのサブネット内のアドレスにするための設定
-
- IPフォワード
-
ufw route allow in on %i out on [外部と接続しているインターフェース]
-
wg0
からインターフェースからのパケットが外へ出られるようにするための設定
-
- カーネルの設定
- IPフォワードは本当はカーネルの設定でも許可する必要がある
- 今回はサーバーに
dockerd
が入っているので、カーネルの設定をする必要はない -
dockerd
のデフォルトの設定では自動的に設定してくれる
- 今回はサーバーに
-
dockerd
が入っていない場合や明示的にdockerd
のIPフォワードを無効化している場合は、echo 1 > /proc/sys/net/ipv4/ip_forward
でIPフォワードを有効化する必要がある
- IPフォワードは本当はカーネルの設定でも許可する必要がある
-
- ファイアウォール
-
AllowedIPs
-
Peer
へフォワードするサブネット - サーバ側の設定では対向の
Peer
のプライベートアドレスを書いておけば良い
-
クライアント (Ubuntu 18.04)
サーバーと同じようにWireGuardをインストールし、鍵を作成する。
sudo apt update
sudo apt install wireguard
# ここからroot
cd /etc/wireguard
wg genkey | tee privatekey | wg pubkey > publickey
作った鍵をもとにコンフィグ(/etc/wireguard/wg0.conf
)を書く
[Interface]
ListenPort = 51820
PrivateKey = [いま作成したUbuntuクライントの秘密鍵]
Address = 10.0.1.2/24
[Peer]
PublicKey = [さっき作成したサーバーの公開鍵]
AllowedIPs = 10.0.1.0/24, 172.16.6.0/24
Endpoint = [サーバーのPublic IP]:51820
PersistentKeepalive = 15
-
AllowedIPs
- サーバーとは設定が少し違う
- WireGuardのVPNネットワークとプライベートネットワークとの通信を許可する
-
PersistendKeepAlive
- NATの裏からクライアントがVPN接続した際に、接続が途切れないようにするための設定
最後に今作ったクライアントの公開鍵の情報をサーバーの/etc/wireguard/wg0.conf
に書き込む。
クライアント (Android)
一旦パソコンでコンフィグを書いて、QRで読み込むのが楽。
WireGuardとqrencodeがインストールしてあるパソコンなら何でもOK。
sudo apt update
sudo apt install wireguard qrencode
# ここからroot
cd /etc/wireguard
wg key | tee android_privatekey | wg pubkey > android_publickey
鍵を作成したらコンフィグを書く。
Ubuntuクライアントと異なる箇所はPrivateKey
とAddress
。
[Interface]
ListenPort = 51820
PrivateKey = [いま作成したAndroidクライントの秘密鍵]
Address = 10.0.1.3/24
[Peer]
PublicKey = [さっき作成したサーバーの公開鍵]
AllowedIPs = 10.0.1.0/24, 172.16.6.0/24
Endpoint = [サーバーのPublic IP]:51820
PersistentKeepalive = 15
以下のコマンドで表示されたQRコードをAndroidから読み込む。
ターミナルにQR表示できるのすごい!
qrencode -t ansiutf8 < /etc/wireguard/android.conf
こちらも、今作ったクライアントの公開鍵の情報をサーバーの/etc/wireguard/wg0.conf
に書き込むのを忘れずに。
接続
VPNをつなげて疎通を確認してみる。
サーバー (Ubuntu 18.04)
以下のコマンドでVPNサーバーを立ち上げる。
再起動時も自動で立ち上がる。
systemctl enable wg-quick@wg0
systemctl start wg-quick@wg0
クライアント (Ubuntu 18.04)
こちらは常にVPN接続している必要がないのでenableしない。
systemctl start wg-quick@wg0
サーバーのPrivate IP(10.0.1.1)と疎通できるのが確認できる。
VPNはきちんと繋がっているのがわかる。
$ ping 10.0.1.1 -c 3
PING 10.0.1.1 (10.0.1.1) 56(84) bytes of data.
64 bytes from 10.0.1.1: icmp_seq=1 ttl=64 time=267 ms
64 bytes from 10.0.1.1: icmp_seq=2 ttl=64 time=267 ms
64 bytes from 10.0.1.1: icmp_seq=3 ttl=64 time=267 ms
--- 10.0.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 267.387/267.566/267.858/0.632 ms
次はプライベートネットワークとの疎通の確認。
UFWはデフォルトでICMPのフォワードを許可しているので、プライベートネットワークとの疎通はTCPで確認する。
$ mtr 172.16.6.1 -r -c 3 --tcp -P 22
Start: 2020-12-03T12:12:25+0200
HOST: XXXXXXXXXXX Loss% Snt Last Avg Best Wrst StDev
1.|-- 10.0.1.1 0.0% 3 260.6 260.5 260.4 260.7 0.2
2.|-- 172.16.6.1 0.0% 3 261.2 261.2 261.1 261.3 0.1
クライアント (Android)
VPNの接続はトグルボタンを押すだけ。
同様にサーバーのPrivate IP(10.0.1.1)と疎通できるのが確認できる。
このとき「トンネル対象アプリ」にPingのアプリを選択するのを忘れずに。
TCPの疎通確認はUbuntuで試せたので割愛。
おわりに
VPN接続してプライベートネットワーク内のホストと通信できるのが確認できました。
Androidは設定をQRで読み込め、しかも、VPNで通信するアプリを選べるというのは便利ですね。
この記事を読んで「面白かった」「学びがあった」と思っていただけた方、よろしければ LGTM、Twitter や Facebook、はてなブックマークにてコメントをお願いします!
また DeNA 公式 Twitter アカウント @DeNAxTech では、 Blog 記事だけでなく色々な勉強会での登壇資料も発信しています。ぜひフォローして下さい!
Follow @DeNAxTech