読者です 読者をやめる 読者になる 読者になる

k_piの雑記帳

個人的に困った点と、その解決法などをつらつら書き連ねた備忘録を兼ねたブログ

VPSを用いたVPNサーバーの立て方(DigitalOcean編)

 【動機】

最近、中国+香港に行く機会があったのだが、セキュリティやグレートファイアウォール(金盾)のことを考えると、
やはり、VPNを準備しておくべきだろうと考えたが、
VPN Gateといった無料サービスはボランティアに悪意のある人がいないとも限らないし、
セカイVPNHMAなどの有料サービスは短期利用では割高に・・・

また、既存のVPNサービスはグレートファイアウォール(金盾)で遮断されるリスクもある。

ということで、VPSを借りて自分でVPNサーバーを立ててやろうと考えた。

【概要】

今回は、DigitalOceanを利用したVPNサーバー(strongSwan)の立て方を紹介する。
DigitalOceanでは一番安いプランは月当り$5で、$1=110円であれば550円と有料VPNサービスより安く、
時間割で課金されるので1日(24時間)であれば$0.007×24=$0.168で済む。

サーバーのロケーション(場所)は、

から選べる。
日本が選択肢にないのが残念だが、IDCFクラウドにも立てたのでこちらに関しては後日紹介することとする。(かなり間が空くかもしれないが。。。)
次回記事を参照すること。(一週間で書けた(^。^))(11/27追記)

 【手順】

 1.DigitalOceanに登録する

DigitalOceanは日本語表記はなく英語であるが、シンプルなデザインのサイトなので、英単語がわかれば特に問題はない。

まず、右上の「Sign Up」をクリックし、メールアドレスと希望のパスワードを入力。
確認メールが届くので、メール内のURLからアクセスし、メールアドレス確認をする。
次に支払用のクレジットカード情報を入力すれば使える。(簡単( ^ω^ ))

2.Dropletを作成する

Dropletは仮想マシンのことで、簡単に言えばサーバーのこと。
「Droplets」→「Create Droplet」と進み、
ディストリビューションや性能、ロケーションなどを選択する。

ここでは、
ディストリビューションDebian 8.6 x64
性能:月当り$5のタイプ
ブロックストレージ(追加ストレージ):なし
リージョン:好きな所を選択(筆者は、サンフランシスコ2・アムステルダム3・トロント1でそれぞれ立てた)
オプション:なし
で作成した例を示す。

ここで、SSH keyを追加しておくと、すぐにSSH接続できるのでおすすめする。
WindowsTeratermを使っている人なら以下のサイトなどを参考にするといい。
SSH公開鍵暗号化方式-Tera Termで秘密鍵・公開鍵の作成 | Tera Term(テラターム)の便利な使い方

3.サーバーのセットアップをする

SSHクライアント(Teraterm等)から、「Droplets」ページに表示されているIPアドレスにアクセスし、
ユーザー「root」で、先ほどのSSH keyでログインする。

3.1.アップデート

ログインしたらすぐにアップデートを行う。

apt-get update
apt-get upgrade
3.1.仮想メモリの追加

以下を実行し、

fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

/etc/fstabに以下の記述を追加

/swapfile swap swap sw 0 0
3.3.iptablesの設定

iptables-persistentをインストールし、

apt-get install iptables-persistent

/etc/iptables/rules.v4を以下のように、

*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 192.168.200.0/24 -j MASQUERADE
-A POSTROUTING -s 192.168.201.0/24 -j MASQUERADE
-A POSTROUTING -s 192.168.202.0/24 -j MASQUERADE
-A POSTROUTING -s 192.168.203.0/24 -j MASQUERADE
-A POSTROUTING -s 192.168.204.0/24 -j MASQUERADE
COMMIT
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -p tcp -m tcp --tcp-flags SYN,ACK SYN,ACK -m state --state NEW -j REJECT --reject-with tcp-reset
-A INPUT -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j DROP
-A INPUT -m state --state INVALID -j DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 3 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 12 -j ACCEPT
-A INPUT -s 192.168.200.0/24 -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -s 192.168.200.0/24 -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -s 192.168.201.0/24 -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -s 192.168.201.0/24 -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -s 192.168.202.0/24 -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -s 192.168.202.0/24 -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -s 192.168.203.0/24 -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -s 192.168.203.0/24 -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -s 192.168.204.0/24 -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -s 192.168.204.0/24 -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p udp -m udp --dport 500 -j ACCEPT
-A INPUT -p udp -m udp --dport 4500 -j ACCEPT
-A INPUT -p esp -j ACCEPT
-A INPUT -p udp -m policy --dir in --pol ipsec -m udp --dport 1701 -j ACCEPT
-A INPUT -p udp -m udp --dport 1701 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -i ppp+ -j ACCEPT
-A FORWARD -o ppp+ -j ACCEPT
-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -s 192.168.201.0/24 -j ACCEPT
-A FORWARD -s 192.168.202.0/24 -j ACCEPT
-A FORWARD -s 192.168.203.0/24 -j ACCEPT
-A FORWARD -s 192.168.204.0/24 -j ACCEPT
-A OUTPUT -p udp -m policy --dir out --pol ipsec -m udp --sport 1701 -j ACCEPT
-A OUTPUT -p udp -m udp --sport 1701 -j REJECT --reject-with icmp-port-unreachable
COMMIT

/etc/iptables/rules.v6を以下のように、

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
COMMIT

変更する。

3.4.VPNのセットアップ

今回は、「L2TP-PSK」・「L2TP-RSA」・「XAuth-PSK」・「Xauth-RSA」・「Xauth-Hybrid」・「IKEv2-PSK」の接続方式に対応させる。
自分の好みに合わせて、取捨選択するといい。
それぞれの方式の特徴は以下の通り。

  • L2TP:対応機器が多いが、動作が不安定な感がある。
  • Xauth:Androidに対応しているが、Windowsは対応していない。
  • IKEv2:Windows7以降で対応しているが、Androidは対応していない。
  • PSK:事前共有鍵方式で認証する。事前に設定した文字列を機器に入力すれば使えるが、この文字列を盗まれたり推測されたりするとVPNが悪用される可能性がある。
  • RSA:公開鍵方式で認証する。セキュリティ的には最も強固になるが、事前に鍵ファイルのやり取りが必要であるなど面倒事が多い。
  • Hybrid:サーバー側のみ公開鍵方式で認証し、クライアントの認証はしない。RSAよりセキュリティの強固さは失われるが、クライアント鍵の管理が不要なのでRSAより多少簡便な方式。

PSK・RSA・Hybridの詳しい内容は以下のサイトが参考になると思う。
Racoon を使ったリモートユーザーアクセス VPN の構築方法

 

さて、本題に入ることにする。

3.4.1.「strongswan」・「xl2tpd」・「libcharon-extra-plugins」をインストールする

(「xl2tpd」はL2TPを使用しないなら不要である。)

apt-get install strongswan xl2tpd libcharon-extra-plugins
3.4.2./etc/sysctl.confを変更する

パケットの転送を有効・ソースルーティングを無効にするためにカーネルオプションを変更する。
ソースルーティングの無効化に関しては以下のページを参考にするといい。
2.2.10. ソースルーティングの無効化

以下の内容を/etc/sysctl.confに追加する。

net.ipv4.ip_forward=1
net.ipv4.conf.default.send_redirects=0
net.ipv4.conf.default.accept_redirects=0
net.ipv4.conf.all.send_redirects=0
net.ipv4.conf.all.accept_redirects=0
net.ipv6.conf.default.send_redirects=0
net.ipv6.conf.default.accept_redirects=0
net.ipv6.conf.all.send_redirects=0
net.ipv6.conf.all.accept_redirects=0
3.4.3. CA鍵とサーバー鍵とクライアント鍵を作成する

(クライアント鍵は「RSA」を使用しない場合は不要、CA鍵・サーバー鍵は「PSK」のみを使用する場合は不要。)

以下のコマンドを実行すればOKだが、サーバー鍵の作成コマンドの中にあるxxx.xxx.xxx.xxxとなっている2か所はVPSサーバーのIPアドレスに書き換える。

