VPS に VPN サーバをたてて iPhone からアクセス(第3回)

レンタル VPS で VPN サーバを動かして iPhone からのネットアクセスをセキュアにする(ついでに自宅 LAN にリモートアクセスできるようにする)というお話の第3回です。今回は iPhone から SoftEther VPN Server に L2TP/IPsec で接続するお話です。

まずは公式マニュアル

サーバ側の設定

第2回の記事にも書きましたが、サーバ環境は次のとおりです:

Interface: vnet1
IPv4: 192.0.2.33/24
IPv6: 2001:db8::2:33/64
FQDN: vpn33.example.com

まず、ファイアウォールに穴をあけます。UDP 500番ポートと、UDP 4500番ポートで、待ち受けできるようにします。

$ sudo iptables -A INPUT -i vnet1 -d '192.0.2.33' -p udp --dport 500 -j ACCEPT
$ sudo iptables -A INPUT -i vnet1 -d '192.0.2.33' -p udp --dport 4500 -j ACCEPT
$ sudo iptables -L -vn
$ sudo ip6tables -A INPUT -i vnet1 -d '2001:db8::2:33' -p udp --dport 500 -j ACCEPT
$ sudo ip6tables -A INPUT -i vnet1 -d '2001:db8::2:33' -p udp --dport 4500 -j ACCEPT
$ sudo ip6tables -L -vn
$ sudo /etc/init.d/iptables-persistent save

次に、SoftEther VPN Server で L2TP/IPsec 接続を有効化します。

Windows PC 上の「SoftEther VPN サーバー管理マネージャ」でサーバに接続して設定する場合は、次のスクリーンショットのように設定します:

もちろん、vpncmd コマンドを使えばコマンドライン上でも設定できます:

$ ./vpncmd localhost:443 /SERVER
VPN Server>IPsecEnable /L2TP:yes /L2TPRAW:no /ETHERIP:no /PSK:Ppz6o5x9J /DEFAULTHUB:hub01

なお、PSK (Pre-Shared-Key) には35文字くらいのランダムな英数字を指定するのが良さそうです。とある解説記事によれば「30~40文字で英数字のみ」が推奨らしいです。ただし、SoftEther VPN 公式マニュアルの IPsecEnable コマンドの説明には「Google Android 4.0 にはバグがあり、PSK の文字数が 10 文字を超えた場合は VPN 通信に失敗することがあります。そのため、PSK の文字数は 9 文字以下にすることを推奨します。」と書かれているので、古い Android を使いたい人は9文字推奨です(上記の例はこれ)。

参考:

iPhone 側の設定

iOS 10.3.1 で試しました。

iOS 標準機能で L2TP/IPsec 接続が可能です。アプリのインストールは不要です。VPN 接続の ON/OFF も、標準の「設定」アプリでできます。

  1. 「設定」アプリを起動。
  2. 「VPN」を選択。
  3. 「VPN構成を追加…」を選択。
  4. 「タイプ」は「L2TP」を選択。
  5. 「説明」欄は「hub01@vpn33」とか適当に入力。
  6. 「サーバ」欄には「vpn33.example.com」と入力。
  7. 「アカウント」欄には「yamada@hub01」と入力。
  8. 「RSA SecureID」は OFF のまま。
  9. 「パスワード」欄には「K8nhrGJHHe98tCck4NGA」と入力。
  10. 「シークレット」欄には PSK 「Ppz6o5x9J」を入力。
  11. 「すべての信号を送信」は ON のまま。
  12. 「プロキシ」は「OFF」のまま。
  13. 右上の「完了」を押す。
  14. 「VPN」画面で、追加した構成を押す(チェックマークが付く)。
  15. 「状況」欄が「未接続」となっているでタッチ。
  16. 「状況」欄が「接続しています…」となる。
  17. VPN 接続に成功すると「状況」欄が「接続中」になる。
  18. 画面左上の電波状況アイコンの隣に「VPN」アイコンが表示されていれば完了。

これで VPN を経由して普通にインターネットにアクセスできるはずです。Safari や Twitter や LINE などが使えることを確認してください。

サーバ側のログを確認

