paloma blog

NWエンジニアやってます。主に自宅環境のお遊びを書きます。Pythonもちょっと。タイトルは好きなカクテルから。

自宅用VPNはOPENVPNが最適解か1 サーバ構築編

外出先から家の家計簿サーバにアクセスするのに昨年SSHフォワードのVPN環境を作りました。
非常にお手軽に作れて使い勝手も悪くないのですが、他のサーバにもアクセスしたくなるかもしれません。
ConnectBotでAndroidの簡易VPNを作る - paloma blog

本当はNWエンジニアらしくIPsecを張りたいのですが、自宅で使っているキャリアのレンタルルータがUDPをNATしない仕様の様なのでSSHにしたのですが、 やはり本物のVPN環境がほしいところ。
※レンタルルータの設定手順がなにか間違っていた可能性がありますが、UDPのNATはしないものとして進めています。

いろいろ考えてTCPVPNといったらSSLVPNだよねということでOPENVPNで作ってみることにしました。
昔仕事でFortigateでSSLVPN環境を作ったことはありますが、サーバでは初めて。

というわけで作成記です。
最適解と考えたのは構築の難易度ではなくルータの件など環境面の方でいろいろ融通が効きそうだと思ったからです。
ちなみに拠点間ではなくスマホから自宅環境へのアクセスを想定しています。

参考手順。
www.digitalocean.com

環境

いつものubuntu環境です。

masashi@PC-ubuntu:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.4 LTS
Release:    20.04
Codename:   focal
masashi@PC-ubuntu:~$ openvpn --version | head -3
OpenVPN 2.4.7 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Mar 22 2022
library versions: OpenSSL 1.1.1f  31 Mar 2020, LZO 2.10
Originally developed by James Yonan

CA局での操作

サーバ証明書作成

以前作った自宅CA局があるのでこちらを使って発行します。

easy-rsaで簡単に自宅CA構築+自己証明書発行 - paloma blog

CA証明書は作成済みなのでサーバ証明書を発行します。

サーバ鍵作成
root@HomeCA:~/easy-rsa/csr# openssl genrsa -out vpnserver.key
Generating RSA private key, 2048 bit long modulus (2 primes)
.........................................+++++
.....................................................................+++++
e is 65537 (0x010001)
CSR作成

今の所ドメイン取得は考えていないのでCommon NameはIP直書きにします。
一応個人情報周りマスクします。

root@HomeCA:~/easy-rsa/csr# openssl req -new -key vpnserver.key -out vpnserver.req \
> -subj /C=JP/ST=xxxxx/L=xxxxx\ shi/O=Home\ labo/CN=118.xxx.xxx.xxx

作成完了。
server.xxxのファイルは以前作成したもので関係ありません。

root@HomeCA:~/easy-rsa/csr# ls -l
total 8
-rw------- 1 root root 1675 Jun 26  2021 server.key
-rw-r--r-- 1 root root 1005 Jun 26  2021 server.req
-rw------- 1 root root 1679 Jun  1 10:00 vpnserver.key
-rw-r--r-- 1 root root  997 Jun  1 10:02 vpnserver.req
署名

まずはCSRをインポートします。

root@HomeCA:~/easy-rsa# ./easyrsa import-req csr/vpnserver.req openvpn

Note: using Easy-RSA configuration from: ./vars

Using SSL: openssl OpenSSL 1.1.1f  31 Mar 2020

The request has been successfully imported with a short name of: openvpn
You may now use this name to perform signing operations on this request.

署名。
easy-rsaはopensslの難しいコマンドを覚えなくていいので楽ですね。

root@HomeCA:~/easy-rsa# ./easyrsa sign-req server openvpn

Note: using Easy-RSA configuration from: ./vars

Using SSL: openssl OpenSSL 1.1.1f  31 Mar 2020


You are about to sign the following certificate.
Please check over the details shown below for accuracy. Note that this request
has not been cryptographically verified. Please be sure it came from a trusted
source or that you have verified the request checksum with the sender.

Request subject, to be signed as a server certificate for 365 days:

subject=
    countryName               = JP
    stateOrProvinceName       = xxxxx
    localityName              = xxxxx shi
    organizationName          = Home labo
    commonName                = 118.xxx.xxx.xxx


Type the word 'yes' to continue, or any other input to abort.
  Confirm request details: yes
Using configuration from /root/easy-rsa/pki/safessl-easyrsa.cnf
Check that the request matches the signature
Signature ok
()
Certificate is to be certified until Jun  1 10:06:55 2023 GMT (365 days)

Write out database with 1 new entries
Data Base Updated

Certificate created at: /root/easy-rsa/pki/issued/openvpn.crt

手順上ta.keyをいうのも作成必要なので作ります。
(これは何か後で調べる)

masashi@PC-ubuntu:/tmp$ openvpn --genkey --secret ta.key
masashi@PC-ubuntu:/tmp$ ls -l ta.key 
-rw------- 1 masashi masashi 636  61 20:13 ta.key

これで証明書作成は完了です。

クライアント証明書作成

つづいてクライアント証明書を作ります。
これをスマホに入れることになります。

証明書と鍵ペア作成。

root@HomeCA:~/easy-rsa# ./easyrsa gen-req client1 nopass

Note: using Easy-RSA configuration from: ./vars

Using SSL: openssl OpenSSL 1.1.1f  31 Mar 2020
Generating a RSA private key
...............................................................................................+++++
..................................+++++
writing new private key to '/root/easy-rsa/pki/private/client1.key.hPbmaswwty'
-----
()
-----
Common Name (eg: your user, host, or server name) [client1]:

Keypair and certificate request completed. Your files are:
req: /root/easy-rsa/pki/reqs/client1.req
key: /root/easy-rsa/pki/private/client1.key

CSRインポートしようとしましたが、上記実行時にディレクトリに作成されるようです。

root@HomeCA:~/easy-rsa# ./easyrsa import-req pki/reqs/client1.req client1

Note: using Easy-RSA configuration from: ./vars

Using SSL: openssl OpenSSL 1.1.1f  31 Mar 2020

Easy-RSA error:

Unable to import the request as the destination file already exists.
Please choose a different name for your imported request file.
Existing file at: /root/easy-rsa/pki/reqs/client1.req

署名。

root@HomeCA:~/easy-rsa# ./easyrsa sign-req client client1

()

subject=
    commonName                = client1

()

Write out database with 1 new entries
Data Base Updated

Certificate created at: /root/easy-rsa/pki/issued/client1.crt

ホスト側での操作

OPENVPN構築

パッケージのインストールは割愛します。
作成した証明書をホスト側に移動しました。
ディレクトリの中身はこんな感じです。
client側のファイルはローカルでの確認用に用意しました。

masashi@PC-ubuntu:/etc$ tree openvpn
openvpn
├── client
│   ├── ca.crt
│   ├── client.conf
│   ├── client.conf.org #デフォルトとして退避
│   ├── client1.crt
│   ├── client1.key
│   └── ta.key
├── server
│   ├── ca.crt
│   ├── openvpn.crt
│   ├── openvpn.key
│   ├── server.conf
│   ├── server.conf.org #デフォルトとして退避
│   └── ta.key
└── update-resolv-conf

server.conf、client.confをそれぞれ編集します。
変更内容は以下の通り。
手順のままなので特にチューニングはしていません。

  • server.conf
masashi@PC-ubuntu:/etc/openvpn/server$ diff -u server.conf{.org,} | grep -E '^(\+|\-)'
--- server.conf.org 2022-06-01 19:41:13.562980184 +0900
+++ server.conf 2022-06-01 19:47:07.182377795 +0900
-port 1194
+port 443
-;proto tcp
-proto udp
+proto tcp
+;proto udp
-cert server.crt
-key server.key  # This file should be kept secret
+cert vpnserver.crt
+key vpnserver.key  # This file should be kept secret
-dh dh2048.pem
+;dh dh2048.pem
+dh none
-;push "redirect-gateway def1 bypass-dhcp"
+push "redirect-gateway def1 bypass-dhcp"
-tls-auth ta.key 0 # This file is secret
+;tls-auth ta.key 0 # This file is secret
+tls-crypto ta.key
-cipher AES-256-CBC
+;cipher AES-256-CBC
+cipher AES-256-GCM
+
+auth SHA256
-;user nobody
-;group nogroup
+user nobody
+group nogroup
-explicit-exit-notify 1
+explicit-exit-notify 0
  • client.conf
