OpenVPNサーバーの構築
Debian 11 でOpenVPNサーバーを構築する
今回はQNAPのContainer StationにあるDebian 11 (LXD)にOpenVPNサーバーを構築した。
コンテナではなく通常のDebianを使っている人は、コンテナの初期設定を無視して構いません(入っていないものは入れてください)。以下全てrootで実行した場合のコードになっています。
コンテナの初期設定(入っていなものがあればインストール)
# コンテナ作成時、ネットワークはbridgeにする。 # 端末で「/bin/sh」でターミナルを開く $ passwd #rootのパスワードを設定 $ ip a #IPアドレスが振られている対象インタフェースを確認する(当方はeth0) $ vi /etc/network/interfaces #IPアドレスを固定する。以下は例である。
auto lo iface lo inet loopback iface eth0 inet static address 192.168.0.2 netmask 255.255.255.0 gateway 192.168.0.1 dns-nameserver 8.8.8.8
変更したら「:wq
」で保存して閉じる。
$ vi /etc/sysctl.conf
設定ファイルを開き、最終行に以下を追記し、IPv6を禁止する。
net.ipv6.conf.all.disable_ipv6 = 1
追記したら「:wq
」で保存して閉じる。
$ reboot #再起動する $ ip a #IPアドレスが固定されていることを確認する $ timedatectl set-timezone Asia/Tokyo #タイムゾーンを東京に変更 $ date #現在時刻が正しいか確認する $ apt update #パッケージ一覧を更新 $ apt -y install openssh-server #sshサーバーをインストール $ adduser user1 #user1にssh用のユーザー名を入れる #パスワードを聞かれたらuser1のパスワードを入力 $ gpasswd -a user1 sudo #user1にsudo権限を付与する $ systemctl restart sshd #sshdを再起動
これ以降、QTSのコンソール画面だけでなく、sshから入れる。
$ ssh user1@192.168.***.*** #IPアドレスは先ほど確認したもの $ sudo su #user1のパスワードを入力し、rootとなる。 # sudo: unable to resolve host **** : Name or service not known # が表示される場合は、 $ sh -c 'echo 127.0.1.1 $(hostname) >> /etc/hosts' #でhostsにホスト名を追加する $ apt -y install cron #cronをインストール $ crontab -e #cronファイルを開く
cronファイルを開き、最終行に以下を追記する。
@reboot mkdir -p /dev/net && mknod /dev/net/tun c 10 200 && chmod 600 /dev/net/tun
追記したら「:wq
」で保存して閉じる。
$ apt -y install gpg wget #gpgとwgetをインストール
OpenVPNのインストール
$ wget -O - https://swupdate.openvpn.net/repos/repo-public.gpg | apt-key add - #公開GPGキーをインポート $ echo "deb http://build.openvpn.net/debian/openvpn/release/2.6 bullseye main"> /etc/apt/sources.list.d/openvpn-aptrepo.list #レポジトリを追加(最新版を入れるため)
2.6
は自分のインストールしたいバージョンを入力、bullseye
は自分のOSを入力する(実際に存在するかは上記URLにアクセスして確認可能)。
$ apt update && apt install -y openvpn #OpenVPNをインストール $ openvpn --version #正しいバージョンかを確認 $ apt -y install easy-rsa iptables-persistent #認証ファイル生成をするEasy RSAと、iptablesの設定を恒久化するためにiptables-persistentをインストール
OpenVPNの認証鍵の作成
CAの構築
$ cp -r /usr/share/easy-rsa /etc/openvpn/ #Easy RSAのディレクトリをコピー $ cd /etc/openvpn/easy-rsa/ #ディレクトリ移動 $ cp vars.example vars #varsのサンプルをコピー $ vim vars #95~100行目あたりのコメントアウトを外して、自分の環境に合わせて編集する。
95~100行目あたりのコメントアウトを外して、自分の環境に合わせて編集する。
set_var EASYRSA_REQ_COUNTRY "JP" set_var EASYRSA_REQ_PROVINCE "Kanagawa" set_var EASYRSA_REQ_CITY "Yokohama" set_var EASYRSA_REQ_ORG "QNAP" set_var EASYRSA_REQ_EMAIL "admin@example.com" set_var EASYRSA_REQ_OU "OpenVPN" set_var EASYRSA_CA_EXPIRE 3650 #CA証明書の有効期限(10年) set_var EASYRSA_CERT_EXPIRE 825 #クライアント証明書の有効期限(825日) set_var EASYRSA_CERT_RENEW 30 #有効期限よりクライアント証明書の更新が可能な日数(30日)
「:wq
」で保存して閉じる。
$ ./easyrsa init-pki #PIKを作成 $ ./easyrsa build-ca #認証局を作成 Enter New CA Key Passphrase: #パスフレーズを入力 #このパスフレーズは後ほど使うので忘れないようにする。 Re-Enter New CA Key Passphrase: #もう一度パスフレーズを入力 Common Name [Easy-RSA CA]: #適当な名前を入れる。例「OpenVPN」 $ cp pki/ca.crt /etc/openvpn/ #生成されたCAの証明書ファイルを移動
サーバー秘密鍵・証明書の生成
$ ./easyrsa build-server-full server nopass #サーバーの秘密鍵と証明書ファイルを生成 #途中でパスフレーズを聞かれるので、先ほどのパスフレーズを入力 #サーバーの秘密鍵にパスワードを付けるとサービス起動時に面倒くさいので、nopassオプションにより秘密鍵はパスワード無しで生成する $ cp pki/private/server.key /etc/openvpn/ #秘密鍵をコピー $ cp pki/issued/server.crt /etc/openvpn/ #証明書ファイルをコピー
DHパラメータの生成
$ ./easyrsa gen-dh #DHパラメータを生成 $ cp pki/dh.pem /etc/openvpn/ #DHパラメータをコピー
TLS認証鍵の生成
$ openvpn --genkey secret ta.key #TLS認証鍵を生成 $ cp ta.key /etc/openvpn/ #TLS認証鍵をコピー
クライアント秘密鍵・証明書の生成
$ ./easyrsa build-client-full client01 nopass #クライアントの秘密鍵・証明書を生成 #パスフレーズを聞かれるので先ほど同様に入力 #「client01」はクライアントとなるユーザー名に置き換えること。 $ cp pki/private/client01.key /etc/openvpn/client/ #クライアント秘密鍵をコピー $ cp pki/issued/client01.crt /etc/openvpn/client/ #クライアント証明書をコピー
CA証明書とクライアント証書の有効期限の確認
$ openssl x509 -text -noout -in pki/ca.crt #Validityに記載されている日付が有効期限 $ view pki/index.txt #2列目に記載されているのが各ユーザごとの有効期限
クライアント証書の有効期限が切れそうな場合、以下の手順で有効期限の更新
$ ./easyrsa renew client01 nopass #client01.key、client01.crtが更新されるので、「クライアント秘密鍵・証明書の生成」の手順でコピーする。
OpenVPNサーバーの設定
$ cd /etc/openvpn #ディレクトリ移動 $ cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf ./ #server.confのサンプルコードをコピー $ cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ./client/client01.conf #client.confのサンプルコードをコピー $ vim server.conf #サーバーの設定ファイルを編集
サーバーの設定ファイルを各自の環境に合わせて変更する。当方の変更箇所のみ以下に記述する。
dh dh.pem #ファイル名の修正
push "redirect-gateway def1 bypass-dhcp" #コメントアウト(;)を外す
push "dhcp-option DNS 8.8.8.8" #DNSの通知 push "dhcp-option DNS 8.8.4.4"
duplicate-cn #同じユーザーの複数接続を許可
max-clients 10 #最大接続数:10
user nobody #ユーザー属性の制約なし group nogroup #グループ属性の制約なし
status /var/log/openvpn/openvpn-status.log #ログの記録
log /var/log/openvpn/openvpn.log #ログの記録 log-append /var/log/openvpn/openvpn.log
explicit-exit-notify 1 #UDPの場合 #TCPの場合はコメントアウト(;)すること。
reneg-sec 43200 #末尾に追記し、再認証するまでの時間を指定 #当方は43200秒(12時間)とした。長すぎるとセキュリティ上好ましくないが、短すぎるとその都度接続が切れて認証が必要となるので、1回の使用時間を目安に設定する。
OpenVPNサーバーの起動
$ service openvpn@server start #VPNサーバーを起動 $ service openvpn@server status #VPNサーバーのステータスを確認 #activeになっていれば成功 $ journalctl -xe #VPNのエラーが出ていないことを確認 $ ip a #インターフェイスに「tun0」が追加されていることを確認
※QNAPで起動すると4行目で以下のメッセージが出力されることがある。
$ journalctl -xe systemd[1]: openvpn@server.service: Main process exited, code=killed, status=9/KILL
これはQTSがOpenVPNを見つけると強制終了させることが原因と思われる。以下の手順で強制終了させないようにする。
- GUIのQTSにadminでログインする。
- App CenterよりQVPNをインストールする。
- QVPNを開いてOpenVPNを選択する。
- 「OpenVPN Serverを有効にする」にチェックを入れ、ポートに使用していない適当な数値を入力し「適用」を押下する。(外向きに空いているポートを指定するとセキュリティホールとなるので、空いていないポートを指定すること)
- これにより、QTSでOpenVPNが動いているため、独自にOpenVPNを動かしてもkillされなくなる。
その他設定
パケット転送の有効化
$ vim /etc/sysctl.conf #設定ファイルを編集
net.ipv4.ip_forward=1 #コメントアウトを外して保存
$ sysctl -p #設定を反映
IPマスカレードの設定
$ iptables-legacy -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE #IPマスカレードの設定をする #eth0は「ip a」でVPNサーバーのIPアドレスが割り振られていたインタフェース名を入力すること $ iptables-legacy-save > /etc/iptables/rules.v4 #設定を恒久的に保存 $ update-alternatives --config iptables #デフォルトを変更 #「iptables-legacy」の番号を入力
ここまで出来たら再起動し、設定が保持されている確認する。
$ reboot #再起動 $ iptables -L -t nat #再行動後も設定が残っているか確認 $ service openvpn@server status #OpenVPNが正常に作動しているか確認
クライアント用ファイルの設定
$ cd /etc/openvpn #ディレクトリ移動 $ vim client/client01.conf #クライアントの設定ファイルを編集
クライアントの設定ファイルを各自の環境に合わせて変更する。当方の変更箇所のみ以下に記述する。
remote my-server 1194 #my-serverをVPNサーバのIPアドレスにする #外から入る場合はグローバルIPアドレスを設定する。 #その場合、ルータのポートフォワーディング(方法は各自で確認)で1194を開放し、VPNサーバのIPアドレスに転送する。(固定のグローバルIPアドレスがない場合はDDNSを設定する)
user nobody #ユーザー属性の制約なし group nogroup #グループ属性の制約なし
reneg-sec 0 #末尾に追記し、再認証するまでの時間を無効(0)にする。 #サーバーとクライアントで設定できるが、短い方の時間で再認証されるため、今回はクライアントでの指定を無効としサーバーの時間で再認証する。特定のクライアントにサーバーより短い時間を設定したい場合は0を消して秒数を指定する。
「:wq
」で保存して閉じる。
$ cp client/client01.conf client/client01.ovpn #ovpnファイルを作成 $ vim client/client01.ovpn #ovpnファイルを編集
ovpnファイルの88〜90行目にある以下の3行を削除する。
ca ca.crt cert client.crt key client.key
削除した箇所に以下を挿入する。「
」など並行で開きながらコピペすると作業しやすい。:vnew ca.crt
<ca> -----BEGIN CERTIFICATE----- #・・・ ca.crt の CERTIFICATE の中身 ・・・ -----END CERTIFICATE----- </ca> <cert> -----BEGIN CERTIFICATE----- #・・・ client/client.crt の CERTIFICATE の中身 ・・・ -----END CERTIFICATE----- </cert> <key> -----BEGIN PRIVATE KEY----- #・・・ client/client.key の PRIVATE KEY の中身 ・・・ -----END PRIVATE KEY----- </key>
ovpnファイルの108行目(上記追記後の181行目あたり)にある以下の行を削除する。
tls-auth ta.key 1
削除した箇所に以下を挿入する。
key-direction 1 <tls-auth> # # 2048 bit OpenVPN static key # -----BEGIN OpenVPN Static key V1----- #・・・ ta.key の OpenVPN Static key V1 の中身 ・・・ -----END OpenVPN Static key V1----- </tls-auth>
「:wq
」で保存して閉じる。
クライアント(GUI)から接続する
$ scp /etc/openvpn/client/client01.ovpn user@192.168.***.***:Downloads/
SCPコマンドなどで先ほど作成したovpnファイルをクライアントPCに転送する。userは受け取るPCのユーザー名、192.168.***.***は受け取るPCのIPアドレスを指定する。Downlodsは例なので、好きなフォルダを指定する。
- OpenVPN公式サイトから「OpenVPN Connect」を自分の使用環境(OS)に合わせてダウンロードする。
- ダウンロードしたものをインストールする。
- 先ほど転送した「client.ovpn」をOpenVPN Connectのアプリにドラッグ&ドロップ、またはダブルクリックしてアプリに読み込ませる。
- addを押下するとプロファイルが追加される。
- ボタンを押下して接続できるか確認する。
PAM認証によるID/パスワード認証の設定
ここまでは鍵認証方式によるOpenVPN接続について設定したが、セキュリティを強化するためにID/パスワード認証を追加で導入する。
ファイルのディレクトリを確認
$ find / | grep openvpn-plugin-auth-pam #openvpn-plugin-auth-pam のディレクトリを確認 #当方は「/usr/lib/x86_64-linux-gnu/openvpn/plugins/openvpn-plugin-auth-pam.so」であった。 $ ls /etc/pam.d/login #loginが存在するか確認
VPNサーバーの設定
$ vim /etc/openvpn/server.conf #サーバの設定ファイルを編集 #末尾に以下を追記し保存する。
plugin /usr/lib/x86_64-linux-gnu/openvpn/plugins/openvpn-plugin-auth-pam.so login #ディレクトリは先ほど確認した場所を指定する。
$ service openvpn@server restart #VPNサーバーを再起動
クライアントファイルの修正
$ vim /etc/openvpn/client/client01.ovpn #クライアントファイルを編集 #末尾に以下を追記し保存する。
auth-user-pass #これにより、ID/パスワードを入力できようになる。
- 「client01.ovpn」をクライアントPCに移動させる。
- ファイルをインポートし、IDとパスワードを入力する。
- 「send」ボタンを押下して接続できるか確認する。rootではログインできないため、管理権限のないユーザーで認証すること。
Google Authenticatorを用いた認証
セキュリティをさらに強化するために、鍵認証方式+パスワード認証方式+OTPの3つを合わせた強固な認証を行う。そのためにGoogle Authenticatorを用いた認証を導入する。
Google認証システムの導入
$ apt install -y libpam-google-authenticator #Google Auth PAMモジュールをインストール $ addgroup gauth #gauthグループを作成 $ useradd -g gauth gauth #gauthグループに属するgauthというユーザーを作成 $ mkdir /etc/openvpn/google-authenticator #Google Auth用のディレクトリを作成 $ chown gauth:gauth /etc/openvpn/google-authenticator #gauthにディレクトリの所有者を変更 $ chmod 0700 /etc/openvpn/google-authenticator #gauthにのみ権限を付与
シークレットキーの生成
$ su -c "google-authenticator -t -d -r3 -R30 -f -l \"My VPN\" -s /etc/openvpn/google-authenticator/client01" - gauth #Google Authトークンを作成 #「client01」はVPNでログインするクライアントのユーザー名に変えること。 Your new secret key is:***** #シークレットキーをコピーしておく。 Enter code from app (-1 to skip):-1 Do you want to do so? (y/n):n $ apt install -y qrencode #QRコードを出力するためのツールをインストール $ qrencode -o QR.png otpauth://totp/label?secret=***** #*****に先程のシークレットキーを貼り付ける。 $ scp QR.png user@192.168.***.***:Downloads/ #クライアントPCにQRコードを転送 #IPアドレスとディレクトリは各自指定 $ rm QR.png #QRコードの転送が確認できたら、セキュリティの観点から削除する。
スマートフォンでGoogle認証システムの認証コードを表示
- iPhone(iOS)の場合(iOSが最新にアップデートされていること)
- 「設定」->「パスワード」-> 右上の「+」
- Webサイト:VPNサーバーのIPアドレス(192.168.***.***)
- ユーザ名:VPNサーバーのユーザ名
- パスワード:VPNサーバーのパスワード
- 入力後、「完了」を押下
- 保存したパスワードを開き、「アカウントオプション」->「確認コードを設定…」->「QRコードをスキャン」
- 先ほど生成したQRコードをスキャンさせると、認証コードが表示される。
- キーチェーンをiCloudに同期させると、他のデバイスやMacからでも確認可能
- 「設定」->「パスワード」-> 右上の「+」
- Androidの場合
- Google 認証システム アプリをインストール
- アプリを起動し右下の「+」ボタンを押下して「QRコードをスキャン」
- アップのトップに認証コードが表示される。
PAMの設定
$ vim /etc/pam.d/openvpn #PAMの設定ファイルを編集 #末尾に以下を追記し保存する。
auth required pam_google_authenticator.so authtok_prompt=pin secret=/etc/openvpn/google-authenticator/${USER} user=gauth
VPNサーバーの設定
$ vim /etc/openvpn/server.conf #サーバー設定ファイルを編集 #ID/パスワード認証で最終行に追記した「plugin」の1行を「yy」「p」でコピー&ペーストし、「login」を以下のように変更する。
plugin /usr/lib/x86_64-linux-gnu/openvpn/plugins/openvpn-plugin-auth-pam.so login plugin /usr/lib/x86_64-linux-gnu/openvpn/plugins/openvpn-plugin-auth-pam.so "openvpn login USERNAME password PASSWORD pin OTP"
reneg-sec 43200 #再認証までの時間が問題ないか確認し、保存する。 #短すぎると再認証の度にGoogle Authのコード入力が必要となるので注意すること。
$ service openvpn@server restart #VPNサーバーを再起動
クライアントファイルの設定
$ vim /etc/openvpn/client/client01.ovpn #クライアントファイルを編集 #末尾に以下を追記し保存する。
static-challenge "Enter Google Authenticator Code:" 1
- 保存したら「client.ovpn」をクライアントPC(またはスマホ)に移動させる。
- ファイルをインポートし、IDとパスワードを入力する。
- 接続ボタンを押下すとコードを聞かれるので、認証コード6桁の数字を入力し、接続できるか確認する。
まとめ
以上の設定でOpenVPNサーバーを構築することができる。
鍵認証方式+パスワード認証方式+OTPの3つを合わせた認証により、外向きにポートを空けても安全性を一定程度、確保することができる。