vpnserver を実行したディレクトリにログファイル用のディレクトリが自動的に作られているはずです。デフォルトでは、自動的に定期的に新しいログファイルに切り替わっていきます。ログファイルは単なる UTF-8 のテキストファイルです。SoftEther VPN Server の言語設定が「日本語」だと、ログも日本語になります。

$ less server_log/vpn_20170510.log

先ほど iPhone からアクセスしたログが表示されるはずです。仮想 HUB「hub01」にユーザ名「yamada」で接続しているはずです。

2017-05-10 12:05:57.268 [HUB "hub01"] コネクション "CID-4" (IP アドレス 203.0.113.111, ホスト名 203.0.113.111.example.com, ポート番号 1701, クライアント名 "L2TP VPN Client", バージョン 4.20 ビルド 9608) が仮想 HUB への接続を試行しています。提示している認証方法は "外部サーバー認証" でユーザー名は "yamada" です。
2017-05-10 12:05:57.268 [HUB "hub01"] コネクション "CID-4": ユーザー "yamada" として正しく認証されました。
2017-05-10 12:05:57.268 [HUB "hub01"] コネクション "CID-4": 新しいセッション "SID-YAMADA-[L2TP]-2" が作成されました。(IP アドレス 203.0.113.111, ポート番号 1701, 物理レイヤのプロトコル: "Legacy VPN - L2TP")

VPS に VPN サーバをたてて iPhone からアクセス(第2回)

レンタル VPS で VPN サーバを動かして iPhone からのネットアクセスをセキュアにする(ついでに自宅 LAN にリモートアクセスできるようにする)というお話の第2回です。今回は SoftEther VPN Server の導入編です。

SoftEther VPN とは

SoftEther VPN は、オープンソースで高機能な VPN ソフトウェアです。独自の VPN 通信方式を実装していて、様々なネットワーク構成に柔軟に対応しています。また、独自の Windows/Linux クライアントはもちろん、L2TP/IPsec や MS-SSTP や OpenVPN など、多くのクライアントからの接続が可能です。

SoftEther VPN を選んだ理由

  • Layer 2 VPN なので LAN 専用のホーム機器にもリモートアクセス可能。
  • ファイアウォール貫通機能が異様に強い。
  • クラウド上の Linux VPS (Ubuntu 14.04 LTS) で VPN サーバを動かせる。
    • プログラムとして x86_64 Linux(カーネルが古い)で動作可能。
    • VPS が設置されているネットワークに迷惑をかけない。
      (構築した VPN がサーバの実ネットワークから切り離されている)
  • iPhone からの接続が可能。
    • iOS 標準機能の L2TP/IPsec が使える。
    • L2TP/IPsec がダメでも OpenVPN が使える。
  • 自宅の Windows PC から接続可能。
  • 自宅の Windows PC をブリッジとして自宅 LAN にリモートアクセス可能。
  • 将来的に Raspberry Pi を買えばブリッジとして使える。
  • VPN サーバをユーザモードで動かせる。 ★すごくうれしい★
  • NAT 機能と DHCP サーバ機能を内蔵していて簡単に使える。
  • 待ち受けポート番号を変更できる(デフォルトは避けたい)。
  • Windows GUI アプリからでも SSH コマンドラインからでも設定・管理が可能。
  • オープンソースなので好きに改造できる。
  • 日本語のマニュアルが充実している。
  • 国産のプロダクトであり、応援したい。

ちなみに、ちょっと気になる点もあります:

  • TLS 1.2 に対応していない(TLS 1.0 のみ)。
  • 使用できる暗号スイートが古い(弱い)。
  • SHA-1 しか選べない(SHA-256 にしたい)。
  • 証明書の鍵が RSA 2048bit までしか選べない(弱い)。
  • 証明書の SAN フィールドに対応していない(廃止された CN フィールドを見てる)。
  • 日本語のログを吐く(検索や加工がしにくい)。
  • テストスクリプトが公開されていない(改造してもテストできない)。

SoftEther VPN Server のダウンロード

ダウンロードするアーカイブファイルの URL は公式サイト参照: https://ja.softether.org/5-download

最新版 (beta) と安定版 (RTM) が異なる場合は、お好きな方を選んでください。

表示されたリンクの URL をコピペしてダウンロードします:

