UbuntuでOpenVPNサーバーを構築する方法:実践ガイド

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

保護されていないリモートアクセスの問題

新しいプロジェクトでインフラを構築するたびに、必ず同じ疑問にぶつかる。開発者が内部サービスにセキュアにアクセスできるようにしながら、インターネットに公開しないためにはどうすればいいのか。SSHは個々のサーバーには十分対応できる。しかし、プライベートなデータベース、内部ダッシュボード、ステージング環境が必要になった瞬間、単発のポートフォワーディングではなく、本物のネットワークトンネルを作るものが必要になる。

OpenVPNはいつも私が立ち返るツールだ。2001年から存在し、ほぼあらゆる環境で動作し、急ごしらえの代替手段が壊れるような状況でも耐えてくれる。適切にセットアップすれば、リモートネットワークへの接続はローカルに繋がっているのと変わらない感覚になる。このガイドでは、素のUbuntu 22.04サーバーから、クライアント設定ファイルを渡せる状態の動作するVPNまで、そのセットアップをそのまま解説する。

ターミナルに触れる前に理解しておくべきコアコンセプト

事前に理解しておく価値のあることがいくつかある。このセクションをスキップすると、後のデバッグに倍の時間がかかるだろう。

PKI:なぜ証明書が重要なのか

OpenVPNは公開鍵基盤(PKI)を使って、サーバーと各クライアントの両方を認証する。接続するすべてのデバイスは、ユーザー名とパスワードだけでなく、独自の証明書が必要だ。これを管理するためのツールチェーンはEasy-RSAと呼ばれ、OpenVPNと一緒に配布されている。

PKIの主要な構成要素:

  • CA(認証局) — 信頼のルート。他のすべてに署名する。
  • サーバー証明書 — クライアントに対して、接続先が本物のサーバーであり、なりすましではないことを証明する。
  • クライアント証明書 — 接続しているデバイスが実際に承認されていることをサーバーに証明する。
  • Diffie-Hellmanパラメータ — ハンドシェイク中の鍵交換に使用される。
  • TLS認証キー(ta.key) — 署名されていないパケットをOpenVPNの処理スタックに到達する前に破棄する、追加のHMACレイヤー。

ルーティングとブリッジング

2つのモードがある:ルーティング(TUN)とブリッジング(TAP)だ。リモートアクセス、チームVPN、セルフホスト型インフラには、TUNが適している。仮想ネットワークインターフェースを作成し、レイヤー3でトラフィックをルーティングする。TAPはレイヤー2でブリッジするが、ほとんど必要なく、管理が複雑で、このガイドでは取り上げない。

このガイドはポート1194 UDPのTUNモードを使用する — OpenVPNの標準だ。

実践:OpenVPNサーバーのセットアップ

1. OpenVPNとEasy-RSAのインストール

クリーンなUbuntu 22.04サーバーから始める。アップデートしてから、両方のパッケージをインストールする:

sudo apt update && sudo apt upgrade -y
sudo apt install openvpn easy-rsa -y

2. PKIインフラの構築

Easy-RSAディレクトリをセットアップしてPKIを初期化する:

make-cadir ~/openvpn-ca
cd ~/openvpn-ca
./easyrsa init-pki

認証局を構築する。CA名を入力するよう求められる — 組織名のような短いものでよい:

./easyrsa build-ca nopass

サーバー証明書と鍵を生成する。nopassフラグはサーバー鍵のパスフレーズをスキップし、OpenVPNが起動時に自動的に開始できるようにする:

./easyrsa gen-req server nopass
./easyrsa sign-req server server

確認を求められたらyesと入力する。次にDiffie-Hellmanパラメータを生成する — このステップはハードウェアによって30秒から数分かかる:

./easyrsa gen-dh

最後に、TLS認証キーを生成する:

openvpn --genkey secret ta.key

3. 証明書をOpenVPNディレクトリにコピーする

sudo cp pki/ca.crt pki/issued/server.crt pki/private/server.key pki/dh.pem ta.key /etc/openvpn/server/

4. OpenVPNサーバーの設定

OpenVPNにはサンプル設定が同梱されている。サーバーテンプレートを出発点としてコピーする:

sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf /etc/openvpn/server/server.conf

編集のために開く:

sudo nano /etc/openvpn/server/server.conf

調整が必要な主要な設定:

# 証明書ファイルへのパスを指定
ca ca.crt
cert server.crt
key server.key
dh dh.pem

# TLS認証を有効化
tls-auth ta.key 0

# AES-256-CBCはすべてのクライアントで動作する。OpenVPN 2.5+では以下も使用可能:
# data-ciphers AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305
cipher AES-256-CBC

# DNSとデフォルトルートをクライアントにプッシュ
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"

