WireGuardを使って自宅環境とVPSとクライアント端末を接続する

# つくるもののイメージ

![スクリーンショット 2020-12-17 0.28.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8190/4558ae84-00f1-2d23-f1eb-46d17adaecbd.png)

# はじめに
昨年のアドベントカレンダーでは、SwitchBotの温湿度計を用いて、自宅の温度、湿度を取得する方法について記載しました。
この温湿度計はNode-REDを使ったAPI機能は停止していますが、日々の温湿度を記録し続けています。
一方で、おうちハックをしようとすると、デバイスが自宅に物理的に存在するため、家の外からでは開発、メンテナンスが中々難しいものがあります。
これを解決するためには、自宅の環境内に外出先からアクセスできる必要があり、VPNの活用がすぐに思いつく手段かと思います。
※今年は新型コロナウイルスの影響で、家にいることが多いため、あまりニーズはないかもしれません。

# 回線上の課題
VPNを使った自宅環境へのアクセス方法として、必要なものは最低限２つ必要かと思います。

- パブリックIPアドレス
- VPNサーバ

パブリックIPアドレスは、インターネットと自宅の出入り口のアドレスであり、外出先からはこのIPアドレスが自宅環境の所在地となります。固定IPである必要はなく、DDNSを活用することで、動的なIPアドレスにも対応することができます。
また、VPNサーバに関しても最近の家庭用ルータに機能として搭載されているものが多いと思いますので、利用ハードルは低いと思います。

しかし、このパブリックIPアドレスですが、家庭で利用している回線によっては、自宅の出入り口を示すことができないことがあります。

自宅で利用しているDS-Lite(Dual-Stack Lite)によるIP v4 over IPv6環境では、自宅のルータにパプリックIPアドレス（IPv4）が付与されず、プロバイダ側に付与されます。
そのため自分でNATのコントロールをすることができず、ポートの開放や、自宅サーバの公開などが行うことが難しいです。

# 解決方法の検討
こういったDS-Liteを用いている場合において、自宅へのアクセス経路を確保する方法として考えられるのは、自宅ルータにPPPoEの接続経路を追加することで

- 自宅からインターネットへの接続はDS-Lite(IPoE)を使う
- インターネットから自宅への接続はPPPoEを使う

といった使い分けをすることが考えられます。この使い分けをする方法でも良いのですが、今回はインターネットからの接続の出入り口を自宅ルータではなくクラウド上のサーバを経由する方式を検討しようと思います。

# 全体の構成

機材を入れたときの概念図
![スクリーンショット 2020-12-17 0.57.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8190/68deb3fc-aba8-3bd6-3b98-4951cff2aafc.png)

Amazon Lightsailで構築するVPNサーバに対して、自宅サーバからVPNセッションを貼り、リモートからの端末はLightsailにVPN接続をします。
そして、リモート端末はLightsailと自宅サーバ間のVPNを経由して自宅の各種端末にアクセスする構成をとります。