$ cd softether
$ curl -O http://jp.softether-download.com/files/softether/v4.20-9608-rtm-2016.04.17-tree/Linux/SoftEther_VPN_Server/64bit_-_Intel_x64_or_AMD64/softether-vpnserver-v4.20-9608-rtm-2016.04.17-linux-x64-64bit.tar.gz
$ mkdir softether-vpnserver-v4.20-9608-rtm-2016.04.17-linux-x64-64bit
$ cd softether-vpnserver-v4.20-9608-rtm-2016.04.17-linux-x64-64bit
$ tar xvfz ../softether-vpnserver-v4.20-9608-rtm-2016.04.17-linux-x64-64bit.tar.gz

セキュリティ関係のソフトウェアなのに配布サーバが HTTPS 化されてないのが残念。不安な人は GitHub からソースファイルをダウンロードしてビルドしましょう。

今回のサーバ環境

今回のインストール先は、クラウド上のレンタル VPS です。

仮想化方式 : OpenVZ (Linux カーネルが更新できない!)
CPU : Intel Xeon
Memory : 2GB
OS : Ubuntu 14.04 LTS (x86_64)
グローバル IP アドレス : 固定で2個(IPv6 ありの仮想インタフェース)

2個あるグローバル IP アドレスは、いずれも FQDN で DNS lookup できます。ただし、CNAME レコードで DNS に登録しているため、逆引きはその FQDN とは異なります。今回は、2個あるグローバル IP アドレスのうち、「default route でない方」を SoftEther VPN Server で使用します。文中では、仮に、以下の値を使用します:

Interface: vnet1
IPv4: 192.0.2.33/24
IPv6: 2001:db8::2:33/64
FQDN: vpn33.example.com

なお、ほんとうは Docker で SoftEther VPN Server を動かしてみたかったのですが、Linux カーネルが古くて Docker は使えませんでした。上記のとおり仮想化方式が OpenVZ なので、カーネルの更新ができないのです。残念!

SoftEther VPN Server のインストール

まず、公式マニュアルを参照:

今回は SoftEther VPN Server をユーザモードで動かすので、公式マニュアルの「7.3.6 VPN Server の配置」以降の作業はやりません(make を実行するだけです)。

$ cd vpnserver
$ nice -19 make

無事に make できたら、実行に必要なファイルだけ手動でコピーします。

$ mkdir ../../bin
$ cp -p hamcore.se2 vpncmd vpnserver ../../bin
$ cd ../../bin

ここでひとつ、おまじないが必要です。

SoftEther VPN Server はデフォルトで TCP 443番ポート(https プロトコル用のポート)で接続を待ち受けます(bind します)。また、iPhone からの接続に L2TP/IPsec を使う場合、UDP 500番ポートと UDP 4500番ポートも bind します。Linux(というか UNIX 全般)では1024番未満のポートを bind するためには「特権」(capabilities) が必要です。iptables で1024番以上のポートにリダイレクトする、という抜け道もありますが、SoftEther VPN Server で L2TP/IPsec の待ち受けポート番号を変える方法がわからないので、今回は使えません(参考記事:「一般ユーザ権限で特権ポートを bind したい」)。Docker を使えればポートマッピングでなんとかなったかもしれませんが。

今回は、Linux の “File Capabilities” 機能を利用して、実行ファイル vpnserver に CAP_NET_BIND_SERVICE 権限を付与します。これにより、root 権限がなくても、この実行ファイルを実行したときに限り、1024番未満のポートを bind できるようになります。ついでに、念のため、ディレクトリ丸ごと Owner を別のユーザに変更して、実行ファイルを書き換えられないようにしておきます。

$ sudo chmod -R a-w .
$ sudo chown -R nobody .
$ sudo chgrp -R nogroup .
$ sudo setcap CAP_NET_BIND_SERVICE+eip vpnserver