masashi@PC-ubuntu:/etc/openvpn/client$ diff -u client.conf{.org,} | grep -E '^(\+|\-)'
--- client.conf.org 2022-06-03 19:58:49.312388881 +0900
+++ client.conf 2022-06-04 04:42:36.750973040 +0900
-;proto tcp
-proto udp
+proto tcp
+;proto udp
-remote my-server-1 1194
+remote localhost 443
-;user nobody
-;group nogroup
+user nobody
+group nogroup
-cert client.crt
-key client.key
+cert client1.crt
+key client1.key
-tls-auth ta.key 1
+;tls-auth ta.key 1
-cipher AES-256-CBC
+cipher AES-256-GCM
+auth SHA256
+
+# key direction
+key-direction 1
+

接続テスト

まずはホスト環境のみで接続テストしてみます。
デーモンではなくコマンド経由でサーバ起動してログ等見ます。

masashi@PC-ubuntu:/etc/openvpn/server$ sudo openvpn --config server.conf
Fri Jun  3 19:36:51 2022 OpenVPN 2.4.7 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Mar 22 2022
Fri Jun  3 19:36:51 2022 library versions: OpenSSL 1.1.1f  31 Mar 2020, LZO 2.10
Fri Jun  3 19:36:51 2022 NOTE: your local LAN uses the extremely common subnet address 192.168.0.x or 192.168.1.x.  Be aware that this might create routing conflicts if you connect to the VPN server from public locations such as internet cafes that use the same subnet.
Fri Jun  3 19:36:51 2022 Outgoing Control Channel Encryption: Cipher 'AES-256-CTR' initialized with 256 bit key
Fri Jun  3 19:36:51 2022 Outgoing Control Channel Encryption: Using 256 bit message hash 'SHA256' for HMAC authentication
Fri Jun  3 19:36:51 2022 Incoming Control Channel Encryption: Cipher 'AES-256-CTR' initialized with 256 bit key
Fri Jun  3 19:36:51 2022 Incoming Control Channel Encryption: Using 256 bit message hash 'SHA256' for HMAC authentication
Fri Jun  3 19:36:51 2022 ROUTE_GATEWAY 192.168.0.1/255.255.255.0 IFACE=enp2s0 HWADDR=6c:62:6d:e9:65:56
Fri Jun  3 19:36:51 2022 TUN/TAP device tun0 opened
()
Fri Jun  3 19:36:51 2022 Initialization Sequence Completed

OK。サーバは立ち上がりました。

クライアント側

同じ手順でクライアント側も起動。

masashi@PC-ubuntu:/etc/openvpn/client$ sudo openvpn --config client.conf
Sat Jun  4 04:43:08 2022 OpenVPN 2.4.7 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Mar 22 2022
Sat Jun  4 04:43:08 2022 library versions: OpenSSL 1.1.1f  31 Mar 2020, LZO 2.10
Sat Jun  4 04:43:08 2022 TCP/UDP: Preserving recently used remote address: [AF_INET]127.0.0.1:443
Sat Jun  4 04:43:08 2022 Socket Buffers: R=[131072->131072] S=[16384->16384]
Sat Jun  4 04:43:08 2022 Attempting to establish TCP connection with [AF_INET]127.0.0.1:443 [nonblock]
Sat Jun  4 04:43:08 2022 TCP connection established with [AF_INET]127.0.0.1:443
Sat Jun  4 04:43:08 2022 TCP_CLIENT link local: (not bound)
Sat Jun  4 04:43:08 2022 TCP_CLIENT link remote: [AF_INET]127.0.0.1:443
Sat Jun  4 04:43:08 2022 NOTE: UID/GID downgrade will be delayed because of --client, --pull, or --up-delay
Sat Jun  4 04:43:08 2022 Connection reset, restarting [0]
Sat Jun  4 04:43:08 2022 SIGUSR1[soft,connection-reset] received, process restarting
Sat Jun  4 04:43:08 2022 Restart pause, 5 second(s)

