この記事は古くなっています。以下の記事を参照してください。


災害時用無料Wi-Fi「00000JAPAN」悪用した攻撃に内閣府が注意喚起” を読んで、私も自前の VPN サーバを建てておこうと思いました。iOS 対応の IKEv2 VPN サーバを、Cent OS 7 で構築する方法を 2回に分けて書きたいと思います。前編では、Let's Encrypt で発行されたサーバ証明書を使って Strongswan を構築し、パスワード認証でいいので VPN が利用できることを確認します。後編では、Let's Encrypt のサーバ証明書を使用したまま、オレオレ認証局を建ててクライアント証明書を使った認証に切り替える方法をご紹介する予定です。

VPN サーバを建てる前に

VPN サーバはその性質上、正しく設定しなかった場合に、貴方が責任を負っている IP アドレスを不特定多数の人に自由に使わせることになります。不適切な設定の VPN サーバは、パスワードなし、あるいは初期パスワードのままの Wi-Fi ルータを設置するのと変わらないとお考えください。悪用された場合は、IP アドレスを元に(貴方が悪用していなくても)、貴方の PC やサーバ等が捜査機関により押収されるでしょう。

本ページの情報は、内閣府の注意喚起に呼応するもので、公益に資すると信じて執筆していますが、十分な知識がないままの VPN サーバの運用は大変危険です。また、本ページの情報を元に VPN サーバを運用した結果について、筆者は何の責任も取れません。ご了承の上、お読みください。

インストールと設定

前提として、Let's Encrypt からサーバ証明書は取得済みとします。証明書はウェブサーバで使用中のものでも、SAN で別名がたくさん設定されているものでも、全く問題なく使えます。読者のスキルとしては、Apache または Nginx などの SSL 設定をしたことがある程度を想定しています。

最初に Strongswan をインストールします。EPEL レポジトリが必要です。yum に追加の設定が必要かもしれません。

$ sudo yum install strongswan
インストール:
  strongswan.x86_64 0:5.6.3-1.el7

$ 

/etc/strongswan/ipsec.d 以下の設定

Let's Encrypt に発行してもらったサーバ証明書を /etc/strongswan/ipsec.d 以下のディレクトリから参照できるように、シンボリックリンクを貼ります。

$ LETSENCRYPT=/etc/letsencrypt/live/example.com
$ IPSECD=/etc/strongswan/ipsec.d
$ sudo ln -s ${LETSENCRYPT}/cert.pem ${IPSECD}/certs/
$ sudo ln -s ${LETSENCRYPT}/chain.pem ${IPSECD}/cacerts/
$ sudo ln -s ${LETSENCRYPT}/privkey.pem ${IPSECD}/private/
$ 

IKEv2 VPN で最低限必要な証明書は、サーバ証明書の公開鍵(cert.pem)、秘密鍵(privkey.pem)、ルート証明書までの証明書チェーン(chain.pem)の 3つです。これらを /etc/strongswan/ipsec.d 以下の適切なディレクトリに配置するだけです。お気付きの通り、Apache などウェブサーバの SSL 設定と何ら変わるところはありません。他の認証局が発行したものも、全く同様に使えます。

DER 形式にわざわざ変換している解説記事を良く見かけますが、PEM のままで OK です。また、/etc/strongswan/ipsec.d 以下を認証局のように使っている解説も良く見かけますが、そのような運用は今何を設定したのか、本質が見えにくくなるだけだと思います。

/etc/strongswan/ipsec.conf の設定

/etc/strongswan/ipsec.conf を設定します。# Add connections here. に続いて、以下のように設定します。

# Add connections here.
conn %default
      keyexchange=ikev2
      ike=aes128-sha256-ecp256,aes256-sha384-ecp384,aes128-sha256-modp2048,aes128-sha1-modp2048,aes256-sha384-modp4096,aes256-sha256-modp4096,aes256-sha1-modp4096,aes128-sha256-modp1536,aes128-sha1-modp1536,aes256-sha384-modp2048,aes256-sha256-modp2048,aes256-sha1-modp2048,aes128-sha256-modp1024,aes128-sha1-modp1024,aes256-sha384-modp1536,aes256-sha256-modp1536,aes256-sha1-modp1536,aes256-sha384-modp1024,aes256-sha256-modp1024,aes256-sha1-modp1024!
      esp=aes128gcm16-ecp256,aes256gcm16-ecp384,aes128-sha256-ecp256,aes256-sha384-ecp384,aes128-sha256-modp2048,aes128-sha1-modp2048,aes256-sha384-modp4096,aes256-sha256-modp4096,aes256-sha1-modp4096,aes128-sha256-modp1536,aes128-sha1-modp1536,aes256-sha384-modp2048,aes256-sha256-modp2048,aes256-sha1-modp2048,aes128-sha256-modp1024,aes128-sha1-modp1024,aes256-sha384-modp1536,aes256-sha256-modp1536,aes256-sha1-modp1536,aes256-sha384-modp1024,aes256-sha256-modp1024,aes256-sha1-modp1024,aes128gcm16,aes256gcm16,aes128-sha256,aes128-sha1,aes256-sha384,aes256-sha256,aes256-sha1!
      dpdaction=clear
      dpddelay=300s
      rekey=no

