VPSでVPNサーバを立てた話

#目的
家などからインターネットアクセスする際の、固定のグローバルIPアドレスが欲しかった。
例えばWebシステムの管理画面にIPアドレス制限をかけて、自分しかアクセスできなくするなどの用途で。
しかしプロバイダの固定IPアドレスオプションのコストが結構高いので、他の用途で契約していたVPSにVPNサーバを立てて、VPSに割り当てられたグローバルIPアドレスを自分の「固定IPアドレス」として使うことにした。

#前提
VPSは以下。

- GMOクラウドVPS
- CentOS 6.8 x86_64
- SELinuxは使わない

典型的なLAMP環境が動いている何の変哲もないVPS。
せっかくだからWindows, Mac, iOS, Androidの各デバイスから接続できるようにしたいので、「L2TP/IPsec PSK」対応とする。

#セットアップ
##epelリポジトリを登録
yumの標準リポジトリに入っていないパッケージを使うので。

```bash
yum install epel-release
```

##SELinuxを無効にする
セキュリティ上望ましくないかとは思うが、参考にしたサイトであらかた無効にしていたのと、何より既にシステムを動かすために無効にしてあったので、このままで行く。

```bash
setenforce 0
```
```text:/etc/selinux/config
:(略)
SELINUX=disabled
:(略)
```

##IPsec, L2TPのパッケージをインストール
IPsecはopenswan、L2TPはxl2tpdで対応することに。

```bash
yum -y --enablerepo=epel install openswan xl2tpd lsof
```

(lsofはあとで設定の確認に必要になるだけで本質ではない)

##xl2tpdの設定

```text:/etc/xl2tpd/xl2tpd.conf
[lns default]
ip range = 192.168.1.128-192.168.1.254
local ip = 192.168.1.99
require chap = yes
refuse pap = yes
require authentication = yes
name = oreorevpnserver
ppp debug = yes
pppoptfile = /etc/ppp/options.xl2tpd
length bit = yes
```

上記設定を追加。
このVPSはグローバルIPアドレスを持つeth0とループバックしか持っていなかったので、ip rangeとlocal ipは適当なローカルアドレスでOK(のはず)。VPSがLANに参加している場合は考慮しないといけない(はず)。

```text:/etc/xl2tpd/xl2tpd.conf
[global]
listen-addr = xxx.xxx.xxx.xxx
```

VPS自身に割り当てられたIPアドレスを上記のように設定する必要がありそうだが、アダプタが一つしかないせいか、特に設定しなくても動いた。

##PPPの設定

```text:/etc/ppp/options.xl2tpd
ipcp-accept-local
ipcp-accept-remote
ms-dns  xxx.xxx.xxx.xxx
ms-dns  xxx.xxx.xxx.yyy
# ms-dns  192.168.1.1
# ms-dns  192.168.1.3
# ms-wins 192.168.1.2
# ms-wins 192.168.1.4
#noccp
auth
crtscts
idle 1800
mtu 1410
mru 1410
nodefaultroute
debug
lock
proxyarp
connect-delay 5000
# To allow authentication against a Windows domain EXAMPLE, and require the
# user to be in a group "VPN Users". Requires the samba-winbind package
# require-mschap-v2
# plugin winbind.so
# ntlm_auth-helper '/usr/bin/ntlm_auth --helper-protocol=ntlm-server-1 --require-membership-of="EXAMPLE\\VPN Users"'
# You need to join the domain on the server, for example using samba:
# http://rootmanager.com/ubuntu-ipsec-l2tp-windows-domain-auth/setting-up-openswan-xl2tpd-with-native-windows-clients-lucid.html
netmask 255.255.255.0
persist
require-mschap-v2
logfile /var/log/xl2tpd.log
```

まるまるコピペ。DNSを設定。Googleさんに頼ることにして`8.8.8.8`とかでもOKらしいけど、VPS用に提供されている2つのDNSサーバのアドレスを指定。
参考サイトによると`#noccp`しないとiOSからの接続に難があるとのこと。
mtu/mruはお好みで。netmaskは先ほどのxl2tpd.confでのip range設定に合わせる。ログファイルの場所もお好み。`touch /var/log/xl2tpd.log`して作っておく。

##openswanの設定