mkdir vpn_certs
ipsec pki --gen > vpn_certs/vpn_CA.key
ipsec pki --self --in vpn_certs/vpn_CA.key --ca --dn "C=JP, O=strongSwan, CN=strongSwanVPN CA" > vpn_certs/vpn_CA.crt
cp vpn_certs/vpn_CA.key /etc/ipsec.d/private/
cp vpn_certs/vpn_CA.crt /etc/ipsec.d/cacerts/
chmod 600 /etc/ipsec.d/private/vpn_CA.key
chmod 600 /etc/ipsec.d/cacerts/vpn_CA.crt
chown root:root /etc/ipsec.d/private/vpn_CA.key
chown root:root /etc/ipsec.d/cacerts/vpn_CA.crt
openssl x509 -inform der -outform pem -in vpn_certs/vpn_CA.crt -out vpn_certs/vpn_CA.pem.crt
ipsec pki --gen > vpn_certs/server.key
ipsec pki --pub --in vpn_certs/server.key | ipsec pki --issue --cacert vpn_certs/vpn_CA.crt --cakey vpn_certs/vpn_CA.key --san @xxx.xxx.xxx.xxx --flag serverAuth --dn "C=JP, O=strongSwan, CN=xxx.xxx.xxx.xxx" > vpn_certs/server.crt
cp vpn_certs/server.key /etc/ipsec.d/private/
cp vpn_certs/server.crt /etc/ipsec.d/certs/
chmod 600 /etc/ipsec.d/private/server.key
chmod 600 /etc/ipsec.d/certs/server.crt
chown root:root /etc/ipsec.d/private/server.key
chown root:root /etc/ipsec.d/certs/server.crt
ipsec pki --gen > vpn_certs/client.key
ipsec pki --pub --in vpn_certs/client.key | ipsec pki --issue --cacert vpn_certs/vpn_CA.crt --cakey vpn_certs/vpn_CA.key --dn "C=JP, O=strongSwan, CN=client" > vpn_certs/client.crt
cp vpn_certs/client.key /etc/ipsec.d/private/
cp vpn_certs/client.crt /etc/ipsec.d/certs/
chmod 600 /etc/ipsec.d/private/client.key
chmod 600 /etc/ipsec.d/certs/client.crt
chown root:root /etc/ipsec.d/private/client.key
chown root:root /etc/ipsec.d/certs/client.crt
openssl x509 -inform der -outform pem -in vpn_certs/client.crt -out vpn_certs/client.pem.crt
openssl rsa -inform der -outform pem -in vpn_certs/client.key -out vpn_certs/client.pem.key
openssl pkcs12 -in vpn_certs/client.pem.crt -inkey vpn_certs/client.pem.key -certfile vpn_certs/vpn_CA.pem.crt -export -out vpn_certs/client.p12

client.p12のパスフレーズは好みのものでOK。
作成後、vpn_CA.crt・server.crt・client.p12をVPNを利用する機器に突っ込んでおく。

この項に関しては、以下のページを参考にさせていただいた。
strongSwanでVPN (IKEv2)を構築する - Qiita

3.4.4.strongSwanのセットアップ

/etc/ipsec.confを以下のように書き換える。
使用しない接続方式に関しては省いて構わない。

config setup
force_keepalive = yes
keep_alive = 10s
nat_traversal=yes
protostack=netkey
virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!192.168.222.0/24
oe=off

conn %default
dpddelay=30
dpdtimeout=120
dpdaction=clear
auto=add
left=%defaultroute
leftsubnet=0.0.0.0/0
right=%any

conn L2TP-PSK
authby=secret
type=transport
leftprotoport=17/1701
rightprotoport=17/%any

conn L2TP-RSA
authby=pubkey
type=transport
leftprotoport=17/1701
rightprotoport=17/%any
leftcert=server.crt
rightcert=client.crt

conn XAuth-PSK
rightsourceip=192.168.201.0/24
leftauth=psk
rightauth=psk
rightauth2=xauth

conn XAuth-Hybrid
rightsourceip=192.168.202.0/24
leftauth=pubkey
leftcert=server.crt
rightauth=xauth

conn Xauth-RSA
authby=xauthrsasig
rightsourceip=192.168.203.0/24
leftauth=pubkey
leftcert=server.crt
rightauth=pubkey
rightcert=client.crt
rightauth2=xauth