conn IPSec-IKEv2
      keyexchange=ikev2
      left=%any
      leftsubnet=0.0.0.0/0
      leftid=example.com
      leftcert=cert.pem
      leftsendcert=always
      right=%any
      rightid=%any
      rightdns=8.8.8.8,8.8.4.4
      rightsourceip=192.168.1.0/24
      auto=add

conn IPSec-IKEv2-EAP
      also="IPSec-IKEv2"
      rightauth=eap-mschapv2
      eap_identity=%any
      auto=add

設定項目の要点は以下の通りです。

  • left にはサーバの IP アドレス、FQDN、サブネットなどを指定します。今回は特に指定しないので %any とします。
  • leftcert にはサーバ証明書のファイル名を書きます。
  • leftid にはサーバ証明書の COMMON NAME (または SAN)を書きます。
  • right にはクライアントの IP アドレス、FQDN、サブネットなどを指定します。今回は公衆無線 LAN などからの接続を想定しており、事前に IP アドレスを特定できないので %any とします。
  • rightdns にはクライアントに伝える DNS のアドレスです。
  • rightsourceip にはクライアントに割り付ける IP アドレスの範囲を指定します。

/etc/strongswan/ipsec.secrets の設定

/etc/strongswan/ipsec.secrets にサーバの秘密鍵(privkey.pem)と、ユーザ名とパスワードを設定します。

# ipsec.secrets - strongSwan IPsec secrets file
: RSA privkey.pem

vpnuser : EAP "plaintext-password"

ここでは、ユーザ vpnuser のパスワードを plaintext-password としています。適宜変更してください。パスワードはなんと直書きですが、クライアント証明書に置き換えるまでの一時的な設定として、気にしないことにします。

/etc/strongswan/strongswan.d/charon-logging.conf の設定

接続トラブルがあったときの原因究明のため、ログレベルを上げておきます。Strongswan の動作ログは、/var/log/messages に出力されます。

  # Default loglevel.
  default = 2
  
  # flush_line = no
  flush_line = yes
  
  # time_format =
  time_format = %F %T

Firewalld 設定

次に、ipsec(IKEv2)を使えるようにします。

$ sudo firewall-cmd --permanent --add-masquerade
success
$ sudo firewall-cmd --permanent --add-service=ipsec
success
$ sudo firewall-cmd --reload
success
$ 

sudo firewall-cmd --permanent --info-service=ipsec をすると分かるように、サービス ipsec を追加すると 500/udp と 4500/udp が開きます。余計な手順を解説している記事が散見されますが、実際に確認していただけるとおりです。

systemctl

VPN サーバを起動します。

$ sudo systemctl enable strongswan
Created symlink from /etc/systemd/system/multi-user.target.wants/strongswan.service to /usr/lib/systemd/system/strongswan.service.
$ sudo systemctl start strongswan
$

iOS 端末からの接続テスト

(iOS 11.4)こんな感じで設定します。

  • サーバ: example.com
  • リモートID: example.com
  • ローカルID: (空欄)
  • ユーザ認証: (“ユーザ名” を選択)
  • ユーザ名: vpnuser(ipsec.secrets に設定したユーザ名)
  • パスワード: plaintext-password(ipsec.secrets に設定したパスワード)
  • プロキシ: オフ

接続して、画面左上に VPN のアイコンが表示されれば OK です。

ユーザ名は vpnuser@example.com のような形式でないとダメ、とする解説記事も多いのですが、私が試した限り、(パスワード認証、クライアント証明書認証の区別なく)そのような制限はありませんでした。どこからそのような話が出てきたのでしょうか?

パスワード直書きでは心許ないですが、まずは Strongswan の基本を抑えましょう。頭を整理しておかないと、セキュアにしたつもりが大きなセキュリティーホールを作りかねません。その上で、後編に続きます。