OpenVPNでPCのリモート環境の整備
リモート環境というとVPN(Virtual Private Network)という言葉が出てくると思いますが、VPNはセキュア通信の方法であってリモートを実現するものではありません。実際のリモート操作は、SSHやリモートデスクトップ、VNCにより実現します。
とはいえリモート環境を構築する場合は、たいていは利用することになります。一か所設定してしまえば、その名の通りIPv4環境でもルーターの内側のネットワークと直接通信できるようになるからです。
VPNをオープンソースで構築しようと思った際、利用するアプリの選択肢はOpenVPNとSoftEtherとなるのではないでしょうか。筆者はその両方を利用していて、セキュリティを強化した運用をしたい際は証明書認証ができるOpenVPN、ユーザー名とパスワード認証だけでいいなら簡単なSoftEtherという使い方をしています。
ここではOpenVPNをとりあげ、証明書認証(IPv4)の構築方法を覚書といして書いています。その中で特に苦労したのはWindows10のクライアントにおける次の点でした。
- OpenVPNクライアントをユーザー権限で実行
- サーバーからのルーティングのPUSHがクライアントで反映されない
- クライアント証明書をコピーして使いまわされないようにする
これらについて誰かの参考になれば幸いです。
OpenVPNを設定する前に
OpenVPNを設定する前に必要な予備知識を簡単に説明します。まずは今回利用する証明書認証です。
証明書認証ではCA(認証局)というものがでてきます。これは実際の通信にはかかわりませんが、サーバーやクライアントに対して証明書を発行する機関です。機関とありますが実際はPCでそれがOpenVPNサーバーを兼ねていることもあります。このCAの証明書はOpenVPNを使うすべてのPCが持っている必要があります。
OpenVPNサーバーは公開鍵暗号を使って通信をするために、自分の秘密鍵を使って、CAに証明書を発行してもらいます。サーバーでは接続してくクライアントがCAの証明書を持っているか否かで接続可否を決めます。通信の際は、サーバーの秘密鍵、証明書、クライアントの秘密鍵、証明書を使って暗号通信を始めます。秘密鍵をお互い知らせないまま(使用するのは自分だけ)で、通信できるのが公開鍵暗号方式です。
OpenVPNクライアントは、サーバーに接続しに行く端末です。クライアントも自分の秘密鍵を使って、CAに証明書を発行してもらう必要があります。接続時にはクライアントもサーバーがCAの証明書をもっているか確認します。
サーバーもクライアントも、自身の秘密鍵と証明書、CAの証明書を持つことになります。ファイル数は6つになりますが、CAの証明書だけはどちらも同じものを持つので5種類ということになります。
OpenSSLでCAを作成して証明書を作る方法はこちらで記載しています。リンク先ではOpenSSLを利用していますが、OpenVPNに付属しているEasyRSA、Windows用GUIのvpnux PKI Managerや他のアプリでも問題ありません。
次に接続方法を示す言葉にTUNとTAPがあります。
詳細はWikipedia:「TUN/TAP」に記載されていますが、簡単にいうとTUNを使うとネットワーク層、TAPを使うとデータリンク層での接続となります。
実際のネットワークに置き換えると、既存のネットワークに対してスイッチングHUBを使って接続しようとするのがTAP、ルーターを使って接続しようとするのがTUNとなります。
ただOpenVPNにおいてはTAP接続をするには、現実世界でHUBを接続するように簡単にはいきません。またスマホアプリにおいては執筆時点ではTAP接続がサポート外になっていたこともあり、どうせ覚えるなら汎用的な方という事で、ここではTUN接続をしていきます。
インストール
OpenVPNのインストールはこちらよりダウンロードして実行すれば、特に問題なく入ると思います。よくこのブログで紹介しているDebianならaptからもインストール可能です。
WindowsではGUIツールもインストールされます。GUIから設定ファイルを指定するか、Program FilesのOpenVPNフォルダにopenvpn.exeがあるのでそれを、設定ファイルのパスを引数にして起動させます。
サーバー側の設定ファイル
OpenVPNでは明確にサーバー(接続を待機する)とクライアント(接続を要求する)側に役割が分かれています。どちらもプログラムファイルに設定ファイル(のパス)を渡すことによって起動されます。共通の設定も多いですが、まずはサーバー側で必要な設定を見ていきます。
オプションはたくさんありますが、TUN接続における証明書認証で最低限必要な個所だけ記します。これらの説明はOpenVPN:「How To」やDebian(Linux)ならman openvpnから確認することもできます。
- proto udp
通信プロトコルです。udpかtcpを指定します。通常はudpでいいと思います。サーバーとクライアントで同じにしておく必要があります。ここではudpを指定します。
- dev tun
前述した接続形態です。tunでネットワーク層接続、tapでデータリンク層接続となります。サーバーとクライアントで同じ値にしておく必要があります。ここではtunを指定します。
- tls-server
証明書認証における役割の設定で、サーバーであることを設定しています。
- ca cafile.crt
証明書認証におけるCA証明書のパスを記入します。Windows環境で¥が存在する時は¥を/(スラッシュ)に置き換えるか。エスケープして¥¥とします。
- cert server.crt
証明書認証における自身の端末の証明書を指定します。指定方法はcaと同じです。
- key server.key
証明書認証における自身の端末の秘密鍵を指定します。指定方法はcaと同じです。
- dh dh2048.pem
ディフィー・ヘルマン鍵共有のパラーメータファイルを指定します。
公開鍵暗号方式では公開鍵・秘密鍵のセットを使って、両者の間で交換した共通鍵を使って通信をするしくみになっています。
何らかの原因で公開鍵暗号方式の鍵が漏洩しても、その通信で利用されていた共通鍵がわからないようにします。
このような処理がなされていない場合、通信全体を盗聴され保存されていると過去にさかのぼって通信内容を解読されてしまいます。
ファイルの指定方法はCAと同様です。
ちなみにOpenSSLでDHパラメータを作成するには「openssl dhparam -out dh2048.pem 2048」とします。
- server 192.168.1.0 255.255.255.0
TUN接続時のサーバーとクライアントが所属するネットワークを指定します。この時サーバーは192.168.1.1になり残りのアドレスはクライアントにやクライアントと接続するエンドポイントで利用されます。
後述のclient-config-dirを使う事によって、クライアント毎に別のネットワークを割り当てサーバーとして複数のネットワークを利用することも可能です。
サーバーのその他のconfigオプション
必須ではありませんが、使用する可能性の高いconfigも書いておきます。
- port 1194
記述をを省略すると1194番ポートが利用されますが変更することもできます。これはクライアントの設定と同じ値にする必要があります。
- dev-none <devName>
Windows時に使用するTAPアダプタ名称を指定します。1つしかない場合は省略できます。ここではコメントアウトして省略します。
- route 192.168.40.128 255.255.255.0
サーバーのOSにOpenVPNが管理しているアドレスを通知します。ここで設定した宛先のパケットはOSからOpenVPNに転送されます。
serverとして設定したアドレスは自動で反映されますので記述は不要です。client-config-dirで設定したアドレスに関しては記述が必要です。
- push "route 192.168.2.0 255.255.255.0"
サーバ側のネットワークの奥にあるネットワークを接続してきたクライアントに通知します。接続が不要だったり、クライアント側が自身で経路設定するのなら記述は必要はありません。
- ifconfig-pool-persist ipp.txt
「ifconfig-pool-persist ipp.txt」では配布済みのIPアドレスを再現するために使うファイルです。ユーザー接続中に再起動が行われた際などにこのファイルから情報を取得してクライアントにそれまでと同じアドレスを割り当てます。ファイルの中身は次のようになっています。
#ipp.txtの中身 user1,192.168.1.2 user2,192.168.1.3
- client-config-dir ccd
クライアント毎に送信する設定を変えたい場合は、フォルダ(この場合はccd)を作成し、そこにユーザー名と同じ名前でファイルを作成します。
証明書認証の場合はユーザー名はCommon Nameとなります。
たとえばクライアント毎アクセス権限を変えたい場合、このエントリーを使ってクライアント事にネットワーク設定を変える必要があります。その際はifconfig-pushを使って次のようにします。
ifconfig-push 192.168.1.21 192.168.1.22先にクライアント側のIPアドレス、次にサーバーのIPアドレスになります。ここでは利用可能な4オクテット目のアドレスの組み合わせは決まっています。How Toページに掲載されていますが、1と2の組み合わせだけ覚えておいて、あとは4の倍数をそれぞれに足したものが利用可能だと覚えておくと簡単です(253と254まで)。
- client-to-client
接続を待ち受ける方サーバーは複数のクライアントと同時接続ができます。この時クライアント同士が接続できるか否かの設定をします。client-to-clientを設定するとクライアント同士で接続が可能になります。必要なければコメントアウトのままにしておきます。
- comp-lzo
データ圧縮形式をlzoに設定しています。これはクライアントとサーバーの両方で同じ設定にする必要があります。圧縮は通信の高速化につながりますが、サーバークライアント双方のCPUを消費します。
- keepalive 10 60
接続確認の間隔と切断と判断されるまでの秒数を指定します。この場合は10秒毎に接続確認をして、60秒間応答がなかったら切断とみなす設定です。
- tls-auth file-path
Dos攻撃防止策です。file-pathにスタティック認証用のキーファイルを指定します。HMAC署名を使って対象外のファイルを破棄します。
- persist-key
UNIX系の環境においては、OpenVPNは起動時には管理者権限で動きその後ユーザー権限に降格するそうです。そういう挙動になるのは鍵の操作については管理者権限が必要だからです。ただ、ソフトウェア内部的に再起動する時に困ります。管理者権限を失っている為に鍵の操作ができません。それに対応するために、内部的な再起動の際も鍵の読み込みはせず現状を維持します。
これは「SIGUSR1シグナル」(特殊な再起動)を受け取った時の内部的な再起動時のみ有効だそうです。
- persist-tun
persist-keyのネットワークインターフェース版です。
- verb 3
ログレベルです。一般的な運用では3が推奨されています。0にすると致命的なエラー以外はログが出ません。トラブルシューティング等には9を使います。
クライアントの設定
サーバー側と重なる部分も多いですが、クライアントにおいては次の設定項目があります。
- client
クライアントの設定であるという意味で、必要項目のいくつかはserverの設定から取得します。
- dev tun
- proto udp
- remote xxx.xxx.xxx.xxx
接続先のVPNサーバーのグローバルIPアドレスまたはドメインを記述します。
- tls-client
証明書認証における役割の設定で、クライアントであることを設定しています。
- ca ca.cert
ca証明書ファイルはサーバーに指定したものと同じ内容のものにする必要があります。
- cert client.cert
証明書ファイルは先のcaから証明してもらいます。基本的に端末それぞれに違うものが設定されます。
- key client.cert
端末毎の秘密鍵です。漏洩すると、通信の秘密が保証されません。
他にはpersist-keyやpersist-tunも設定できます。サーバー側でprotoやportをかえたりcomp-lzoを設定したりしたら、クライアント側にも同じ設定にしてください。
グローバルIPアドレスの取得方法
OpenVPNはクライアントからサーバーに接続する際グローバルIPアドレスが必要ですが、たいていの家庭では固定されたグローバルIPアドレスを持っていないと思います。グローバルIPアドレスはインターネットを接続する環境毎にひとつ(以上)割り当てられていますが、ルーターが再起動されたりするとそのアドレスが変更されることがあります。
グローバルIPアドレスが変更されると接続ができなくなってしまいます。その問題を解決してくれるのがDDNSというサービスです。家のVPNサーバーのグローバルIPアドレスの変更をそのサービスが記録してくれるので、そこに問い合わせることにより現在のIPアドレスがわかるという仕組みです。
防犯カメラなどでも需要がありDDNSサービスはわりと多く存在します。有償、無償いろいろあります。有償のものほどサービスがダウンしないといった安定性や、変更時にすぐに反映してくれたりする即時性が高かったりします。
筆者はSoftEtherもVPNサーバーとして利用していて、こちらはDDNSサービスまで提供してくれているので、それを借用しております。(SoftEtherもOpenVPNもアドレスは一緒でポートでサーバーを振り分けています)
DDNSでの運用は、DDNS登録時にドメイン名をもらえるのでそれをconfigfileに記載します。あとはインターネット上にあるDDNSサービスがよろしくやってくれます。
ただ、DDNSにこだわる必要もありません。グローバルIPアドレスは接続が途切れない限りは変わりませんので、接続したい人が接続した時に目的のサーバーのグローバルIPアドレスを知ることができれば接続は可能です。
PHPが使えるホームページを持っていれば定期的に家からアクセスするスクリプトを組んでそこに記録しておいたり、IPアドレスを表示してくれるサイトにいってHTMLを解読して変更があったらメールするようにしたり、家に誰かがいれば確認してもらってもいいです。
ルーターの設定
もうひとつIPアドレスに関して問題があります。IPv4の世界ではインターネットから、ルーターの内側のIPアドレスを指定して接続することができない事です。
それを解決してくれるのがルーターに存在する「ポートフォワーディング」という機能です。ルーターの外側にVPNの用のデータが来た際に、それを内側のVPNサーバーへ転送してくれます。ルーターが何を基準にVPNのデータであるか否かを判断するかというと、先のOpenVPNのconfigファイルで設定したプロトコル(udp)とポート(1194)です。
例えば筆者の手持ちのルーターBuffalo WXR-1750DHPでは「ポートフォワーディング」のことを「ポート変換」と呼んでいますが、その設定画面では次のような感じです。
転送先の内部のIPアドレスは実際のサーバーのIPアドレスです。OpenVPNで設定するバーチャルなIPアドレスと混同しないように注意してください。
Windows10のクライアントにおけるセキュリティの設定
追記
下記の方法で、runasの/savecredオプションで資格情報を保存すると、資格情報を保存したユーザーで他のrunasを経由して他のすべてのアプリを動かせるようになってしまうことがわかりました。そのため以下の方法でセキュリティを確保することはできません。何か別の方法が見つかったら再度追記します。ここまでの設定でクライアントとサーバー間が接続できるようになります。しかし次の点がWindows10のOpenVPNClientの運用で次の事が問題に思えました。
- ユーザー権限でOpenVPN起動できない
セキュリティの為、PCはユーザー権限で動かしておきたいところです。多くのPCのHUBとなるサーバーに接続するのだからなおさらです。
- サーバーからPUSHされるルート情報ががOpenVPNのClientに反映されない
サーバーからPUSH経由で起動されるrouteコマンドを反映させるためには、管理者ユーザーで起動した上で管理者として実行(昇格)させないといけません。
- クライアントキーをコピーされて使いまわされるのを防ぎたい
Windows内にファイルとして存在するclient.key client.crtのセットをコピーされたら他のPCでも利用できてしまいます。これを防ぎたいです。
これらの問題に対応します。まずOpenVPNを管理者モードで起動させる方法です。WindowsではOpenVPN-GUIが一緒にインストールされますがここでは利用しません。openvpn.exeにconfigfileのパスを引数につけてコマンドラインで起動させます。
この仕組みは、runnasの/savecertオプションと、powershellでの権限昇格を組合わせて実現します。
runnasの/savecertについては「ユーザーがパスワードなしで管理者としてプログラムを実行できるようにする方法」、権限昇格については「runasコマンドでuser:Administratorとしても管理者権限で動かせない」を参考にさせていただきました。ありがとうございました。
まずデスクトップを右クリックで、「新規作成」「ショートカット」でリンク先に先の行を設定します。usernameの部分は実際にOpenVPNを起動させる管理者権限がありパスワードが設定されたユーザーを設定します。
さらに この中でd:¥ovpn¥vpn.batとしてファイルを指定しています。このファイルの中に実際のopenvpnのコマンドを記述します。
コマンドウインドウやパワーシェルウインドウ、UAC画面が出てきてスマートではありませんが、一応これでWindowsをユーザー権限で動かした状態でパスワードを求められることなく、管理者権限でopenVPNを起動させることができます。
ショートカットリンク
runas /savecred /user:username "powershell start-process d:\ovpn\vpn.bat -verb runas"vpn.bat
"C:\Program Files\OpenVPN\bin\openvpn.exe" d:\ovpn\config.ovpnただし、一度パスワードを知っている人がユーザー権限のウインドウズでこのコマンド(ショートカット)を起動させる必要があります。ここで入力されたパスワードは「コントロールパネル」「資格情報マネージャ」「Windows資格情報」に保存されます。
証明書ファイルをコピーして使いまわされないようにするには、秘密鍵ファイル(.key)の権限を修正して一般ユーザーから読み取り不可します。
まず管理者ユーザーでログインした状態で、秘密鍵ファイルを右クリックでプロパティを出します。「セキュリティ」タブから「詳細設定」を開きます。
「継承の無効化」をクリックするとメッセージが表示されますので、上段の「継承されたアクセス許可をこのオブジェクトの明示的なアクセス許可に変換しますを選択します。アクセス許可エントリを削除「Authencted Users」と「Users」のエントリーを削除します。
追加タブからOpenVPNを起動させるユーザーを指定して追加します。「プリンシパルの選択」で先ほど「Runas」で設定したOpenVPNを起動させる対象のユーザー名を入れて、「フルアクセス」を選択してください。
ユーザー権限でOpenVPNが起動されて接続できるけれど、.keyファイルはオープンできない状態になっていれば成功です。読み取り不可なのでコピーもできないという仕組みです。
今度は同じ方法で作成したショートカットと、vpn.batのファイルに対して、UsersとAuthenticated Usersの書き込み権限を外します。先ほど削除した画面で「編集」を押すと編集画面になるので、「書き込み」のチェックボックスを外します。
runasで起動するファイルを変更されたり、batファイルの中身を変えられたりするとユーザーが管理者権限で何でもできてしまいます。
次回はここからもう一歩進めて、ネットワーク単位で端末を接続する方法やスマホにOpenVPNクライアントをインストールする方法について書きます。