ESTABLISHにはなりましたが、Connection resetになってますね。
サーバ側のログもtls-cryptがエラーになってます。

Jun  4 04:43:08 PC-ubuntu openvpn[630900]: TCP connection established with [AF_INET]127.0.0.1:57156
Jun  4 04:43:08 PC-ubuntu openvpn[630900]: 127.0.0.1:57156 TLS: Initial packet from [AF_INET]127.0.0.1:57156, sid=7873fbc8 512a693e
Jun  4 04:43:08 PC-ubuntu openvpn[630900]: 127.0.0.1:57156 tls-crypt unwrap error: packet too short
Jun  4 04:43:08 PC-ubuntu openvpn[630900]: 127.0.0.1:57156 TLS Error: tls-crypt unwrapping failed from [AF_INET]127.0.0.1:57156
Jun  4 04:43:08 PC-ubuntu openvpn[630900]: 127.0.0.1:57156 Fatal TLS error (check_tls_errors_co), restarting
Jun  4 04:43:08 PC-ubuntu openvpn[630900]: 127.0.0.1:57156 SIGUSR1[soft,tls-error] received, client-instance restarting

調べたらta.keyも呼び出さないとダメだそうです。
[Solved] tls-crypt unwrap error: packet too short - OpenVPN Support Forum

再実施。

masashi@PC-ubuntu:/etc/openvpn/client$ sudo openvpn --config client.conf --tls-crypt ta.key 
Sat Jun  4 04:48:18 2022 OpenVPN 2.4.7 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Mar 22 2022
Sat Jun  4 04:48:18 2022 library versions: OpenSSL 1.1.1f  31 Mar 2020, LZO 2.10
Sat Jun  4 04:48:18 2022 Outgoing Control Channel Encryption: Cipher 'AES-256-CTR' initialized with 256 bit key
Sat Jun  4 04:48:18 2022 Outgoing Control Channel Encryption: Using 256 bit message hash 'SHA256' for HMAC authentication
Sat Jun  4 04:48:18 2022 Incoming Control Channel Encryption: Cipher 'AES-256-CTR' initialized with 256 bit key
Sat Jun  4 04:48:18 2022 Incoming Control Channel Encryption: Using 256 bit message hash 'SHA256' for HMAC authentication
Sat Jun  4 04:48:18 2022 TCP/UDP: Preserving recently used remote address: [AF_INET]127.0.0.1:443
Sat Jun  4 04:48:18 2022 Socket Buffers: R=[131072->131072] S=[16384->16384]
Sat Jun  4 04:48:18 2022 Attempting to establish TCP connection with [AF_INET]127.0.0.1:443 [nonblock]
Sat Jun  4 04:48:18 2022 TCP connection established with [AF_INET]127.0.0.1:443
Sat Jun  4 04:48:18 2022 TCP_CLIENT link local: (not bound)
Sat Jun  4 04:48:18 2022 TCP_CLIENT link remote: [AF_INET]127.0.0.1:443
Sat Jun  4 04:48:18 2022 NOTE: UID/GID downgrade will be delayed because of --client, --pull, or --up-delay
Sat Jun  4 04:48:18 2022 TLS: Initial packet from [AF_INET]127.0.0.1:443, sid=4cadbc4a c3da1e0c
Sat Jun  4 04:48:18 2022 VERIFY OK: depth=1, CN=HomeCA.szkmhome.lab
Sat Jun  4 04:48:18 2022 VERIFY KU OK
()
Sat Jun  4 04:48:19 2022 /sbin/ip link set dev tun1 up mtu 1500
Sat Jun  4 04:48:19 2022 /sbin/ip addr add dev tun1 local 10.8.0.6 peer 10.8.0.5
Sat Jun  4 04:48:19 2022 /sbin/ip route add 127.0.0.1/32 via 192.168.0.1
RTNETLINK answers: File exists
Sat Jun  4 04:48:19 2022 ERROR: Linux route add command failed: external program exited with error status: 2
Sat Jun  4 04:48:19 2022 /sbin/ip route add 0.0.0.0/1 via 10.8.0.5
Sat Jun  4 04:48:19 2022 /sbin/ip route add 128.0.0.0/1 via 10.8.0.5
Sat Jun  4 04:48:19 2022 /sbin/ip route add 10.8.0.1/32 via 10.8.0.5
Sat Jun  4 04:48:19 2022 GID set to nogroup
Sat Jun  4 04:48:19 2022 UID set to nobody
Sat Jun  4 04:48:19 2022 WARNING: this configuration may cache passwords in memory -- use the auth-nocache option to prevent this
Sat Jun  4 04:48:19 2022 Initialization Sequence Completed