# キープアライブ:10秒ごとにping、120秒応答なしで再起動
keepalive 10 120

# 起動後にroot権限を放棄
user nobody
group nogroup

redirect-gatewayディレクティブについての注意:これはすべてのクライアントトラフィックをVPN経由でルーティングする。セキュリティ上は通常これが望ましいが、クライアントが内部リソースのみにアクセスする必要がある場合は、その行を削除して代わりに特定のルートをプッシュする。

5. IPフォワーディングの有効化

これがないと、VPNクライアントは行き詰まる — VPNサーバーには到達できるが、その先には何もアクセスできない。初回セットアップで最初に忘れたことだ。同じ失敗を繰り返さないように:

echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

6. ファイアウォールとNATの設定

プライマリネットワークインターフェースを確認する:

ip route | grep default

VPNトラフィックがインターネットに到達できるようNATマスカレードを設定する(eth0は実際のインターフェース名に置き換える):

sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
sudo apt install iptables-persistent -y
sudo netfilter-persistent save

次にOpenVPNポートを開放し、SSHがアクセス可能なままになるようにする:

sudo ufw allow 1194/udp
sudo ufw allow OpenSSH
sudo ufw enable

7. サービスの起動と有効化

sudo systemctl start openvpn-server@server
sudo systemctl enable openvpn-server@server
sudo systemctl status openvpn-server@server

ステータス出力でactive (running)を確認する。tun0インターフェースも表示されるはずだ:

ip addr show tun0

8. クライアント証明書の生成

接続するデバイスにはそれぞれ独自の証明書が必要だ。わかりやすい名前を使うこと — 失効させる時に感謝するだろう:

cd ~/openvpn-ca
./easyrsa gen-req alice-laptop nopass
./easyrsa sign-req client alice-laptop

9. クライアント設定ファイルの作成

最もきれいなアプローチはインライン設定だ — すべてを1つの.ovpnファイルにまとめる。エンドユーザーが証明書を個別に管理する必要がない:

client
dev tun
proto udp
remote YOUR_SERVER_IP 1194
resolv-retry infinite
nobind
persist-key
persist-tun
cipher AES-256-CBC
verb 3
key-direction 1

<ca>
# ca.crtの内容を貼り付け
</ca>
<cert>
# alice-laptop.crtの内容を貼り付け
</cert>
<key>
# alice-laptop.keyの内容を貼り付け
</key>
<tls-auth>
# ta.keyの内容を貼り付け
</tls-auth>

1回手動でやるのは問題ない。複数のクライアントには、各証明書ファイルを読み込んで自動的にインライン化する短いbashスクリプトを書くといい。誰かに単一の.ovpnファイルを渡すだけで、1分以内に接続できる — 説明書不要だ。

苦労して学んだいくつかのこと

  • デバイスが紛失したり従業員が退職したりした場合は、証明書を失効させること。Easy-RSAがこれに対応している:./easyrsa revoke alice-laptopの後に./easyrsa gen-crlを実行する。サーバー設定にcrl-verify crl.pemを追加して、失効した証明書が実際に拒否されるようにする — その行がないと、CRLファイルは無視される。
  • 証明書名を再利用しないこと。一度署名された名前を再利用すると、解決が面倒な証明書の競合が発生する。最初からalice-laptopbob-phoneのような名前を使うこと。
  • VPNには、ほぼ常にUDPがTCPより優れている。TCP上のOpenVPNはTCP-over-TCP状況を生み出す — 外側のTCPレイヤーが再送信すると、内側のTCPスタックも再送信し、パケットロスを処理するのではなく悪化させる。UDPはこれを完全に回避する。UDP 1194をブロックするファイアウォールの背後にいる場合のみ、TCPにフォールバックする。
  • GUIクライアントにインポートする前に、ターミナルでテストすること。openvpn --config alice-laptop.ovpnを直接実行する。ターミナルは正確なエラーメッセージを表示する。GUIクライアントはそれらをサイレントに飲み込み、原因の推測を迫られる。

まとめ

適切に設定されたOpenVPNサーバーは、状況が不安定になっても切れない、本当に頼れる安定した暗号化トンネルを提供してくれる。PKIのセットアップは最初は難しそうに見える。しかし、剥ぎ取ってみれば、CAが両側の証明書に署名しているだけだ。そのメンタルモデルが理解できれば、残りはコマンドを実行するだけだ。

検討する価値のある次のステップ:bashスクリプトでクライアント設定の生成を自動化する、管理インターフェースを有効にしてアクティブな接続をリアルタイムで監視する、LDAPと連携してチーム全体の一元認証を実現する。ほとんどのセットアップ — 特にSSHトンネルの寄せ集めを置き換えるものには — ここで構築したものが出荷できるほどの堅牢性を既に持っている。

Share: