IPsecによるVPNのセキュアな接続(サーバー編)

はじめに

VPNの接続にはOpenVPNやL2TPなどいろいろな方法がありますが、なかでもIPsecを使った接続はよりセキュアなだけではなく設定に柔軟性があるので、いったん設定できれば応用が利きます。サーバのレンタルVPSとの接続に自宅からだけでなく、外出先からWi-Fiを使った接続、さらにスマートフォンからの接続とあらゆる機器から接続を考えたらIPsecは最もよい選択になります。IPsecには大きく分けてIKEv1とIKEv2あり、ここではよりセキュアなIKEv2を使って設定を進めていきます。VPSのOSはDebian stretch(Debian 9)を使っています。Debian jessieでも設定は同じです。IPsecのアプリケーションはstrongSwanを使用しています。

サーバにaptでパッケージをインストールします。

sudo apt install strongswan strongswan-charon strongswan-ikev2 \
           libstrongswan-extra-plugins libstrongswan-standard-plugins libcharon-extra-plugins

サーバのCA証明書及びServer証明書の作成します。

作成する場所は自分のPCとして進めていきます。

mkdir ~/ipsec
cd ~/ipsec

CA証明書の作成は次のようにスクリプトを作成します。

#!/bin/sh 
 
mkdir -p private cacerts 
openssl genrsa -out private/caKey.pem 4096 
chmod 600 private/caKey.pem 
ipsec pki --self --ca --lifetime 3650 \ 
 --in private/caKey.pem --type rsa \ 
 --dn "C=JP, O=MyDomain, CN=My Root CA" \ 
 --digest sha256 \ 
 --outform pem \ 
 > cacerts/caCert.pem

Server鍵および証明書の作成は次のようにスクリプトを作成します。–san xxxxx… とFQDNにしておきます。

#!/bin/sh 
 
mkdir -p private certs 
 
openssl genrsa -out private/ServerKey.pem 2048 
chmod 600 private/ServerKey.pem 
ipsec pki --pub --in private/ServerKey.pem --type rsa  | \ 
 ipsec pki --issue --lifetime 1095 \ 
 --cacert cacerts/caCert.pem \ 
 --cakey private/caKey.pem \ 
 --dn "C=JP, O=MyDomain, CN=xxxxxxxxx.vps.xxxxxx.jp" \ 
 --san xxxxxxxxx.vps.xxxxxx.jp \ 
 --digest sha256 \ 
 --flag serverAuth --flag ikeIntermediate \ 
 --outform pem > certs/ServerCert.pem

Client鍵および証明書の作成は次のようにスクリプトを作成します。クライアントの方も同様に’–san’をFQDNに設定します。またconnによって使い分けするので’–dn’の’CN=’をname@FQDN名とします。

注)ipsecよりopensslのほうが精度よい鍵が作れます

#!/bin/sh 
 
#id=1
NAME=MyLinux
 
CLIENTKEY="ClientKey.pem" 
CLIENTCERT="ClientCert.pem" 
CLIENTCN="${NAME}@xxxx.xxxddns.jp" 
 
#ipsec pki --gen --type rsa --size 2048 --outform pem > $CLIENTKEY 
 
openssl genrsa -out $CLIENTKEY 2048 
 
ipsec pki --pub --in $CLIENTKEY --type rsa | \ 
 ipsec pki --issue --lifetime 1095 \ 
 --cacert cacerts/caCert.pem \ 
 --cakey private/caKey.pem \ 
 --dn "C=JP, O=MyDomain, CN=${CLIENTCN}" \ 
 --san ${CLIENTCN} \ 
 --digest sha256 \ 
 --outform pem > $CLIENTCERT 
 
openssl pkcs12 -export -inkey $CLIENTKEY \ 
 -in $CLIENTCERT -name "My VPN Certificate" \ 
 -certfile cacerts/caCert.pem \ 
 -caname "My Root CA" \ 
 -out ${CLIENTCERT%.pem}.p12

リボーケーションリストの作成は次のようにスクリプトを作成します。

#!/bin/sh 
 
user=<Client証明書>.pem

ipsec pki --signcrl --cacert cacerts/caCert.pem \ 
 --cakey private/caKey.pem \ 
 --reason superseded \ 
 --cert $user \ 
 --outform pem \ 
 > crl.pem

これらのスクリプトのパーミッションと所有者を変更します。

