raspbian wiregardサーバー化(SDboot+USBroot)

#はじめに
VPNプロトコルとしてWiregardがLinuxカーネル5.6にマージされました。
PPTPよりセキュアでIPSecより簡易なようで、今後使う機会が出てくるかもしれないと思い、余っていたRaspberry pi 2 model B rev1.1でVPNサーバーを作ってみます。
raspbian-buster-liteの2020-02-13版を使用します。

# SDboot+USBroot化

一応サーバーなのでSDカードで運用するのは不安がありますので、SSDなどをUSBに接続してUSBブートにしておきたいです。
しかし、2020/5/10時点で正式にUSBブート出来るRaspberry piは以下のものになります。

* Raspberry pi 2 model B rev 1.2
* Raspberry pi 3 model B/B+

今回使用しようとしているボードはこれに当てはまりません。

なお、リビジョンなど不明な場合は、以下のコマンドで確認出来ますので、適当にraspbianを起動して確認して下さい。

```bash
pi@raspberrypi:~ $ cat /proc/device-tree/model
Raspberry Pi 2 Model B Rev 1.1
```

対応出来ないとあきらめるて、高品質SDで運用してもいいですが、わざわざ追加投資したくないので、Raspberry pi 1 の頃から多々事例のあるSDカードでブートし、root領域を別ストレージにする方法を適用しようと思います。
(なお、この手法はRaspberry pi4にも適用出来るはずです。[未確認])

## 準備

いろいろ手順がありますが、今回は以下の手順で行います。

1. SDカードで通常起動
1. USBストレージ準備
1. USBストレージ内の領域をroot領域にする

raspbianのサイズから、SDカードは2GB以上のものが最初に必要になります。
(boot用のSDカードは、boot領域のみ必要ですので、bootのみの256MB程度のSDカードに差し替える事も出来ます。今回はやりません。)
今回は手元にあった2BGのSDカードと4GBのUSBメモリで手順を進めます。

### SDカードで起動

SDカードにraspbianを書き込み、USBメモリを接続して起動します。
(私はsshを有効化し、ディスプレイなどは無しにしています。このあたりの操作は解説しませんので、何らかの方法でログインし、コマンドを実行できるようにして下さい。)
SDカードは/dev/mmcblk0、USBメモリは私の環境では/dev/sdaになりましたので、コマンドはこれに合わせています。

### USBストレージ準備

USBストレージの全領域をpartedコマンドでext4パーティションにします。
(すでに使用した事があるUSBメモリでは、パーティションの削除などを行って下さい。)

```bash
pi@raspberrypi:~ $ sudo parted /dev/sda
GNU Parted 3.2
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) mklabel gpt
Warning: The existing disk label on /dev/sda will be destroyed and all data on this disk will be lost. Do you want to
continue?
Yes/No? yes
(parted) mkpart primary ext4 0% 100%
(parted) p
Model: Generic USB Flash Disk (scsi)
Disk /dev/sda: 4074MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system  Name     Flags
 1      1049kB  4073MB  4072MB  ext4         primary

(parted) q
Information: You may need to update /etc/fstab.
```

作成した領域に、SDカードのroot領域である/dev/mmcblk0p2をコピーします。
(ddを使用しますので要注意、ifとofの指定を間違えるとデータが消え、書き込みからやり直しになります。)

```bash
pi@raspberrypi:~ $ sudo dd if=/dev/mmcblk0p2 of=/dev/sda1 bs=32M conv=noerror,sync status=progress
1711276032 bytes (1.7 GB, 1.6 GiB) copied, 280 s, 6.1 MB/s
50+1 records in
51+0 records out
1711276032 bytes (1.7 GB, 1.6 GiB) copied, 315.463 s, 5.4 MB/s
```

サイズの違うパーティションのデータをコピーしたので、サイズ情報などがずれた状態になっています。
これをe2fsckとresize2fsで修復します。

