前提条件
※tun(ルーティング)方式で設定する
※自宅用なのでセキュリティリスク(CAの秘密鍵へのアクセス)を承知した上でOpenVPNサーバーとCAを同じマシンにインストールする
・ Ubuntu: 22.04.1 ・ openvpn: 2.5.5 ・ easy-rsa: 3.0.8 ・ openssl: 3.0.2
サーバー設定手順
openvpnとeasy-rsaをインストールする。
# apt install openvpn easy-rsa
ルート証明書の有効期間(日数)を変更したい場合、事前に下記を参考に環境変数を変更する。
# export EASYRSA_CA_EXPIRE=7300
公開鍵基盤(PKI)を初期化して認証局(CA)を設置する。CA作成時に秘密鍵のパスフレーズを聞いてくる。このパスフレーズは新しい証明書発行時に必要になる。
# cd /usr/share/easy-rsa/ # ./easyrsa init-pki # ./easyrsa build-ca
認証局(CA)が発行する証明書の有効期間(日数)を変更したい場合、事前に下記を参考に環境変数を変更する。
# export EASYRSA_CERT_EXPIRE=3650
VPNサーバー用の証明書を作成する。
※パスフレーズは不要なのでnopassを指定
# ./easyrsa build-server-full vpn.example.com nopass
Diffie-Hellmanパラメーターファイルを作成する。
# ./easyrsa gen-dh
TLS-AuthのHMACに使用する共通鍵を作成する。
# openvpn --genkey secret /etc/openvpn/server/ta.key
OpenVPNサーバーの設定ファイルをサンプルからコピーする。
# cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf /etc/openvpn/
設定ファイルを下記のように変更する。
※重要そうな箇所のみ記載
※serverにはクライアントに割り当てられるipアドレスを定義
※push(route)にはクライアントにアクセスを許可するサーバーのプライベートネットワークを指定
※push(redirect-gateway)でクライアントのIPトラフィックがVPNを通過するよう設定
※push(dhcp-option DNS)でクライアントが使用するDNSサーバーを指定
※client-to-clientでクライアント同士の通信を許可
※duplicate-cnで同じ証明書を使用した複数のクライアント接続を許可(非推奨)
port 7716 proto udp dev tun ca /usr/share/easy-rsa/pki/ca.crt cert /usr/share/easy-rsa/pki/issued/vpn.example.com.crt key /usr/share/easy-rsa/pki/private/vpn.example.com.key dh /usr/share/easy-rsa/pki/dh.pem server 172.16.1.0 255.255.255.0 push "route 192.168.1.0 255.255.255.0" push "redirect-gateway def1 bypass-dhcp" push "dhcp-option DNS 192.168.1.11" push "dhcp-option DNS 8.8.8.8" client-to-client duplicate-cn tls-auth server/ta.key 0
IPフォワードを有効にして、異なるネットワーク(NIC)間でパケットが転送されるように設定変更する。
# sed -i "s/#net.ipv4.ip_forward/net.ipv4.ip_forward/g" /etc/sysctl.conf # sysctl -p
iptablesでIPマスカレードを有効に設定する。
# apt install iptables-persistent # iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -o [デバイス名] -j MASQUERADE # netfilter-persistent save
サービスを有効化して起動する。
# systemctl enable --now openvpn@server
クライアント証明書の発行
クライアントに配る*.ovpnを作成するのが面倒なのでスクリプトを作成した。地味にハマったポイントはTLS-Authの「key-direction 1」サーバーの設定が0なら1にする必要がある。
#!/bin/bash easyrsa_location=/usr/share/easy-rsa sample_config_location=/usr/share/doc/openvpn/examples/sample-config-files takey_location=/etc/openvpn/server/ta.key server=vpn.example.com port=7716 echo "作成するユーザーIDを入力してください。" read -p "ユーザーID:" id if [ -z "$id" ]; then exit 0 fi fullname=$id.$server echo echo "クライアント接続設定ファイル「$id.ovpn」を作成します。" read -p "Enterキーで続行します。" result if [ ! -z "$result" ]; then exit 0 fi echo default_location=$(pwd) cd $easyrsa_location ./easyrsa build-client-full $fullname nopass if [ ! $? -eq 0 ]; then exit 0; fi cd $default_location cp $sample_config_location/client.conf $id.ovpn sed -i "s/my-server-1 1194/$server $port/g" $id.ovpn sed -i "s/ca ca.crt/#ca ca.crt/g" $id.ovpn sed -i "s/cert client.crt/#cert client.crt/g" $id.ovpn sed -i "s/key client.key/#key client.key/g" $id.ovpn sed -i "s/tls-auth ta.key 1/#tls-auth ta.key 1\nkey-direction 1/g" $id.ovpn echo "" >>$id.ovpn # CA echo "<ca>" >>$id.ovpn grep -A 100 'BEGIN CERTIFICATE' $easyrsa_location/pki/ca.crt >>$id.ovpn echo "</ca>" >>$id.ovpn echo "" >>$id.ovpn # Key echo "<key>" >>$id.ovpn grep -A 100 'BEGIN PRIVATE KEY' $easyrsa_location/pki/private/$fullname.key >>$id.ovpn echo "</key>" >>$id.ovpn echo "" >>$id.ovpn # Cert echo "<cert>" >>$id.ovpn grep -A 100 'BEGIN CERTIFICATE' $easyrsa_location/pki/issued/$fullname.crt >>$id.ovpn echo "</cert>" >>$id.ovpn echo "" >>$id.ovpn # TLS-auth echo "<tls-auth>" >>$id.ovpn cat $takey_location >>$id.ovpn echo "</tls-auth>" >>$id.ovpn echo "" >>$id.ovpn echo "作成が完了しました。"
実行可能にしてスクリプトを実行すれば対話型でクライアント用の*.ovpnを作成できる。作成された*.ovpnのパーミッションには気をつけが方が良い。
# chmod +x build-client-ovpn.sh # ./build-client-ovpn.sh
クライアント証明書の更新
更新が可能になる期間を変更したい場合、事前に下記を参考に環境変数を変更する。
# export EASYRSA_CERT_RENEW=365
これも面倒なので更新用のスクリプトを作成した。
#!/bin/bash easyrsa_location=/usr/share/easy-rsa sample_config_location=/usr/share/doc/openvpn/examples/sample-config-files takey_location=/etc/openvpn/server/ta.key server=vpn.example.com port=7716 echo "更新するユーザーIDを入力してください。" read -p "ユーザーID:" id if [ -z "$id" ]; then exit 0 fi fullname=$id.$server echo if [ ! -f "$easyrsa_location/pki/issued/$fullname.crt" ]; then echo "既存の証明書が見つかりませんでした。" exit 1 fi echo "クライアント接続設定ファイル「$id.ovpn」を再作成します。" read -p "Enterキーで続行します。" result if [ ! -z "$result" ]; then exit 0 fi echo default_location=$(pwd) cd $easyrsa_location ./easyrsa renew $fullname nopass if [ ! $? -eq 0 ]; then exit 0; fi cd $default_location cp $sample_config_location/client.conf $id.ovpn sed -i "s/my-server-1 1194/$server $port/g" $id.ovpn sed -i "s/ca ca.crt/#ca ca.crt/g" $id.ovpn sed -i "s/cert client.crt/#cert client.crt/g" $id.ovpn sed -i "s/key client.key/#key client.key/g" $id.ovpn sed -i "s/tls-auth ta.key 1/#tls-auth ta.key 1\nkey-direction 1/g" $id.ovpn echo "" >>$id.ovpn # CA echo "<ca>" >>$id.ovpn grep -A 100 'BEGIN CERTIFICATE' $easyrsa_location/pki/ca.crt >>$id.ovpn echo "</ca>" >>$id.ovpn echo "" >>$id.ovpn # Key echo "<key>" >>$id.ovpn grep -A 100 'BEGIN PRIVATE KEY' $easyrsa_location/pki/private/$fullname.key >>$id.ovpn echo "</key>" >>$id.ovpn echo "" >>$id.ovpn # Cert echo "<cert>" >>$id.ovpn grep -A 100 'BEGIN CERTIFICATE' $easyrsa_location/pki/issued/$fullname.crt >>$id.ovpn echo "</cert>" >>$id.ovpn echo "" >>$id.ovpn # TLS-auth echo "<tls-auth>" >>$id.ovpn cat $takey_location >>$id.ovpn echo "</tls-auth>" >>$id.ovpn echo "" >>$id.ovpn echo "作成が完了しました。"
実行可能にすれば対話型で更新ができる。作成された*.ovpnのパーミッションには気をつけが方が良い。
# chmod +x renew-client-ovpn.sh # ./renew-client-ovpn.sh