conn IKEv2-PSK
keyexchange=ikev2
rightsourceip=192.168.204.0/24
leftauth=pubkey
leftcert=server.crt
rightauth=eap-mschapv2
eap_identity=%any

わかりづらかった設定内容について少し説明すると、

  • oe=off:日和見暗号化の明示的無効化
  • dpd...:接続が切れていると判断するハートビートの送信間隔・タイムアウト時間・切れたときにどのように動作するかを指定している。(dpdaction=clearで接続をクリアすることにしている)
  • forceencaps:NAT-Tの実装が適当なクライアント用に強制的にNAT-Tの通信をする設定。yesだとデフォルトでNAT-Tが無効化されているWindows機から接続できないのでnoにしておく。
  • auto=add:起動時の動作設定。「接続待ちで起動」はadd、「接続しに行く」ならstart
  • rekey=no:トンネルの定期的な張り直しを要求するか否か。ただし、クライアント側からの要求があればyes,noにかかわらず張り直しが行われる。
  • leftprotoport=17/1701:IPプロトコル番号17番(UDP)、ポート番号1701番(L2TP)を指定している。

といった感じ、その他の設定項目は以下を参考にする。
ipsec.conf Reference - IpsecConf - strongSwan
ipsec.conf(5): IPsec config/connections - Linux man page
No Such Blog or Diary - Ubuntu 12.04 LTS で L2TP/IPsec を証明書で
IPsec / XAuth でサクッと VPN サーバを立てる - Qiita
strongSwanでVPN (IKEv2)を構築する - Qiita

3.4.5.ユーザー名・PSK・証明書等を設定する

PSKと「RSA」で使用する証明書、また、「XAUTH」と「IKEv2」で使用するユーザー名とパスフレーズを設定する。

/etc/ipsec.secrets以下のように編集する。

: PSK "{PSK文字列}"
%any : RSA server.key
{ユーザー名} : XAUTH "{パスフレーズ}"
{ユーザー名} : EAP "{パスフレーズ}"

ユーザー名は複数端末で共有してもいいと思うが、同時使用すると問題が出るとも限らないので、複数用意しておいた方が無難。

3.4.6.xl2tpdのセットアップ

L2TP」を使用しない場合は不要。

/etc/xl2tpd/xl2tpd.confを以下のように変更し、

[global]
port = 1701
[lns default]
ip range = 192.168.200.2-192.168.200.200
local ip = 192.168.200.1
length bit = yes
refuse chap = yes
require authentication = yes
name = l2tpd
pppoptfile = /etc/ppp/options.l2tpd.lns

/etc/ppp/options.l2tpd.lnsを以下のように変更する。

name l2tpd
auth
refuse-pap
refuse-chap
refuse-mschap
require-mschap-v2
nodefaultroute
crtscts
lock
ms-dns 8.8.8.8
hide-password
modem
proxyarp
mtu 1280
mru 1280
idle 1800
connect-delay 7500

また、/etc/ppp/chap-secretsを以下のように変更する。

{ユーザー名} l2tpd {パスフレーズ} *

この項は以下のサイトを参考にした。
EZ-NET: CentOS 6.0 で L2TP-VPN サーバを構築する
Man page of PPPD

4.各端末をセットアップ

Androidなら、VPN 設定ガイド - sonymobileなどを参考に、
Windowsなら、在宅勤務を実現するリモート・アクセスVPN構築術:最終回 Windows OSで作るVPNサーバ (6/8) - @ITなどを参考に設定すると良い。

【最後に】

自分でやってみるとVPNサーバー立てるって面倒(´・ω・`)
勉強+試行錯誤が多かった・・・(結局IKEv2-RSAは上手くいかなかったし)

でもまあ、実際に海外で使えたのでOKとしよう(^。^)

SoftEther使えばもっと簡単だったろうが、証明書使えなさそうなので、セキュリティを気にする人は頑張ってstrongSwan使うしかなさげ。

また、もっとセキュリティを気にする人は、SSHのポートを変えたり、別ユーザを追加してrootログインはできないようにしたりすればいいと思う。

なお、この記事からDigitalOceanに登録してもらえると、$10分のクレジットがもらえるそうなので、お得です。
また、使い込んでもらえると、こちらにもキャッシュバックがあり幸せになれます(^。^)