```bash
pi@raspberrypi:~ $ sudo e2fsck -f /dev/sda1
e2fsck 1.44.5 (15-Dec-2018)
rootfs: recovering journal
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
Free blocks count wrong (122034, counted=81319).
proc            /proc           proc    defaults          0       0
Fix<y>? yes
console=serial0,115200 console=tty1 root=PARTUUID=e68eb608-224a-4209-bcb8-16a11bce5c55 rootfstype=ext4 elevator=deadlineFree inodes count wrong (59995, counted=59936).
Fix<y>? yes

rootfs: ***** FILE SYSTEM WAS MODIFIED *****
rootfs: 44480/104416 files (0.3% non-contiguous), 332377/413696 blocks
pi@raspberrypi:~ $ sudo resize2fs /dev/sda1
resize2fs 1.44.5 (15-Dec-2018)
Resizing the filesystem on /dev/sda1 to 994048 (4k) blocks.
The filesystem on /dev/sda1 is now 994048 (4k) blocks long.
```

e2fsckは何度か「`Fix<y>?`」と問い合わせが発生しますので、発生する都度「y(yes)」を入力して下さい。

#### USBストレージ内の領域をroot領域にする

データ領域は準備出来ましたので、/dev/sda1をroot領域にする様操作します。
  
まず、パーティションのuuidを確認します。

```bash
pi@raspberrypi:~ $ ls -l /dev/disk/by-partuuid/
total 0
lrwxrwxrwx 1 root root 15 Feb 13 16:10 738a4d67-01 -> ../../mmcblk0p1
lrwxrwxrwx 1 root root 15 Feb 13 16:10 738a4d67-02 -> ../../mmcblk0p2
lrwxrwxrwx 1 root root 10 May 10 09:21 e68eb608-224a-4209-bcb8-16a11bce5c55 -> ../../sda1
```

このuuidを使用して/boot/cmdline.txtを修正します。

```bash
pi@raspberrypi:~ $ sudo vi /boot/cmdline.txt
console=tty1 root=PARTUUID=738a4d67-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
↓
console=tty1 root=PARTUUID=e68eb608-224a-4209-bcb8-16a11bce5c55 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
```

「root=PARTUUID=738a4d67-02」を「root=PARTUUID=e68eb608-224a-4209-bcb8-16a11bce5c55」に変更します。
  
再起動してデータ領域を確認すると以下の様になっています。

```bash
pi@raspberrypi:~ $ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root       3.8G  1.3G  2.3G  35% /
devtmpfs        459M     0  459M   0% /dev
tmpfs           464M     0  464M   0% /dev/shm
tmpfs           464M   18M  446M   4% /run
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           464M     0  464M   0% /sys/fs/cgroup
/dev/mmcblk0p1  253M   53M  200M  21% /boot
tmpfs            93M     0   93M   0% /run/user/1000
```

このままでも問題はないようですが、念のため/etc/fstabも修正します。

```bash
pi@raspberrypi:~ $ sudo vi /etc/fstab
proc            /proc           proc    defaults          0       0
PARTUUID=738a4d67-01  /boot           vfat    defaults          0       2
PARTUUID=738a4d67-02  /               ext4    defaults,noatime  0       1
# a swapfile is not a swap partition, no line here
#   use  dphys-swapfile swap[on|off]  for that
↓
proc            /proc           proc    defaults          0       0
PARTUUID=738a4d67-01  /boot           vfat    defaults          0       2
PARTUUID=e68eb608-224a-4209-bcb8-16a11bce5c55  /               ext4    defaults,noatime  0       1
# a swapfile is not a swap partition, no line here
#   use  dphys-swapfile swap[on|off]  for that
```

「PARTUUID=738a4d67-02」を「PARTUUID=e68eb608-224a-4209-bcb8-16a11bce5c55」に修正します。
  
問題なく再起動出来たら、「raspi-config」などを使用し、必要な初期設定を行って下さい。
IPアドレス固定と、ホスト名変更は行う事をお勧めします。

# wireguard(サーバー)

## インストール