sudo chown root:root *.sh
sudo chmod 755 *sh
sudo ./mk-ca.sh
sudo ./mk-server-key.sh
sudo chown root:root cacerts/* certs/* private/*
sudo chmod 600 /etc/ipsec.d/private/*

証明書を作成したらCAの内容を調べます。方法は次の2通りあります。

1) ipsec pki --print --in /etc/ipsec.d/certs/xxxxCert.pem
2) openssl x509 -in /etc/ipsec.d/certs/xxxxCert.pem -text -noout

scp等でサーバにコピーしてサーバーの設定ファイルにインストールします。

sudo rm /etc/ipsec.d/cacerts/* /etc/ipsec.d/certs/* /etc/ipsec.d/private/*
sudo cp -a cacerts certs private /etc/ipsec.d

IPsecの設定

次の設定は各々のデバイスに対応した設定例です。

/etc/ipsec.conf:

config setup 
 plutostart=no

conn %default 
 ikelifetime=60m 
 keylife=20m 
 rekeymargin=3m 
 keyingtries=1 
 keyexchange=ikev2

conn common 
 # left=%any 
 leftcert=ServerCert.pem 
 leftsourceip=%config 
 leftid=xxxxxxxxxx.vps.xxxxxx.jp 
 leftauth=pubkey 
 leftfirewall=yes

# Site to Site: Router and VPS 
conn home-router 
 left=xxxxxxxxxxx.vps.xxxxxx.jp 
 leftsubnet=xx.xx.xx.254/32 
 right=xxxxxx.xxxddns.jp 
 rightid="C=JP, O=MyDomain, CN=xxxxx@xxxxxx.xxxdns.jp --san=xxxxx@xxxxxx.xxxdns.jp" 
 rightid2=xxxxx@xxxxxx.xxxdns.jp 
 rightsubnet=192.168.1.0/27 
 rightauth=pubkey 
 #rightallowany=yes 
 ike=aes128-sha256-modp2048 
 esp=aes128-sha256-modp2048 
 also=common  
 #auto=route 
 auto=add

# IKEv2 Certificate for Linux and Android
conn vpn-client-linux-android 
 left=%defaultroute 
 leftsubnet=0.0.0.0/0
 right=%any
 rightid2=*linux@xxxxxx.xxxdns.jp
 rightauth=pubkey 
 rightallowany=yes
 rightsourceip=192.168.200.0/24
 dpdaction=clear
 dpddelay=300s
 rekey=no
 reauth=no
 fragmentation=yes
 eap_indentity=%any
 ike=aes256-sha384-modp2048,aes256-sha256-modp2048
 esp=aes256-sha384-modp2048,aes256-sha256-modp2048
 also=common
 auto=add

# EAP-MSCHAPv2 for Windows and macOS 
conn vpn-client-windows-macos 
 left=%defaultroute 
 leftsubnet=0.0.0.0/0 
 leftsendcert=always 
 right=%any 
 rightid2=*@xxxxxx.xxxdns.jp 
 rightsourceip=192.168.200.0/24 
 rightauth=eap-mschapv2 
 ike=aes256-sha1-modp1024,aes128-sha1-modp1024,3des-sha1-modp1024! 
 esp=aes256-sha256,aes256-sha1,3des-sha1! 
 dpdaction=clear 
 dpddelay=300s 
 rekey=no 
 reauth=no 
 fragmentation=yes 
 eap_indentity=%any 
 rightdns=8.8.8.8 
 also=common 
 auto=add

秘密鍵はLinuxではRSAのみ、WindowsとmacOSではRSA+EAPになります。

/etc/ipsec.secrets:

: RSA serverKey.pem 
user : EAP "pass"

include /var/lib/strongswan/ipsec.secrets.inc

Note:ユーザー、パスワードは環境にあわせて変更します。

/etc/strongswan.conf:

charon { 
    load_modular = yes 
    plugins { 
      include strongswan.d/charon/*.conf 
   } 
    dns1 = 8.8.8.8
    dns2 = 8.8.4.4
    threads = 16 
}

libstrongswan { 
    crypto_test { 
    on_add = yes 
    } 
}
include strongswan.d/*.conf

ipsecの属性をIPヘッダに追加するとmtu値が大きくなるため変更します。

/etc/strongswan.d/charon/kernel-netlink.conf:

mtu = 1352

Shorewall(firewall)の設定

ファイヤーウォールの設定はEAPプロトコルを通すことと500と4500ポートを開けることです。Shorewallをつかう場合の設定です。

interfaces:
eth0しかないので変更しません。

hosts:
manの説明によると一つインターフェースしかないときzoneで設定するために定義するファイルなので次のようにしました。

#ZONE       HOST(S) OPTIONS 
vpn eth0:0.0.0.0/0

zone:
これはShorewallには必須なので登録します。そのままドキュメントからコピーします。

#ZONE TYPE OPTIONS IN OUT 
# OPTIONS OPTIONS
vpn ipsec mode=tunnel

policy:
ファイヤウォールからvpnにアクセスできるようにする設定です。

#SOURCE DEST POLICY LOG LEVEL LIMIT:BURST
$FW vpn ACCEPT

rules:
ipsecのポートを開けます。

#ACTION SOURCE DEST PROTO DEST SOURCE 
#ACCEPT net $FW ah 
ACCEPT net $FW esp 
ACCEPT net $FW udp 500 
ACCEPT net $FW udp 4500

tunnels:
zoneと対応しておく必要があるので設定します。

#TYPE ZONE GATEWAY(S) GATEWAY 
ipsec net 0.0.0.0/0 vpn

start:

Shorewallのシステムで対応できない設定はstartで設定します。

iptables -I INPUT -m policy --dir in --pol ipsec --proto esp -j ACCEPT 
iptables -I FORWARD -m policy --dir in --pol ipsec --proto esp -j ACCEPT 
iptables -I FORWARD -m policy --dir out --pol ipsec --proto esp -j ACCEPT 
iptables -I OUTPUT -m policy --dir out --pol ipsec --proto esp -j ACCEPT
iptables -t nat -I POSTROUTING -m policy --pol ipsec --dir out -j ACCEPT
iptables -t nat -A POSTROUTING -s 192.168.200.0/24 -o eth0 -m policy --dir out --pol ipsec -j ACCEPT 
iptables -t nat -A POSTROUTING -s 192.168.200.0/24 -o eth0 -j MASQUERADE

以上で、サーバ側の設定は完了です。

References: