OpenVPN のサーバを立てる
概要
OpenVPN のサーバを立て、接続できるところまでを説明します。大まかには、
(1) OpenVPN と easy-rsa をインストールし、
(2) 認証局や各種証明書、鍵を作成し、
(3) OpenVPN の設定ファイルを作成・編集し、
(4) クライアントに配るための設定ファイルを作成します。
表記上の注意
本文書では一環して sudo コマンドを用いません。その代わりに、プロンプト文字によってそのコマンド操作が特権を必要とするかを区別します。特権を必要とするコマンド操作である場合にはプロンプト文字を # で表示し、さもなくば $ で表示します。これは、一般的な B シェルのプロンプト表示と一致します。また、ワーキングディレクトリはユーザのホームディレクトリであることを想定しています。
コマンド操作のうち、ユーザ(あなた)が入力すべき部分は Courier Bold の書体で表示されます。出力結果などの部分は Courier の書体で表示されます。また、環境によって入力や出力が異なる部分は Bold Italic や Italic で表示されます。例えば次のようになります。(Scrapbox の仕様上、そのように表示されません。)
code:console
$ echo "hello, world"
hello, world
$ whoami
user
基本システムのインストール
ここでは OpenVPN をインストールするまでの準備を行います。
CentOS 9 Stream をインストールする
CentOS 9 Stream を適当にインストールします。構成は Server を選択します。
パッケージを更新する
インストール済みのパッケージを最新の状態に更新しておきます。この際、しばしばカーネルの更新が入るので再起動も行います。
code:console
# dnf upgrade
# reboot
OpenVPN と easy-rsa のインストール
ここでは OpenVPN と easy-rsa のインストールを行います。
EPEL を有効にする
EPEL は Extra Packages for Enterprise Linux の頭字語です。OpenVPN と easy-rsa は EPEL の一部として提供されるため、初期状態ではインストールできません。試してみると良いでしょう。
code:console
$ dnf search openvpn
No matches found.
$ dnf search easy-rsa
No matches found.
EPEL に含まれるパッケージを利用するためには次のように実行します。
code:console
# dnf install epel-release
OpenVPN と easy-rsa をインストールする
OpenVPN と easy-rsa をインストールします。easy-rsa パッケージには認証局や証明書の発行を簡単に行うためのシェルスクリプトが含まれます。
code:console
# dnf install openvpn easy-rsa
正常にインストールされたのかを確かめるためには次のように実行します。
code:console
$ hash -r # ハッシュテーブルのクリア
$ openvpn --version
$ /usr/share/easy-rsa/3/easyrsa
easy-rsa のスクリプトへのエイリアスをつくる
現状、easy-rsa のスクリプトを利用するためにはスクリプトへのフルパスを指定する必要があります。これではとても手間になるのでエイリアスを作成して実行を楽にします。次のように実行すると、そのシェルが実行されている間は easyrsa コマンドを利用可能になります。
code:console
$ alias easyrsa="/usr/share/easy-rsa/3/easyrsa"
$ easyrsa # 動作確認用
証明書たちの作成
ここでは easy-rsa のスクリプトを利用して各種証明書や鍵を発行します。ここで発行される証明書は所謂 “オレオレ証明書” であることに留意してください(個人利用では問題にならないかもしれません)。
作業用ディレクトリを初期化する
作業用ディレクトリを初期化します。この操作でディレクトリ pki が出現します。
code:console
$ easyrsa init-pki
認証局(CA)をつくる
認証局(CA)をつくります。この際、CA 用のパスフレーズ(New CA Key Passphrase)と PEM 用のパスフレーズ(PEM pass phrase)を求められるのでそれぞれ設定します。さらに、認証局の一般名(Common Name)も求められますが、そのまま Enter キーを押下することでデフォルトの名前(Easy-RSA CA)を利用できます。この操作でファイル ca.crt が所定のディレクトリに出現します。
code:console
$ easyrsa build-ca
サーバ証明書をつくる
サーバ証明書と秘密鍵をつくります。この際、認証局の PEM 用のパスフレーズを求められるので入力します。サーバ名(server)は任意の名前を利用できます(ファイル名なども同様に変化します)。この操作でファイル server.crt とファイル server.key が所定のディレクトリに出現します。
code:console
$ easyrsa build-server-full server nopass
Diffie–Hellman パラメータをつくる
Diffie–Hellman 鍵交換に用いられるパラメータとなる素数をつくります。とても大きな素数を生成しているので少し時間が掛かります。この操作でファイル dh.pem が所定のディレクトリに出現します。
code:console
$ easyrsa gen-dh
TLS-Auth 鍵をつくる
TLS-Auth 鍵をつくります。HMAC 認証の追加レイヤの実現のために必要なようです。この操作でファイル ta.key がディレクトリ pki 配下に出現します。このファイルは使われないかもしれません。
code:console
$ openvpn --genkey secret ./pki/ta.key
ディレクトリ pki の中身
ここで、ディレクトリ pki の中身を確認しておきましょう(一部のファイルやディレクトリを省略しています)。
code:pre
pki/ 3.1. で作成した作業用ディレクトリ
|-- ca.crt 3.2. で作成した認証局証明書
|-- certs_by_serial/...
|-- dh.pem 3.5. で作成した DH パラメータ
|-- index.txt
|-- index.txt.attr
|-- issued/ 証明書のディレクトリ
| |-- client.crt 3.4. で作成したクライアント証明書
| `-- server.crt 3.3. で作成したサーバ証明書
|-- openssl-easyrsa.cnf
|-- private/ 秘密鍵のディレクトリ
| |-- ca.key 3.2. で作成した認証局秘密鍵
| |-- client.key 3.4. で作成したクライアント秘密鍵
| `-- server.key 3.3. で作成したサーバ秘密鍵
|-- renewed/...
|-- reqs/...
|-- revoked/...
|-- safessl-easyrsa.cnf
|-- serial
`-- ta.key 3.6. で作成した TLS-Auth 鍵
証明書たちを配置する
上の作業で作成した各種証明書や鍵を所定のディレクトリ(/etc/openvpn/server 配下)に配置します。
code:console
# cp -R ./pki/* /etc/openvpn/server/.
# ls /etc/openvpn/server/. # 確認用
フォワーディングの設定
OpenVPN の機能の中で IP フォワーディングを利用するので有効にしておきます。この操作でファイル /etc/sysctl.d/01-ipv4_forward.conf が作成されます。
code:console
# echo "net.ipv4.ip_forward = 1" | tee /etc/sysctl.d/01-ipv4_forward.conf
net.ipv4.ip_forward = 1
# sysctl --system # 設定を適用する
$ sysctl -a 2>/dev/null | grep "ip_forward" # 設定確認
net.ipv4.ip_forward = 1
net.ipv4.ip_forward_update_priority = 1
net.ipv4.ip_forward_use_pmtu = 0
設定ファイルの記述
ここでは OpenVPN の設定ファイルを記述します。
設定ファイルのサンプルをコピーする
OpenVPN に同梱されているサンプルをもとに設定ファイルを記述します。まずは設定ファイルのサンプルをコピーしてきます。
code:console
# cp /usr/share/doc/openvpn/sample/sample-config-files/server.conf \
/etc/openvpn/server/.
設定ファイルを編集する
上の操作でコピーしてきた設定ファイル /etc/openvpn/server/server.conf を編集します。編集点の要約は次の通りです。
code:diff
--- a/server.conf 2022-05-24 17:48:18.000000000 +0900
+++ b/server.conf 2022-07-05 15:26:41.213815700 +0900
@@ -29,11 +29,11 @@
# on the same machine, use a different port
# number for each one. You will need to
# open up this port on your firewall.
-port 1194
+port 443
# TCP or UDP server?
-;proto tcp
-proto udp
+proto tcp
+;proto udp
# "dev tun" will create a routed IP tunnel,
# "dev tap" will create an ethernet tunnel.
@@ -76,13 +76,13 @@
# OpenVPN can also use a PKCS #12 formatted key file # (see "pkcs12" directive in man page).
ca ca.crt
-cert server.crt
-key server.key # This file should be kept secret
+cert issued/server.crt
+key private/server.key # This file should be kept secret
# Diffie hellman parameters.
# Generate your own with:
# openssl dhparam -out dh2048.pem 2048
-dh dh2048.pem
+dh dh.pem
# Network topology
# Should be subnet (addressing via IP)
@@ -139,7 +139,7 @@
# address pool (10.8.0.0/255.255.255.0)
# back to the OpenVPN server.
;push "route 192.168.10.0 255.255.255.0"
-;push "route 192.168.20.0 255.255.255.0"
+push "route 192.168.54.0 255.255.255.0"
# To assign specific IP addresses to specific
# clients or if a connecting client has a private
@@ -241,7 +241,7 @@
# a copy of this key.
# The second parameter should be '0'
# on the server and '1' on the clients.
-tls-auth ta.key 0 # This file is secret
+;tls-auth ta.key 0 # This file is secret
# Select a cryptographic cipher.
# This config item must be copied to
@@ -260,7 +260,7 @@
# For compression compatible with older clients use comp-lzo
# If you enable it here, you must also
# enable it in the client config file.
-;comp-lzo
+comp-lzo
# The maximum number of concurrently connected
# clients we want to allow.
@@ -284,7 +284,7 @@
# Output a short status file showing
# current connections, truncated
# and rewritten every minute.
-status openvpn-status.log
+status /var/log/openvpn-status.log
# By default, log messages will go to the syslog (or
# on Windows, if running as a service, they will go to
@@ -294,7 +294,7 @@
# while "log-append" will append to it. Use one
# or the other (but not both).
;log openvpn.log
-;log-append openvpn.log
+log-append /var/log/openvpn.log
# Set the appropriate level of log
# file verbosity.
@@ -312,4 +312,4 @@
# Notify the client that when the server restarts so it
# can automatically reconnect.
-explicit-exit-notify 1
\ No newline at end of file
+;explicit-exit-notify 1
Service ファイルの書き換え
Service ファイルを編集しないと OpenVPN が起動しないようです。これよりも良い解決方法があると信じていますが、現時点では見出せないのでこれで妥協とします。
デフォルトの service ファイルのコピーを取り、その内容を編集します。この操作でファイル /etc/systemd/system/my-openvpn-server@.service を作成し、編集します。
code:console
# cp /usr/lib/systemd/system/openvpn-server@.service \
/etc/systemd/system/my-openvpn-server@.service
# sed -i"" -e"13s/:BF-CBC / /" \
/etc/systemd/system/my-openvpn-server@.service
OpenVPN サーバのサービス起動
OpenVPN のサーバのサービスを起動します。次のように実行します。ここで、server には 3.3. で指定したサーバ名を指定します。きっと起動します。
code:console
# systemctl start my-openvpn-server@server
# systemctl enable my-openvpn-server@server
Firewall の設定
Firewall の設定をします。今回は(とても行儀の悪いことですが)HTTPS の格好をしてポートを開けてもらいます。HTTPS は TCP の 443 番ポートを利用し、firewall はそれを知っています。さらに、SELinux もそれを知っているので好都合であるからです。うーん、行儀が悪過ぎます。ゾーンを切っている場合は適宜対応してください。
code:console
# firewall-cmd --permanent --add-service=https
# firewall-cmd --reload
クライアントに配る設定ファイルの準備
ここでは、クライアントに配るための設定ファイルを準備します。
設定ファイルのサンプルをコピーする
まずは OpenVPN に同梱されているサンプルをもとに設定ファイルを記述します。まずは設定ファイルのサンプルをコピーしてきます。
code:console
$ cp /usr/share/doc/openvpn/sample/sample-config-files/client.conf ./.
設定ファイルを編集する
上の操作でコピーしてきた設定ファイル client.conf を編集します。編集点の要約は次の通りです。
code:diff
--- a/client.conf 2022-05-24 17:48:18.000000000 +0900
+++ b/client.conf 2022-07-05 16:55:43.024815700 +0900
@@ -33,13 +33,13 @@
# Are we connecting to a TCP or
# UDP server? Use the same setting as
# on the server.
-;proto tcp
-proto udp
+proto tcp
+;proto udp
# The hostname/IP and port of the server.
# You can have multiple remote entries
# to load balance between the servers.
-remote my-server-1 1194
+remote 192.168.54.159 443
;remote my-server-2 1194
# Choose a random host from the remote
@@ -85,9 +85,9 @@
# a separate .crt/.key file pair
# for each client. A single ca
# file can be used for all clients.
-ca ca.crt
-cert client.crt
-key client.key
+;ca ca.crt
+;cert client.crt
+;key client.key
# Verify server certificate by checking that the
# certificate has the correct key usage set.
@@ -105,7 +105,7 @@
# If a tls-auth key is used on the server
# then every client must also have the key.
-tls-auth ta.key 1
+;tls-auth ta.key 1
# Select a cryptographic cipher.
# If the cipher option is used on the server
証明書と鍵の連結
上で編集したファイルに各種証明書と鍵を連結します。
code:console
$ echo '<ca>' >>./client.conf
# cat /etc/openvpn/server/ca.crt >>./client.conf
$ echo '</ca>' >>./client.conf
$ echo '<cert>' >>./client.conf
# awk -e '
BEGIN { PEM = 0 }
/^--/ { if (!(PEM = !PEM)) print }
{ if (PEM) print }' /etc/openvpn/server/issued/client.crt \
>./client.conf
$ echo '</cert>' >>./client.conf
$ echo '<key>' >>./client.conf
# cat /etc/openvpn/server/private/client.key >>./client.conf
$ echo '</key>' >>./client.conf
クライアントに転送
上で編集したファイルを client.ovpn と名付けてクライアントに転送します。転送方法は適当にやります。なんとかしてください。
完成
完成しています。完成しているので完成しています。本当です。
全部自動でやってくれるシェルスクリプトがどこかで配布されるかもしれません。期待しないでお待ちください。
この文書はもともと 2022-12-01 に書かれたものであるようです。