各種 OS のインストール方法は公式サイトで紹介されています。
[https://www.wireguard.com/install/](https://www.wireguard.com/install/)
  
raspbianは正規リポジトリにパッケージがありませんので、公式ドキュメントには説明が内容です。
他に参考にできるドキュメントを探すと、denianのリポジトリを使用する方法をいろいろな方が実践しているようです。
私はその中で以下のドキュメントを参考にしました。
[https://github.com/adrianmihalko/raspberrypiwireguard](https://github.com/adrianmihalko/raspberrypiwireguard)
(Raspberry Pi 2 v1.2 and above)となっていますが特に問題ないようです。

```bash
pi@raspberrypi:~ $ sudo apt-get update
pi@raspberrypi:~ $ sudo apt-get upgrade
pi@raspberrypi:~ $ sudo apt-get install raspberrypi-kernel-headers
pi@raspberrypi:~ $ echo "deb http://deb.debian.org/debian/ unstable main" | sudo tee --append /etc/apt/sources.list.d/unstable.list
pi@raspberrypi:~ $ sudo apt-get install dirmngr
pi@raspberrypi:~ $ wget -O - https://ftp-master.debian.org/keys/archive-key-$(lsb_release -sr).asc | sudo apt-key add -
pi@raspberrypi:~ $ printf 'Package: *\nPin: release a=unstable\nPin-Priority: 150\n' | sudo tee --append /etc/apt/preferences.d/limit-unstable
pi@raspberrypi:~ $ sudo apt-get update
pi@raspberrypi:~ $ sudo apt-get install wireguard
pi@raspberrypi:~ $ sudo reboot
```

/etc/sysctl.conf を編集し、「net.ipv4.ip_forward」の項目を 1 にする。

```bash
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1
```

## 鍵作成

サーバー側とクライアント用の秘密鍵と公開鍵を作成します。
ファイルの置き場所はsshと分けるので、「~/wgkeys」に生成します。

```bash
pi@raspberrypi:~ $ mkdir wgkeys
pi@raspberrypi:~ $ cd wgkeys  
pi@raspberrypi:~/wgkeys $ wg genkey > server_private.key  
Warning: writing to world accessible file.
Consider setting the umask to 077 and trying again.

pi@raspberrypi:~/wgkeys $ wg pubkey > server_public.key < server_private.key
pi@raspberrypi:~/wgkeys $ wg genkey > client1_private.key  
Warning: writing to world accessible file.
Consider setting the umask to 077 and trying again.
pi@raspberrypi:~/wgkeys $ wg pubkey > client1_public.key < client1_private.key
pi@raspberrypi:~/wgkeys $ ls
client1_private.key client1_public.key server_private.key server_public.key
```

次の作業で必要になるので、各鍵の中身を確認します。

```bash
pi@raspberrypi:~/wgkeys $ cat server_private.key
yBjQRFeYKDocbXwvFaeJIGZlxncgz5UBTkQynxvAtHs=
pi@raspberrypi:~/wgkeys $ cat server_public.key
xKA7PQDN/+eIPaSO9gxnIgeyqtEeLkpMLLhD/YnAewQ=
pi@raspberrypi:~/wgkeys $ cat client1_private.key
0GUNsRgb/j428Ftkh1v0KcshtWyIskkjOzNsTYheQXc=
pi@raspberrypi:~/wgkeys $ cat client1_public.key
QYieIYVjL6FUe+PEK+PYfTvMeq+jNJOaLe/ZX8+aznI=
```

## サーバー設定ファイル

設定ファイル`/etc/wireguard/wg0.conf`を作成します。

```bash
pi@raspberrypi:~/wgkeys $ sudo vi /etc/wireguard/wg0.conf
[Interface]
#自分のIPアドレスを指定
Address = 192.168.200.1/24
#待ち受けポート
ListenPort = 51820

#サーバー側秘密鍵
PrivateKey = yBjQRFeYKDocbXwvFaeJIGZlxncgz5UBTkQynxvAtHs=
#replace eth0 with the interface open to the internet (e.g might be wlan0 if wifi)
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
#Client1の公開鍵
PublicKey = QYieIYVjL6FUe+PEK+PYfTvMeq+jNJOaLe/ZX8+aznI=
#WireGuard経由で通信するネットワーク
AllowedIPs = 192.168.200.215/32
```

`Address`については、元々のLANと違うサブネットになる様にする。
同一にした場合、接続元LANと区別がつかずルーティングに支障が出るようで通信不全になってしまう。

今回は元々のアドレスは`192.168.25.96/24`、VPNアドレスは`192.168.200.1/24`として設定します。

## サーバー起動(wg0インターフェース起動)

`wg-quick`コマンドでサーバーを起動。

```bash
pi@raspberrypi:~/wgkeys $ sudo wg-quick up wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 192.168.200.1 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] ip -4 route add 192.168.200.215/32 dev wg0
[#] iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
```

`wg`コマンドでサーバーの状態を確認。

```bash
pi@raspberrypi:~/wgkeys $ sudo wg
interface: wg0
  public key: xKA7PQDN/+eIPaSO9gxnIgeyqtEeLkpMLLhD/YnAewQ==
  private key: (hidden)
  listening port: 51820

peer: QYieIYVjL6FUe+PEK+PYfTvMeq+jNJOaLe/ZX8+aznI=
  allowed ips: 192.168.200.215/32
```

起動している事を確認出来たら、サービスに登録。

```bash
pi@raspberrypi:~/wgkeys $ sudo systemctl enable wg-quick@wg0
Created symlink /etc/systemd/system/multi-user.target.wants/wg-quick@wg0.service → /lib/systemd/system/wg-quick@.service.
```

# wireguard(クライアント)

Linuxをクライアントにする方法は、公式ドキュメントや各解説記事が充実していますので割愛します。
windows10とAndroidについては、[公式アプリ](https://www.wireguard.com/install/)に設定ファイルを読み込ませるだけですので、難しくはありませんが、Windows10について設定法を記載します。

## クライアント設定ファイル

設定ファイル`clientwg.conf`を作成します。
クライアントマシン上に作成して下さい。

```conf
[Interface]
#Client1の秘密鍵
PrivateKey = 0GUNsRgb/j428Ftkh1v0KcshtWyxxskjOzNsTYheQXc=
#Client1に付与するIPアドレス
Address = 192.168.200.215/24

[Peer]
#サーバーの公開鍵
PublicKey = xKA7PQDN/+eIPaSO9gxnIgeyqtEevLpMLLhD/YnAewQ=
#サーバーのアドレスまたはドメイン名とポート番号
Endpoint = 192.168.25.96:51820
# or
Endpoint = example.com:51820

#WireGuard経由で通信するネットワーク
AllowedIPs = 192.168.25.0/24,192.168.200.0/24
```

このファイルはWindows/Linux/Androidで使用出来ます。
(MacOS/iOSは環境がないため未確認です。)

## クライアント設定

クライアントソフトをインストールして起動します。
以下の画面が表示されるので、右下にある「トンネル追加」ボタンをクリックして下さい。
![wireguard01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593720/20c303aa-107d-1739-b6cc-b5bdeec98454.jpeg)
ファイル選択画面になりますので、作成した`clientwg.conf`を選択して下さい。
ファイルが読み込まれると、以下の様にトンネルの設定が行われます。
![wireguard02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593720/8c664050-a63a-c37f-2d44-43557308bb9d.jpeg)
インターフェースに表示されている「有効化」ボタンで有効化します。
成功すると以下の画面になります。
![wireguard03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593720/92499ef7-36d2-1408-cb26-2691d9948b36.jpeg)

失敗する場合、サーバー・クライアントの設定を再度確認して下さい。

接続成功したらコマンドプロンプトかpwoershellで`ipconfig`を実行すると、以下の様な情報を取得出来ます。

```powershell
> ipconfig
・・・・・
不明なアダプター clientwg:

   接続固有の DNS サフィックス . . . . .:
   IPv4 アドレス . . . . . . . . . . . .: 192.168.200.215
   サブネット マスク . . . . . . . . . .: 255.255.255.0
   デフォルト ゲートウェイ . . . . . . .:
・・・・・
```

これでクライアントからIPベースアクセスでLAN内と通信する事が出来る様になります。

#おわりに
単純に接続するだけであればIPsecよりかなり簡単にVPN接続出来たと思います。
今回出来なかった点としては、以下などがあります。

* DHCPと連携させる事が出来ず、固定IP環境になる
* ホスト名ではなくIPアドレスでアクセスする必要がある
* 共有鍵では無いので、クライアントを追加するたび設定ファイルを修正する必要がある

今後解消出来たら、続編を書くかもしれません。