Ubuntu 24.04 Server で OpenVPN のブリッジ接続サーバを導入しネームサーバ・DHCPサーバと同時運用する 3 : クライアントの設定

前の前の記事はこちら → [1 : Easy-RSA による証明書等の準備](https://qiita.com/335mochi/items/ce1cfba3cdf51d5c621c)

https://qiita.com/335mochi/items/ce1cfba3cdf51d5c621c


前の記事はこちら → [2 : サーバの設定](https://qiita.com/335mochi/items/40e931c306ed55c1d3d0)

https://qiita.com/335mochi/items/40e931c306ed55c1d3d0


# 3 : クライアントの設定

以上で、サーバのほうは完成しました。

あとは、クライアントの設定ファイルなど、クライアントの構築です。

クライアントのホストで作業します。


## 3-1 OpenVPNクライアントの設定ファイルを作成

クライアントの基本的な 設定ファイル `client.conf` （`/etc/openvpn/client.conf`）を作ります。

実際には、 `/etc/openvpn/client/` に ファイル `client.conf` を作って保持し、それへのシンボリックリンクを `/etc/openvpn/` に置きました。

```bash
user<clienthost~> % sudo -s
root<clienthost~> % cd /etc/openvpn/client/
root<clienthost/etc/openvpn/client> % cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf .
root<clienthost/etc/openvpn/client> % vim client.conf
```

最終的な設定内容だけを示します。
なお、 `my.domain` は名前解決してグローバルアドレスが得られるようになっているドメイン名です。

``` :/etc/openvpn/client/client.conf
client

dev tap0

proto udp

remote my.domain 1194

resolv-retry infinite

nobind

user nobody
group nogroup

persist-key
persist-tun

ca /etc/openvpn/ca.crt
cert /etc/openvpn/clienthost.crt
key /etc/openvpn/clienthost.key

remote-cert-tls server

tls-auth /etc/openvpn/ta.key 1

verb 3

mssfix 1280

```

ファイルを保存したらシンボリックリンクを作ります。

```bash
root<clienthost/etc/openvpn/client> % cd ..
root<clienthost/etc/openvpn> % ln -s client/client.conf
```


###### `client.conf` の内容に関するメモ

[参考 : `man openvpn`](https://linux.die.net/man/8/openvpn)
[参考 : Deprecated Options in OpenVPN](https://community.openvpn.net/openvpn/wiki/DeprecatedOptions)
[参考 : OpenVPNに接続したときに、接続が不安定になる問題を解消する](https://qiita.com/reoring/items/f6400212d3de19ee5ad7)
[参考 : OpenVPN TIPS - UDP使用時にVPN通信が不安定になる場合](https://yamatamemo.blogspot.com/2012/06/openvpn-tips-udpvpn.html)

| 設定内容 | メモ |
|---|---|
| `client` | `pull` `tls-client` の2つを指定するのと同等とのこと。 |
| `dev tap0` | `dev tap` でも大丈夫ですが、ここでは、 `tap0` と指定しました。 |
| `proto udp` | サーバの設定と合わせます。 |
| `remote my.domain 1194` | 接続先です。 ポート `1194` はサーバの設定と合わせます。 |
| `remote-cert-tls server` | 悪意を持ったクライアントがサーバになりすます攻撃を防ぐためのオプションです。昔は `ns-cert-type server` というオプションだったようですね。それがこれに置き換わったようです。 |
| cipher AES-256-CBC | いまのバージョンの OpenVPN では、サーバとクライアントが相談して利用可能な中から最適なサイファを決めるようになっているそうで、オプションでの指定は必要ないようです。 バージョン 2.3 以前のサーバと通信する場合は互換性のために入れてもよいとの情報がありますが、しないので省きました。 |
| data-ciphers AES-256-GCM:AES-128-GCM:?CHACHA20-POLY1305:AES-256-CBC | 上と同じ。省きました。
| comp lzo | サーバの設定と合わせなければなりません。サーバの設定で入れなかったので、クライアントの設定からも除かなくてはいけません。 |
| `mssfix 1280` | よくわかっていないのですが、送信する UDPパケット の大きさの上限を決める、みたいな意味のようです（でいいですか？）。場合により、ある大きさを超えるパケットが経路途中のルータで破棄されるというケースがあるみたいで、それが起こると通信できなくなったり遅延したりします。いろいろ試す中でそのようなことがあったので、参考サイトの説明に従ってこの値を定めてみました。いちおう、これで順調に動作しています。 |


## 3-2 証明書や鍵のファイルを適切な場所に置く

[1 : Easy-RSA による証明書等の準備](https://qiita.com/335mochi/items/ce1cfba3cdf51d5c621c) で用意した証明書や鍵のファイルのうち OpenVPN のクライアントに必要なものを、コピーしてきて適切な場所（`/etc/openvpn/`）に置きます。

OpenVPN のクライアントが必要とするファイルは以下です。

| 必要なもの | ファイル名 |
|---|---|
| クライアントの証明書 | clienthost.crt |
| クライアントの秘密鍵 | clienthost.key |
| CAの証明書 | ca.crt |
| TLS認証鍵 | ta.key |


#### (1) 適切な場所にコピーする

上の4つのファイルを、サーバのホストにある Easy-RSA のディレクトリからクライアントのホストに送り、 `/etc/openvpn/` に置きます。

実際には、 `clienthost.crt` と `clienthost.key` の2つのファイルは、 `/etc/openvpn/client/` に保持し、それらへのシンボリックリンクを `/etc/openvpn/` に置きました。


#### (2) 秘密鍵からパスフレーズを取り除く

**サーバの秘密鍵** に対してしたのと同じように、 **クライアントの秘密鍵** からパスフレーズを取り除いておきます。

`openssl` コマンドで行います。 `openssl rsa -in 元の秘密鍵ファイル -out パスフレーズの取り除かれた秘密鍵を格納するファイル名` とします。
`Enter pass phrase for clienthost.key.BACKUP:` でそのパスフレーズを入力します。

```bash
root<clienthost/etc/openvpn> % cd client/
root<clienthost/etc/openvpn/client> % mv clienthost.key clienthost.key.BACKUP
root<clienthost/etc/openvpn/client> % openssl rsa -in clienthost.key.BACKUP -out clienthost.key
Enter pass phrase for clienthost.key.BACKUP:
writing RSA key
```

**サーバの秘密鍵** のところで述べたのと同じように、 **クライアントの秘密鍵** についても、このファイルが盗まれたら（パスフレーズがあれば秘密鍵は漏洩しない可能性があったところ、パスフレーズを取り除いてしまったので）一巻の終わり、と考え、ファイルとディレクトリのパーミッションに細心の注意を払っておく必要があります。

このファイルのオーナーは root:root にし、パーミッションは 600 にしました。


## 3-3 systemd で サービス `openvpn` を有効化

クライアントのホストにおいて、 systemd で サービス `openvpn` を有効化します。
（実際には、最初から有効化されているようなので、この作業は必要ないかと思います。）

```bash
root<clienthost/etc/openvpn> % cd
root<clienthost~> % sudo systemctl enable openvpn
Synchronizing state of openvpn.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install enable openvpn
```


## 3-4 OpenVPN の tap接続 に関わる route の設定

Ubuntu の NetworkManager には OpenVPN と連携するモジュールのパッケージがあり、 `openvpn` のパッケージとともにインストールされていますので、ここまでの作業で、システムに tap接続 の設定が認識され、接続できる状態になっています。

しかし、実際に接続テストをしてみると、接続しているものの通信できないという状態になります。
その問題を解決します。


###### tap接続 を起動する前の状態

まず、 tap接続 を起動する前のインタフェースの状態は

```bash
root<clienthost~> % exit
exit
user<clienthost~> % ifconfig
​enp175s0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether 06:e0:4c:6a:02:13  txqueuelen 1000  (イーサネット)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

​lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (ローカルループバック)
        RX packets 183  bytes 15273 (15.2 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 183  bytes 15273 (15.2 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

​wlp174s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.201.13  netmask 255.255.255.0  broadcast 192.168.201.255
        inet6 2001:268:981b:8d89:aace:3896:a11e:e49a  prefixlen 64  scopeid 0x0<global>
        inet6 2001:268:981b:8d89:3eaa:e15b:e724:379  prefixlen 64  scopeid 0x0<global>
        inet6 fe80::d82f:f558:99e1:f584  prefixlen 64  scopeid 0x20<link>
        ether f4:7b:09:99:fb:01  txqueuelen 1000  (イーサネット)
        RX packets 153  bytes 48685 (48.6 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 157  bytes 26905 (26.9 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

```

です。 `enp175s0` は有線インタフェース、 `wlp174s0` は無線インタフェースです。
現在、有線は接続されていなくて無線で接続されており、無線インタフェースが アドレス `192.168.201.13/24` を持っていることがわかります。

route は

```bash
user<clienthost~> % route
カーネルIP経路テーブル
受信先サイト    ゲートウェイ    ネットマスク   フラグ Metric Ref 使用数 インタフェース
default         _gateway        0.0.0.0         UG    600    0        0 wlp174s0
link-local      0.0.0.0         255.255.0.0     U     1000   0        0 wlp174s0
192.168.201.0   0.0.0.0         255.255.255.0   U     600    0        0 wlp174s0
```

となっています。


###### NetworkManager での接続の確認

ここで、NetworkManager が認識している接続のリストを表示させると

```bash
user<clienthost~> % nmcli connection
NAME         UUID                                  TYPE      DEVICE   
wifi1        0d9603b3-9124-4437-b970-0d23815e573e  wifi      wlp174s0 
wifi2        b2c1560d-6305-4f1d-a2f9-488ccc6884bf  wifi      --       
tap0         b9b087c3-d3d6-4b20-a101-bb45a60cdbe1  tun       --       
有線接続 1   1be4e9ec-3c65-31ae-980c-106c59275d19  ethernet  --       
```

と表示されます。
`tap0` がちゃんと含まれていますね。

では、 `tap0` を起動してみます。

```bash
user<clienthost~> % nmcli connection up tap0
接続が正常にアクティベートされました (D-Bus アクティブパス: /org/freedesktop/NetworkManager/ActiveConnection/2)
user<clienthost~> % nmcli connection
NAME              UUID                                  TYPE      DEVICE   
wifi1             0d9603b3-9124-4437-b970-0d23815e573e  wifi      wlp174s0 
tap0              b9b087c3-d3d6-4b20-a101-bb45a60cdbe1  tun       tap0     
wifi2             b2c1560d-6305-4f1d-a2f9-488ccc6884bf  wifi      --       
有線接続 1        1be4e9ec-3c65-31ae-980c-106c59275d19  ethernet  --       
```

うまくいきました。

ところが、この状態で、 VPN でつないだローカルネットワーク内のホストへ `ping` を打っても、返事が返ってきません。
それどころか、 `wifi1` を通した VPN とは無関係な外部への通信もできなくなってしまっています。


###### 通信できない原因

その原因は、 route にあります。
この状態で route を表示させると

```bash
user<clienthost~> % route
カーネルIP経路テーブル
受信先サイト    ゲートウェイ    ネットマスク   フラグ Metric Ref 使用数 インタフェース
default         192.168.0.1     0.0.0.0         UG    450    0        0 tap0
default         _gateway        0.0.0.0         UG    600    0        0 wlp174s0
link-local      0.0.0.0         255.255.0.0     U     1000   0        0 wlp174s0
192.168.0.0     0.0.0.0         255.255.255.0   U     450    0        0 tap0
192.168.201.0   0.0.0.0         255.255.255.0   U     600    0        0 wlp174s0
```

となります。 `_gateway` （`192.168.201.0/24` のゲートウェイ）と `192.168.0.1` （`192.168.0.0/24` のゲートウェイ）の2つが `default` になっています。
これが原因のようです。


###### tap接続 を default route にしないよう NetworkManager に指示

この問題は、 `tap0` を `default` とする設定を取り除けば解決します。
それは

```bash
user<clienthost~> % sudo route del default tap0
```

でできますが、 NetworkManager に覚えてもらうには、次のようにします。

```bash
user<clienthost~> % nmcli connection modify tap0 ipv4.never-default yes
```

このようにすると、再起動後も永続する設定になります。


###### 問題の解決を確認

一旦、 `tap0` を停止して、ふたたび起動します。

```bash
user<clienthost~> % nmcli connection down tap0
接続 'tap0' が正常に非アクティブ化されました (D-Bus アクティブパス: /org/freedesktop/NetworkManager/ActiveConnection/2)
user<clienthost~> % nmcli connection up tap0
接続が正常にアクティベートされました (D-Bus アクティブパス: /org/freedesktop/NetworkManager/ActiveConnection/3)
```

すると、 route は

```bash
user<clienthost~> % route
カーネルIP経路テーブル
受信先サイト    ゲートウェイ    ネットマスク   フラグ Metric Ref 使用数 インタフェース
default         _gateway        0.0.0.0         UG    600    0        0 wlp174s0
link-local      0.0.0.0         255.255.0.0     U     1000   0        0 wlp174s0
192.168.0.0     0.0.0.0         255.255.255.0   U     450    0        0 tap0
192.168.201.0   0.0.0.0         255.255.255.0   U     600    0        0 wlp174s0
```

ちゃんと `default` が1個になりました。

通信も無事にできるようになりました。 VPN で繋いだローカルネットワーク内のすべてのホストと自由に通信することができます。もちろん外部との通信もできます。



###### NetworkManager での tap接続 の設定の内容

NetworkManager での `tap0` の設定を一覧表示させるとこうなります。

```bash
user<clienthost~> % nmcli connection show tap0
connection.metered:                     不明
connection.lldp:                        default
connection.mdns:                        -1 (default)
connection.llmnr:                       -1 (default)
connection.dns-over-tls:                -1 (default)
connection.wait-device-timeout:         -1
ipv4.method:                            auto
ipv4.dns:                               --
ipv4.dns-search:                        --
ipv4.dns-options:                       --
ipv4.dns-priority:                      0
ipv4.addresses:                         --
ipv4.gateway:                           --
ipv4.routes:                            --
ipv4.route-metric:                      -1
ipv4.route-table:                       0 (unspec)
ipv4.routing-rules:                     --
ipv4.ignore-auto-routes:                いいえ
ipv4.ignore-auto-dns:                   いいえ
ipv4.dhcp-client-id:                    --
ipv4.dhcp-iaid:                         --
ipv4.dhcp-timeout:                      0 (default)
ipv4.dhcp-send-hostname:                はい
ipv4.dhcp-hostname:                     --
ipv4.dhcp-fqdn:                         --
ipv4.dhcp-hostname-flags:               0x0 (none)
ipv4.never-default:                     はい
ipv4.may-fail:                          はい
ipv4.required-timeout:                  -1 (default)
ipv4.dad-timeout:                       -1 (default)
ipv4.dhcp-vendor-class-identifier:      --
ipv4.dhcp-reject-servers:               --
ipv6.method:                            link-local
ipv6.dns:                               --
ipv6.dns-search:                        --
ipv6.dns-options:                       --
ipv6.dns-priority:                      0
```


## 3-5 ユーザ操作で OpenVPN tap接続 を起動するスクリプトを用意

システム起動時に OpenVPN の tap接続 を起動するようにするには、 systemd で `openvpn@client` を有効化すればいいです。

```bash
user<clienthost~> % sudo systemctl enable openvpn@client
```

しかし、私の場合は、クライアントはつねにネットワークに接続しているわけではないので、必要に応じてユーザが操作して OpenVPN の tap接続 を起動するようにします。

そのためのスクリプトを用意します。

```bash
user<clienthost~> % cd bin/
user<clienthost~/bin> % vim start_vpn_with_dhcp
```

内容は次のとおりです。

```sh :/home/user/bin/start_vpn_with_dhcp
#!/bin/sh

/usr/bin/nmcli connection up tap0

```

実行パーミッションを付与しておきます。

```bash
user<clienthost~/bin> % chmod a+x start_vpn_with_dhcp
```

ユーザーは、ネットワークに繋がっている状態で、このスクリプトを実行すれば、いつでも、 tap接続 を開始することができます。

---

以上で、すべての準備が完了しました。