OpenVPN TAP/TUN 混合環境で、TAPクライアント側からTUNクライアント側のネットワークにルーティングする

[前回の記事](https://qiita.com/Takezoh/items/329081779c57abf3b59a)でブリッジモードよる VPN 環境を構築し、リモートワークでの作業効率は確保できているが、オフィスに残されている物理マシンのメンテナンスのために出社する必要性が残っている。
オフィス環境の都合により、サイト間VPNやポートマッピングが利用できない為、オフィス側に OpenVPN クライアントを設置して AWS とトンネルを張る。
利用者側は VPN の切り替えや複数接続の設定を行わなくて良いように、既に構築している TAP モードのVPNから、オフィス側（OpenVPN のクライアント側）ネットワークにアクセスできるようにしたい。

OpenVPN 互換の AWS Client VPN は Client to Client な接続ができないため、ここでも EC2 上に OpenVPN を構築する。

# ルーティングモード (TUN) の VPN を構築

オフィスのネットワークはネットワークアドレスが異なる為、IPルーティングが可能な TUN モードの VPN サーバーを新規に構築。

## IP Foward を有効化

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

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

```
port 1194
proto udp

dev tun0

ca ca.crt
cert server.crt
key server.key  # This file should be kept secret
dh dh2048.pem

server 10.8.0.0 255.255.255.0

ifconfig-pool-persist /var/log/openvpn/ipp-office.txt
client-config-dir ccd
route 192.168.133.0 255.255.255.0

keepalive 10 120

cipher AES-256-GCM
compress lz4-v2
push "compress lz4-v2"

user nobody
group nogroup

persist-key
persist-tun

status /var/log/openvpn/openvpn-status-office.log
log         /var/log/openvpn/openvpn-office.log
log-append  /var/log/openvpn/openvpn-office.log
verb 3
explicit-exit-notify 1

push "route-metric 20"
engine aesni
```
TAPクライアントからTUNクライアントへの接続は次の通りTUNクライアント同士の接続ではないため `client-to-client` は必要ない。

`TAPクライアント => TAPサーバー => TUNサーバー => TUNクライアント`

オフィス（クライアント側）のネットワークへの経路は VPN を通る様に設定する

`route 192.168.133.0 255.255.255.0`

### TUNサーバーのクライアント個別設定

`192.168.133.0/24` は `office` クライアントを経由させる

```:/etc/openvpn/ccd/office
iroute 192.168.133.0 255.255.255.0
```

## TUNクライアントの設定
[前回の記事](https://qiita.com/Takezoh/items/329081779c57abf3b59a)のクライアント設定とほぼ同じ。
接続先と接続モードを変更するだけ。

```
dev tun
remote SERVER_ADDR 1194
```

## TUNサーバーを起動しルーティングテーブルを確認

今回は TAPサーバーと TUNサーバーを同じインスタンスに立てているので両方の経路情報が表示されている。

```
$ netstat -nr
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         10.10.21.1      0.0.0.0         UG        0 0          0 br0
10.8.0.0        10.8.0.2        255.255.255.0   UG        0 0          0 tun0
10.8.0.2        0.0.0.0         255.255.255.255 UH        0 0          0 tun0
10.10.21.0      0.0.0.0         255.255.255.0   U         0 0          0 br0
10.10.21.1      0.0.0.0         255.255.255.255 UH        0 0          0 br0
192.168.133.0   10.8.0.2        255.255.255.0   UG        0 0          0 tun0
```
`10.10.21.0/24` TAPネットワーク
`10.8.0.0/24` TUNネットワーク
`192.168.133.0/24` TUNクライアント側ネットワーク


## TUNクライアントのルーティングテーブルも確認

```
$ netstat -nr
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         192.168.133.1   0.0.0.0         UG        0 0          0 eth0
10.8.0.1        10.8.0.5        255.255.255.255 UGH       0 0          0 tun0
10.8.0.5        0.0.0.0         255.255.255.255 UH        0 0          0 tun0
192.168.133.0   0.0.0.0         255.255.255.0   U         0 0          0 eth0
192.168.133.1   0.0.0.0         255.255.255.255 UH        0 0          0 eth0
```
`10.8.0.0/24` TUNネットワーク
`192.168.133.0/24` ローカルネットワーク

# TAPサーバーの設定を修正

TAPサーバーに接続しているクライアントに `192.168.133.0/24` の経路情報をプッシュする。

```:/etc/openvpn/server.conf
push "route 192.168.133.0 255.255.255.0"
```


# NAT テーブルを編集

上記までで TUN VPN の設定は完了だが、このままではクライアント側のネットワークからパケットが返送できない為、アクセスできない。

![名称未設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1083/e23b4989-0c31-fcda-b0ea-167a81c0b88e.png)

`10.10.21.100(送信元)` => `10.10.21.5 <> 10.8.0.1(経由)` => `10.8.0.5(送信先)`
このような送信経路の場合、パケットを受け取った `10.8.0.5` は `10.10.21.0/24` への経路を知らないため戻りのパケットを送信することが出来ない。
単純に `10.8.0.5` の TUN Client に `10.10.21.0/24` への経路情報を追加するだけでは、`192.168.133.0/24` 内のデフォルトゲートウェイに `10.10.21.0/24` へは TUN Client を経由するように設定しなければ Jenkins Cluster 等に TUN Client 越しに接続することはできない。

今回は経由サーバーで IPマスカレード（[ネットワークアドレス変換](https://ja.wikipedia.org/wiki/%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E5%A4%89%E6%8F%9B)）を行い、送信元アドレスを経由サーバーのアドレスに書き換えることで解決する。

### TUNサーバーのNATテーブルを編集

送信元が `10.10.21.0/24` で宛先が `tun0` のパケットのアドレスを書き換える。

```
iptables -t nat -A POSTROUTING -s 10.10.21.0/24 -o tun0 -j MASQUERADE
```

### TUNクライアントのNATテーブルを編集

送信元が `10.8.0.0/24` で宛先が `eth0` のパケットのアドレスを書き換える。

```
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
```

## 疎通確認

```
$ ping 192.168.133.1
PING 192.168.133.1 (192.168.133.1) 56(84) bytes of data.
64 bytes from 192.168.133.1: icmp_seq=1 ttl=128 time=3.82 ms
```

これで TAP クライアントから TUNクライアント側のネットワークへ接続できる。

今回は TAPサーバーと TUNサーバーを同じインスタンス上に構築したが、別インスタンスの場合は、サブネットのルートテーブルを編集する必要がある。

# TAPクライアント側ネットワークへルーティングする

上記のように複雑な構築をしなくとも、TAPクライアント側ネットワークへルーティングさせる事は可能。

### TAPサーバー側のクライアント個別設定

ルーティングしたいクライアントのIPを固定する

```:/etc/openvpn/ccd/office
ifconfig-push 10.10.21.6 255.255.255.0
```

### TAPサーバーのルーティングテーブルを編集

`192.168.133.0/24` へは固定した TAP Client `10.10.21.6` を経由するように設定する。

```
route add -net 192.168.133.0 gw 10.10.21.6 netmask 255.255.255.0 br0
```

### TAPクライアントのNATテーブルを編集

クライアント側のネットワークの機器がパケットを返送できるようにIPマスカレードを設定する。

```
iptables -t nat -A POSTROUTING -s 10.10.21.0/24 -o eth0 -j MASQUERADE
```