# WireGuardとは
VPNを構築するにはIPSecやOpenVPNなど様々ツール、実装があります。
その中でも今回は[WireGuard](https://www.wireguard.com/)を使って本構成を構築したいと思います。

WireGuardはオープンソースのVPNサーバソフトウェアで、シンプルかつ高速で、利用できる暗号化の強度も高いという特徴が公式サイトに書かれています。

公式サイトに書かれている特徴は以下のものがあります。

- Simple & Easy-to-use
- Cryptographically Sound
- Minimal Attack Surface
- High Performance
- Well Defined & Thoroughly Considered

こうした特徴のWireGuardを用いて前述したVPNの構成を構築していきます。

# それぞれの実装
この構成を作るにあたって、登場するネットワークは3つあります。それぞれ下記のIPアドレスとします。

- 自宅サーバがある自宅ネットワーク： 192.168.11.0/24
- Lightsailと自宅サーバ間のVPN： 10.0.1.0/24
- Lightsailと各種端末の間のVPN： 10.0.2.0/24

## 自宅サーバ・Lightsail共通項目
### WireGuardのインストールと設定
両方Ubuntu18.04を使っています。

WireGuardのインストールを行います。
現在のLTSであるUbuntu20.04.xを使えば、リポジトリの追加は不要です。

```
$ sudo add-apt-repository ppa:wireguard/wireguard
$ sudo apt-get update
$ sudo apt-get install wireguard
```

IPv4 forwardingの追加

```/etc/sysctl.conf
net.ipv4.ip_forward = 1
```

設定の反映

```
$ sudo sysctl -p
```

各々で必要となる、秘密鍵と公開鍵の生成

```
$ wg genkey | tee privatekey | wg pubkey > publickey
$ cat publickey
　<それっぽい英数が出力>
$ cat privatekey
　<それっぽい英数が出力>
```

この秘密鍵と公開鍵はそれぞれの端末ごとに生成する必要があります。

- 自宅サーバの秘密鍵と公開鍵
- Lightsailの秘密鍵と公開鍵
- 各種端末の秘密鍵と公開鍵



## AWS Lightsail

Lightwailは自宅サーバからのアクセスと各種端末からのアクセスの両方があるので、
それぞれwg0.conf、wg1.confの2つを用意しています。
それぞれの設定項目の概要

[Interface]にはVPNサーバとしての設定を記載し、[Peer]にはクライアント側の情報を記載します。

|項目名|設定内容|
|---|---|
|Address|VPNに用いるIPアドレス|
|ListenPort|WireguardがListenするポート番号 wg0とwg1で別のポートにする。ufw等でポートを開けておくことが必要|
|PrivateKey|サーバ側の秘密鍵で、サーバ側で生成する。|
|PublicKey|クライアント側の公開鍵で、クライアント側で生成する。|
|AllowedIPs|WireGuardのに接続するクライアントのVPN用IPアドレス。単なる接続許可IPではなく、ルーティングにも利用されるため、VPNの先のIPアドレスも合わせて記載する。0.0.0.0/0を書くとクライアント端末の全ての通信がVPN吸い込まれていく。|

自宅サーバとの接続用

```wg0.conf
[Interface]
Address = 10.0.1.1
ListenPort = <任意のポート>
PrivateKey = <PrivateKey>

[Peer]
PublicKey = <自宅サーバのPublic Key>
AllowedIPs = 10.0.1.2/32, 10.0.1.3/32, 192.168.11.0/24
```

各種端末からの接続用

```wg1.conf
[Interface]
Address = 10.0.2.1
ListenPort = <任意のポート>
PrivateKey = <Private Key>

[Peer]
PublicKey = <例 iPhoneのPublic Key>
AllowedIPs = 10.0.2.2/32 (iPhoneでVPN接続をしたら、このIPがつく）

[Peer]
PublicKey = <例 iPadのPublic Key>
AllowedIPs = 10.0.2.3/32 (MacでVPN接続をしたら、このIPがつく）

[Peer]
PublicKey = <例 MacのPublic Key>
AllowedIPs = 10.0.2.4/32 (iPadでVPN接続をしたら、このIPがつく）
```
WireGuardを起動します。

```
# wg-quick up wg0
# wg-quick up wg1
```


## 自宅サーバ
次に自宅サーバ側の設定です。
自宅サーバは192.168.11.0/24のネットワークに所属しており、VPN用には10.0.1.0/24のネットワークを設定します。
本構成では自宅サーバはクライアントとして接続をします。[Peer]に書くべき内容はLightsailへの接続情報となります。

```wg0.conf
[Interface]
Address = 10.0.1.2/24
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT
ListenPort = <任意のポート>
PrivateKey = <自宅サーバの秘密鍵>

[Peer]
PublicKey = <Lightsailの公開鍵>
AllowedIPs = 10.0.1.0/24, 10.0.2.0/24 (自宅サーバ↔Lightsail間、Lightsail↔各種端末間のネットワークを記載）
Endpoint = <LightsailのパブリックIPアドレス>:<LIghtsail側で設定した任意のポート>
PersistentKeepalive = 25 (NAT環境で必要なKeepAlive送信間隔 単位は秒)
```

WireGuardを起動します。

```
# wg-quick up wg0
```

この状態で無事起動したら状態の確認を行います。

```
# wg
```

接続がうまくいっていれば、こういった出力になります。

```
interface: wg0
  public key: <公開鍵>
  private key: (hidden)
  listening port: 51620

peer: <Lightsailの公開鍵>
  endpoint: <LightsailのIP>:<Lightsail側で設定したポート>
  allowed ips: 10.0.1.0/24, 10.0.2.0/24
  latest handshake: 52 seconds ago
  transfer: 639.25 KiB received, 6.08 MiB sent
  persistent keepalive: every 25 seconds
```

## Mac
WireGuardのアプリがMacApp Storeにあります。 https://apps.apple.com/jp/app/wireguard/id1451685025?mt=12 (AppStoreが開きます。）
起動したら左下の+ボタンからLightsailへのアクセス経路を追加します。
秘密鍵と公開鍵は+ボタンを押せば自動的に生成されて、テンプレートが表示されます。
※AppStoreのが使えない場合は、Homebrewで`brew install wireguard-tools`を実行して設定してください。

試しに+ボタンを押したもの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8190/38394a32-1c02-530c-c34d-69647fa47235.png)
ここに出力されている内容を書き換えて、こういった形にします。

```
[Interface]
PrivateKey = <自動的に生成されたもの>
Address = 10.0.2.4/32

[Peer]
PublicKey = <Lightsailの公開鍵>
AllowedIPs = 10.0.1.0/24, 10.0.2.0/24, 192.168.11.0/24
Endpoint = <LightsailのIP>:<Lightsail側で設定したポート>
PersistentKeepalive = 25
```

# 接続確認
## Mac

MacについているデバイスのIPアドレスを見ると172.20.10.7

```shell

$ ifconfig en0
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	options=400<CHANNEL_IO>
	ether f0:xx:xx:xx:96:6f
	inet6 fe80::xxx:x111:xxxx:xxb3%en0 prefixlen 64 secured scopeid 0x6
	inet 172.20.10.7 netmask 0xfffffff0 broadcast 172.20.10.15
	nd6 options=201<PERFORMNUD,DAD>
	media: autoselect
	status: active
```

WireGuardの状態を確認（これはhomebrewで入れたものです）

```shell

$sudo wg
interface: utun6
  public key: <Macの公開鍵>
  private key: (hidden)
  listening port: 53979

peer: <Lightsailの公開鍵>
  endpoint: <LightsailのIP>:<Lightsailのポート>
  allowed ips: 10.0.1.0/24, 10.0.2.0/24, 192.168.11.0/24
  latest handshake: 2 minutes, 9 seconds ago
  transfer: 476 B received, 692 B sent
  persistent keepalive: every 25 seconds

```

```shell

$ ping 192.168.11.45
PING 192.168.11.45 (192.168.11.45): 56 data bytes
64 bytes from 192.168.11.45: icmp_seq=0 ttl=63 time=701.324 ms
64 bytes from 192.168.11.45: icmp_seq=1 ttl=63 time=111.772 ms
64 bytes from 192.168.11.45: icmp_seq=2 ttl=63 time=136.809 ms
```

timeは遅いですが、無事自宅のIPアドレスと接続できていることがわかります。

## Lightsail
Lightsailでwgを打つとこういった状態になります。

```shell

$ wg
interface: wg0
  public key: <公開鍵>
  private key: (hidden)
  listening port: <Port>

peer: <公開鍵>
  endpoint: <IP>:12580
  allowed ips: 10.0.1.2/32, 10.0.1.3/32, 192.168.11.0/24
  latest handshake: 1 minute, 14 seconds ago
  transfer: 30.60 MiB received, 7.77 MiB sent

interface: wg1
  public key: <公開鍵>
  private key: (hidden)
  listening port: 5551

peer: <公開鍵>
  endpoint: <IP>:42928
  allowed ips: 10.0.2.2/32
  latest handshake: 34 seconds ago
  transfer: 1.46 MiB received, 5.82 MiB sent

peer: <公開鍵>
  endpoint: <IP>:61166
  allowed ips: 10.0.2.3/32
  latest handshake: 9 days, 4 hours, 34 minutes, 58 seconds ago
  transfer: 391.76 KiB received, 559.13 KiB sent

peer: <公開鍵>
  endpoint: <IP>:42526
  allowed ips: 10.0.2.4/32
  latest handshake: 1 minute, 44 seconds ago
  transfer: 522.74 KiB received, 273.48 KiB sent
```

自宅サーバで設定している10.0.1.2/32と
Macで設定している10.0.2.4/32のlast handshakeが1分44秒前と接続が確認できます。

# おわりに
これでパブリックIPアドレスやポート開放を自由に行えない自宅環境においても自宅外から通信を行うことができるようになりました。
冒頭にも書いたとおり、新型コロナウイルスの影響でリモートから家という機会が減りつつあるとは思いますが、いつでもどこでもおうちハックをできる環境を作ることができます。