ルートもインストールされました。
OKそうですね。

サーバ側もログがずらずらっと出てきましたのでOkでしょう。

Jun  4 04:48:18 PC-ubuntu openvpn[630900]: TCP connection established with [AF_INET]127.0.0.1:57208
Jun  4 04:48:18 PC-ubuntu openvpn[630900]: 127.0.0.1:57208 TLS: Initial packet from [AF_INET]127.0.0.1:57208, sid=916e5c45 e9d1b439
Jun  4 04:48:18 PC-ubuntu openvpn[630900]: 127.0.0.1:57208 VERIFY OK: depth=1, CN=HomeCA.szkmhome.lab
Jun  4 04:48:18 PC-ubuntu openvpn[630900]: 127.0.0.1:57208 VERIFY OK: depth=0, CN=client1
()
Jun  4 04:48:18 PC-ubuntu openvpn[630900]: 127.0.0.1:57208 Control Channel: TLSv1.3, cipher TLSv1.3 TLS_AES_256_GCM_SHA384, 2048 bit RSA
Jun  4 04:48:18 PC-ubuntu openvpn[630900]: 127.0.0.1:57208 [client1] Peer Connection Initiated with [AF_INET]127.0.0.1:57208
Jun  4 04:48:18 PC-ubuntu openvpn[630900]: client1/127.0.0.1:57208 MULTI_sva: pool returned IPv4=10.8.0.6, IPv6=(Not enabled)
Jun  4 04:48:18 PC-ubuntu openvpn[630900]: client1/127.0.0.1:57208 MULTI: Learn: 10.8.0.6 -> client1/127.0.0.1:57208
Jun  4 04:48:18 PC-ubuntu openvpn[630900]: client1/127.0.0.1:57208 MULTI: primary virtual IP for client1/127.0.0.1:57208: 10.8.0.6
Jun  4 04:48:19 PC-ubuntu openvpn[630900]: client1/127.0.0.1:57208 PUSH: Received control message: 'PUSH_REQUEST'
Jun  4 04:48:19 PC-ubuntu openvpn[630900]: client1/127.0.0.1:57208 SENT CONTROL [client1]: 'PUSH_REPLY,redirect-gateway def1 bypass-dhcp,route 10.8.0.1,topology net30,ping 10,ping-restart 120,ifconfig 10.8.0.6 10.8.0.5,peer-id 0,cipher AES-256-GCM' (status=1)
Jun  4 04:48:19 PC-ubuntu openvpn[630900]: client1/127.0.0.1:57208 Outgoing Data Channel: Cipher 'AES-256-GCM' initialized with 256 bit key
Jun  4 04:48:19 PC-ubuntu openvpn[630900]: client1/127.0.0.1:57208 Incoming Data Channel: Cipher 'AES-256-GCM' initialized with 256 bit key
Jun  4 04:48:19 PC-ubuntu NetworkManager[1118]: <info>  [1654285699.6846] manager: (tun1): new Tun device (/org/freedesktop/NetworkManager/Devices/25)
Jun  4 04:48:19 PC-ubuntu charon: 11[KNL] interface tun1 activated
Jun  4 04:48:19 PC-ubuntu systemd-udevd[666021]: ethtool: autonegotiation is unset or enabled, the speed and duplex are not writable.
Jun  4 04:48:19 PC-ubuntu charon: 13[KNL] fe80::9bb5:5d53:5ab6:4925 appeared on tun1
Jun  4 04:48:19 PC-ubuntu charon: 02[KNL] 10.8.0.6 appeared on tun1
()