```text:/etc/ipsec.conf
:(略)
include /etc/ipsec.d/*.conf
```
```text:/etc/ipsec.d/l2tp-psk.conf
conn L2TP-PSK-NAT
  rightsubnet=0.0.0.0/0
  forceencaps=yes
  also=L2TP-PSK-noNAT

conn L2TP-PSK-noNAT
  #iOS用の設定
  dpddelay=10
  dpdtimeout=20
  dpdaction=clear
  #iOS用の設定 ここまで
  authby=secret
  pfs=no
  auto=add
  keyingtries=3
  rekey=no
  ikelifetime=8h
  keylife=1h
  type=transport
  left=%defaultroute
  leftprotoport=17/1701
  right=%any
  rightprotoport=17/%any
    ike=3des-sha1,aes-sha1,aes256-sha2_256,aes256-sha2_512
    phase2alg=3des-sha1,aes-sha1,aes256-sha2_256,aes256-sha2_512
    sha2-truncbug=yes
```

このへんは参考サイトからのコピペなので今一つ理解していない。VPN接続してきた端末からのパケットをルーティングする設定なのだと思う。

##PPP接続用のパスワードを設定

```text:/etc/ppp/chap-secrets
# Secrets for authentication using CHAP
# client        server  secret                  IP addresses
"hogehoge" * "passwd" *
:(略)
```

アカウント`hogehoge`をパスワード`passwd`で認証する。平文でアカウント名とパスワードを列挙するだけみたい。なんだかちょっと不安。特にここでのアカウント名とLinuxユーザーは関係ないみたい。

##IPsec用の事前共有鍵を設定

```text:/etc/ipsec.d/default.secrets
: PSK "presharedkey"
```
この1行だけのファイルを作ると、`presharedkey`という事前共有鍵(シークレット)が設定される。ここも思い切り平文なのね。

##ファイアウォール(iptables)に穴を開ける
以下のような設定スクリプトにしてある。

```bash:iptables.sh
#!/bin/bash

/etc/rc.d/init.d/iptables stop

# 設定初期化
iptables -F
iptables -X

# ポリシー設定(デフォルト全拒否)
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

# ループパック通信許可
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# 外への接続を許可
iptables -P OUTPUT ACCEPT

:(略)

# L2TP/IPsec
iptables -A FORWARD -i ppp+ -j ACCEPT
iptables -A FORWARD -o ppp+ -j ACCEPT
iptables -A INPUT -p esp -j ACCEPT
iptables -A INPUT -p udp -m udp --dport 1701 -j ACCEPT
iptables -A INPUT -p udp -m udp --dport 500 -j ACCEPT
iptables -A INPUT -p udp -m udp --dport 4500 -j ACCEPT

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j MASQUERADE

# FWルールセット保存
/etc/rc.d/init.d/iptables save

# FW開始
/etc/rc.d/init.d/iptables start
```

iptablesの設定をカスタマイズしている人はこの手のスクリプトでまとめて設定してると思うけど、`# L2TP/IPSec`のところにまとめた部分が重要。これやらないとVPN接続しても外に出られなかったり外から見えなかったり。

##カーネルパラメータの変更
以下を追記。

```text:/etc/sysctl.conf
:(略)
net.core.xfrm_larval_drop = 1
net.ipv4.ip_forward = 1
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.eth0.send_redirects = 0
net.ipv4.conf.lo.send_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.eth0.accept_redirects = 0
net.ipv4.conf.lo.accept_redirects = 0
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.eth0.rp_filter = 0
net.ipv4.conf.lo.rp_filter = 0
```

eth0とlo以外にもアダプタがあったら、それらについても`send_redirects`と`accept_redirects`と`rp_filter`を`0`にする。

##起動
```bash
/sbin/service xl2tpd start
/sbin/service ipsec start
/sbin/chkconfig xl2tpd on
/sbin/chkconfig ipsec on

/sbin/sysctl -p
```

##IPsecの確認

```bash
ipsec verify
```

これで何か怒られたら設定が間違ってる。

#接続
今時のOSは大体「L2TP/IPsec PSK」でVPN接続できるようだ。RSA SecurIDとかL2TPセキュリティ保護とかIPSec IDなどといったオプションは設定不要だが、Androidで接続するときにDNSサーバーを設定しないと上手くいかないことがあった。

#参考サイト

- [L2TP/IPsec（AndroidやiPhoneからのVPN接続）を経路を用意すべくVPSにL2TP/IPsecサーバを設置するとき、ネットにある情報だとなかなかつながらないから、標準環境としてAWSのCentOS 6.3 x86_64 Release Media(ami-3fe8603e)の起動直後から最短距離で設定する方法をまとめた。 · GitHub] (https://gist.github.com/CLCL/5742738)
- [EZ-NET： CentOS 6.0 で L2TP-VPN サーバを構築する]
 (http://network.station.ez-net.jp/server/remote/Linux/l2tp.asp)
- [linuxでVPNサーバ - Qiita]
 (http://qiita.com/mell3210/items/2fa2c9b616e4a2c685af)