もし、setcap コマンドが無いと怒られたら、libcap2-bin パッケージをインストールしてください。CentOS などの RPM 系では libcap パッケージらしいです。(参考ページ

$ sudo apt-get install libcap2-bin

最後に、vpnserver を実行するディレクトリ(この配下にログファイルなどが作られる)に移動して、上記ファイルへのシンボリックリンクを作成します。

$ mkdir ../run
$ cd ../run
$ rm -f hamcore.se2 vpncmd vpnserver
$ ln -s ../bin/hamcore.se2
$ ln -s ../bin/vpncmd
$ ln -s ../bin/vpnserver

初期状態では SoftEther VPN Server の管理者パスワードが設定されていないので、まだファイアウォール (iptables) に穴を開けてはいけません。ローカル・ループバック通信は iptables でデフォルトで許可されているはずなので、次に説明する初期設定は可能なはずです。

SoftEther VPN Server の初期設定

上記の公式マニュアルでは、vpnserver を起動してから**「できるだけ早く」**VPN サーバー管理マネージャで接続して管理者パスワードを変更するように、と書かれていますが、セキュリティ関係のソフトウェアでそんな危ういことをしてはいけません。

まず、vpnserver が初期状態で bind するすべてのポートを、ファイアウォール (iptables と ip6tables) がブロックしていることを確認します。

  • 443/tcp
  • 992/tcp
  • 1194/tcp
  • 5555/tcp

次に、vpnserver を起動します。起動するとすぐにコマンドプロンプトに戻ってきます。

$ date && nice -10 ./vpnserver start

続いて、vpncmd を実行して初期設定を開始します。

$ ./vpncmd localhost:443 /SERVER
  1. 管理者パスワードを設定する。
  2. デフォルトのリスナーポート「992番」を Disable する。
  3. デフォルトのリスナーポート「1194番」を Disable する。
  4. デフォルトのリスナーポート「5555番」を Disable する。
  5. SSL 通信で使用する暗号化アルゴリズムを一番強い「DHE-RSA-AES128-SHA」に変更する。
  6. 「インターネット接続の維持機能」を Disable する。
  7. 「VPN Azure 中継サービス」を利用しないようにする。
  8. デフォルトで存在している仮想 HUB「DEFAULT」を削除する。
  9. ランダムに初期化されたサーバ証明書をファイルとして保存しておく。
  10. SoftEther VPN プロジェクトが提供している Dynamic DNS (DDNS) サービスを利用しないようにする。

最後の項目だけは vpncmd では設定できません。それ以外の項目を vpncmd 上で設定します。

VPN Server>ServerPasswordSet
VPN Server>ListenerList
VPN Server>ListenerDisable 992
VPN Server>ListenerDisable 1194
VPN Server>ListenerDisable 5555
VPN Server>ServerCipherGet
VPN Server>ServerCipherSet DHE-RSA-AES128-SHA
VPN Server>KeepDisable
VPN Server>VpnAzureSetEnable no
VPN Server>HubDelete DEFAULT
VPN Server>ServerCertGet ./cert.pem
VPN Server>exit

なお、今回は接続性を優先して待ち受けポートを443番(HTTPS と同じ)にしていますが、セキュリティを優先するなら別のポートにしたほうが良いです。1024番以上のポートを使えば、前述の「おまじない」(Capabilities 付与)も不要になります(ただし iPhone から L2TP/IPsec 接続する場合は UDP 500番ポートを使うので「おまじない」必須)。

vpncmd が終了したら、vpnserver も停止させます。

$ ./vpnserver stop

続いて、設定ファイル vpn_server.config をテキストエディタで開いて、直接編集します。公式マニュアルの “DynamicDnsGetHostname” の項を参照して、Dynamic DNS を無効化します。

最後に、設定ファイル vpn_server.config を別の機器(USB メモリとか)にバックアップしておきます。ただし、このファイルには SoftEther VPN Server の秘密鍵が含まれているので、取り扱いには注意しましょう。

ファイアウォールに穴を開ける

TCP 443番ポートのみ待ち受け可能にします。

$ sudo iptables -A INPUT -i vnet1 -d '192.0.2.33' -p tcp --dport 443 -j ACCEPT
$ sudo iptables -L -vn
$ sudo ip6tables -A INPUT -i vnet1 -d '2001:db8::2:33 ' -p tcp --dport 443 -j ACCEPT
$ sudo ip6tables -L -vn
$ sudo /etc/init.d/iptables-persistent save

もし、iptables-persistent が無いと怒られたら、iptables-persistent パッケージをインストールしてください。

$ sudo apt-get install iptables-persistent

vpnserver を起動して、ちゃんと TCP 443番ポートを listen しているか netstat コマンドで確認しておきます。

$ date && nice -10 ./vpnserver start
$ netstat -antu

仮想 HUB の新規作成

iPhone からネットアクセスする際に使う仮想 HUB を新規作成します。

  • 仮想 HUB の名前は hub01 とする。
  • iPhone 側のユーザ名は yamada とする。
  • ユーザ yamada のパスワードは K8nhrGJHHe98tCck4NGA とする(乱数生成)。
  • 仮想 HUB 管理パスワードは不要なので設定しない。
  • SecureNAT 機能を有効化する(デフォルトで DHCP サーバ機能も有効になる)。
  • 仮想 HUB で使用するサブネットは 192.168.223.0/24 とする(他とかぶらなさそうなプライベートアドレスを適当に選ぶ)。

実際の作業は vpncmd で行います。もちろん、Windows PC の「SoftEther VPN サーバー管理マネージャ」でも同様の設定が可能です。

$ ./vpncmd localhost:443 /SERVER
VPN Server>HubCreate hub01
VPN Server>Hub hub01
VPN Server>SetEnumDeny
VPN Server>UserCreate yamada /GROUP:none /REALNAME:none /NOTE:none
VPN Server>UserPasswordSet yamada
K8nhrGJHHe98tCck4NGA
VPN Server>SecureNatStatusGet
VPN Server>SecureNatHostGet
VPN Server>SecureNatHostSet /MAC:none /IP:192.168.223.1 /MASK:255.255.255.0
VPN Server>NatGet
VPN Server>DhcpGet
VPN Server>DhcpSet /START:192.168.223.10 /END:192.168.223.200 /MASK:255.255.255.0 /EXPIRE:86400 /GW:192.168.223.1 /DNS:192.168.223.1 /DNS2:none /DOMAIN:none /LOG:yes
VPN Server>SecureNatEnable
VPN Server>SecureNatStatusGet

iPhone から接続するときには、ユーザ名として「yamada@hub01 」を、パスワードとして「K8nhrGJHHe98tCck4NGA」を、それぞれ使用することになります。

なお、仮想 HUB を新規に作成したときは、「SoftEther VPN サーバー管理マネージャ」の仮想 HUB のプロパティ設定ウインドウでチェックボックス「匿名ユーザーに対してこの仮想 HUB を列挙しない」に必ずチェックを入れましょう。あるいは、vpncmd で仮想 HUB 設定に遷移して SetEnumDeny コマンドを実行しても同じです(上記の設定例でも実行しています)。

より安全に運用するには

  1. Windows PC 上の GUI アプリ「SoftEther VPN サーバー管理マネージャ」を使わずに vpncmd だけで管理できるなら、管理者ログインを VPN サーバ内部からのみに制限できます。リモートから SoftEther VPN Server に直接接続して設定することが不可能になるので、より安全になります。もちろん、SoftEther VPN Server を動かしているサーバに SSH ログインできれば、vpncmd を使ってリモートから管理できます。

    具体的には、SoftEther VPN Server のリモート管理接続元 IP アドレスとして 127.0.0.1::1 だけを許可します。設定方法は公式マニュアルの「3.3.18 IP アドレスによるリモート管理接続元の制限」を参照してください。

  2. 万が一に備えて、vpnserver を実行するユーザを新たに作って SoftEther VPN Server 専用のユーザにすることをオススメします。

    SoftEther VPN Server のダウンロードや make などは普段使っているユーザで行い、生成された実行ファイル vpnserver とライブラリファイル hamcore.se2 を実行用ユーザのホームディレクトリ配下にコピーすれば、vpnserver を実行できます。実行用ユーザに GitHub などへのアクセス権を与える必要はありません。

    管理コマンド vpncmd は誰でも(vpnserver を実行しているユーザ以外でも)使えるので、vpnserver 実行用ユーザはそれこそ「ログインできないユーザ」(ログインシェルが /bin/false/usr/sbin/nologin になっているユーザ)でも問題ありません。というか、ログインできないように設定することをオススメします。

    vpnserver 実行用ユーザは、sudo できないユーザにしておきましょう。具体的な条件は /etc/sudoers の設定に依存しますが、デフォルトならば「グループ sudo に属さないユーザ」にしておけば大丈夫です。

    ユーザ root が存在するシステムでは、vpnserver 実行ユーザは root への su ができないユーザにしておきましょう。たとえば、グループ wheel に属しているユーザは避けましょう。