NW周りのステータス

同一マシン内ですがVPNは張れたようなのでNWのステータスを見てみます。

トンネルインターフェースがちゃんとUpしてます。
デフォルトの10.8.0.0/24のIPも払い出されてますね。

masashi@PC-ubuntu:~$ ip address show dev tun1
25: tun1: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 100
    link/none 
    inet 10.8.0.6 peer 10.8.0.5/32 scope global tun1
       valid_lft forever preferred_lft forever
    inet6 fe80::9bb5:5d53:5ab6:4925/64 scope link stable-privacy 
       valid_lft forever preferred_lft forever

続いてルーティングインストール。
払い出しもデフォルトのままです。
ホスト機のプロキシ経由でLXD環境にアクセスしたいだけなので追加は不要でしょう。

masashi@PC-ubuntu:~$ ip r show dev tun1
0.0.0.0/1 via 10.8.0.5 
10.8.0.1 via 10.8.0.5 
10.8.0.5 proto kernel scope link src 10.8.0.6 
128.0.0.0/1 via 10.8.0.5 

一応pingも打ってみます。
10.8.0.5はGWですが通りませんでした。

masashi@PC-ubuntu:~$ ping -c4 10.8.0.5
PING 10.8.0.5 (10.8.0.5) 56(84) バイトのデータ

--- 10.8.0.5 ping 統計 ---
送信パケット数 4, 受信パケット数 0, パケット損失 100%, 時間 3064ミリ秒

10.8.0.1は何者かわかりませんが、返ってきます。

masashi@PC-ubuntu:~$ ping -c4 10.8.0.1
PING 10.8.0.1 (10.8.0.1) 56(84) バイトのデータ
64 バイト応答 送信元 10.8.0.1: icmp_seq=1 ttl=64 時間=0.057ミリ秒
64 バイト応答 送信元 10.8.0.1: icmp_seq=2 ttl=64 時間=0.059ミリ秒
64 バイト応答 送信元 10.8.0.1: icmp_seq=3 ttl=64 時間=0.059ミリ秒
64 バイト応答 送信元 10.8.0.1: icmp_seq=4 ttl=64 時間=0.058ミリ秒

--- 10.8.0.1 ping 統計 ---
送信パケット数 4, 受信パケット数 4, パケット損失 0%, 時間 3056ミリ秒
rtt 最小/平均/最大/mdev = 0.057/0.058/0.059/0.000ミリ秒

この辺は実際の疎通でNGになったら調べましょう。

サービス起動

これで接続確認できましたのでデーモンで起動しておきます。

masashi@PC-ubuntu:/etc/openvpn/server$ sudo systemctl start openvpn-server@server
masashi@PC-ubuntu:/etc/openvpn/server$ sudo systemctl status openvpn-server@server
● openvpn-server@server.service - OpenVPN service for server
     Loaded: loaded (/lib/systemd/system/openvpn-server@.service; disabled; vendor preset: enabled)
     Active: active (running) since Fri 2022-06-03 19:38:49 JST; 51s ago
       Docs: man:openvpn(8)
             https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage
             https://community.openvpn.net/openvpn/wiki/HOWTO
   Main PID: 630900 (openvpn)

これでOK。

まとめ

OPENVPN環境の構築を行いました。
SSLVPNは証明書が必要ですが、どの手順を見ても証明書の作成から書かれていて長くなりがちです。
私はCA局は作成していたのでサーバ証明書発行のみで済みましたが、このへんは仕様上仕方ないにしても結構面倒ですね。
(面倒なほどの難しいコマンドは打ってませんが…)

とりあえず無事にローカルでの接続確認はできましたので、次回はスマホからのアクセスを試します。