Linux サーバ間 IPsec 接続 (strongswan)

Linux サーバ同士の間で通常の IPsec を接続してみる。IPsec 実装として strongswan と libreswan のどちらを使うかは好みによるが、この項では strongswan を利用する。libreswan古い openswan を使ったやり方は別記事にて。

I. 前提

環境は以下の通り。

vpn1、vpn2、host1、host2、router1 OSは全てUbuntu 18.04である。

vpn1←→vpn2の間で、strongswanでトンネルモードIPsec接続をする。10.0.1.0/24 から 10.0.2.0/24 へのパケット、またその逆方向のパケットはトンネルへ入るようにする。つまり、例えばhost1からhost2へpingを打つとトンネルを通ることになる。10.0.1.0/24や10.0.2.0/24へのスタティックルートはrouter1に追加しないようにしておくので、VPNトンネルが出来なければhost1からhost2へのpingは到達できない。

vpn2側に自動接続開始の設定を入れることで、VPNトンネルを自動的に張ることにする。

II. 設定

以下、設定を記述する(IPアドレス設定など基本的なところは省略)

1. router1 の設定:

通過パケットを転送できるように、カーネルパラメータを変更する。
user@router1:~$ sudo vi /etc/sysctl.conf

net.ipv4.ip_forward=1  #28行目のコメントを外す

上記カーネルパラメータを有効化する。
user@router1:~$ sudo sysctl -p /etc/sysctl.conf

2. vpn1の設定:

strongswan をインストールする。このネットワーク構成ではインターネットからの apt install 不可なので、インターネット接続可能なネットワークに一時的に接続しておく。
user@vpn1:~$ sudo apt install strongswan

インストールが終わったら、ネットワーク構成を検証用の構成に戻す。以下のように netplan 設定ファイルを編集する。
user@vpn1:~$ vi /etc/netplan/50-cloud-init.yaml

network:
    version: 2
    ethernets:
        ens160:
            addresses: [198.51.100.100/24]
            gateway4: 198.51.100.1
        ens192:
            addresses: [10.0.1.1/24]

編集したら適用する。
user@vpn1:~$ sudo netplan apply

カーネルパラメータを設定する。
user@vpn1:~$ sudo vi /etc/sysctl.conf

net.ipv4.ip_forward=1  #28行目のコメントを外す

上記カーネルパラメータを有効化する。
user@vpn1:~$ sudo sysctl -p /etc/sysctl.conf

IPsecの事前共有鍵を設定する。
user@vpn1:~$ sudo vi /etc/ipsec.secrets

# 以下の行を追記
: PSK "mypresharedkey"

IPsecの接続設定を記述する。ファイルの最後あたりに追記する形にする。
user@vpn1:~$ sudo vi /etc/ipsec.conf

conn linux-to-linux
        authby=secret		# 共有鍵認証とする
        auto=add		# こちら側からはVPN接続を自動開始しない
        closeaction=clear
        dpdaction=clear
        left=198.51.100.100	# 自ホストのIPアドレス
        leftsubnet=10.0.1.0/24	# 自分側のプライベートネットワーク
        right=203.0.113.100	# 対向側ホストのIPアドレス
        rightsubnet=10.0.2.0/24	# 対向側のプライベートネットワーク

デーモンを再起動する。
user@vpn1:~$ sudo systemctl restart strongswan

3. vpn2 の設定:

vpn1 と同様に、strongswan をインストールする。検証構成ではインターネットからの apt install 不可なのも vpn1 と同様である。一時的にインターネット接続可能なネットワークに接続しておく。
user@vpn2:~$ sudo apt install strongswan

インストールが終わったら、ネットワーク構成を検証用の構成に戻す。
user@vpn2:~$ vi /etc/netplan/50-cloud-init.yaml

network:
    version: 2
    ethernets:
        ens160:
            addresses: [203.0.113.100/24]
            gateway4: 203.0.113.1
        ens192:
            addresses: [10.0.2.1/24]

編集したら適用する。
user@vpn2:~$ sudo netplan apply

カーネルパラメータを設定する。
user@vpn2:~$ sudo vi /etc/sysctl.conf

net.ipv4.ip_forward=1  #28行目のコメントを外す

上記カーネルパラメータを有効化する。
user@vpn2:~$ sudo sysctl -p /etc/sysctl.conf

IPsec 事前共有鍵を設定する。
user@vpn2:~$ sudo vi /etc/ipsec.secrets

# 以下の行を追記
: PSK "mypresharedkey"

IPsecの設定を記述する。right/leftをvpn1側とは入れ換える。
user@vpn2:~$ sudo vi /etc/ipsec.conf

conn linux-to-linux
        authby=secret
        auto=start		# こちら側からVPN接続を自動開始する
        closeaction=restart
        dpdaction=restart
        left=203.0.113.100
        leftsubnet=10.0.2.0/24
        right=198.51.100.100
        rightsubnet=10.0.1.0/24

デーモンを再起動する。
user@vpn2:~$ sudo systemctl restart strongswan

これで完成。

III. 確認

ipsec statusコマンドで、接続状況を確認できる。

user@vpn1:~$ sudo ipsec status
Security Associations (1 up, 0 connecting):
linux-to-linux[1]: ESTABLISHED 7 minutes ago, 198.51.100.100[198.51.100.100]...203.0.113.100[203.0.113.100]
linux-to-linux{1}: INSTALLED, TUNNEL, reqid 1, ESP SPIs: c90fad30_i c17db9d8_o
linux-to-linux{1}: 10.0.1.0/24 === 10.0.2.0/24

router1でtcpdumpを仕掛けておき、host1からhost2あてにpingを打ってみる。
user@host1:~$ ping 10.0.2.100
user@router1:~$ sudo tcpdump -n -i ens192 not tcp port 22
15:15:46.146244 IP 198.51.100.100 > 203.0.113.100: ESP(spi=0xc17db9d8,seq=0x1d), length 136
15:15:46.146569 IP 203.0.113.100 > 198.51.100.100: ESP(spi=0xc90fad30,seq=0xd), length 136
15:15:47.169558 IP 198.51.100.100 > 203.0.113.100: ESP(spi=0xc17db9d8,seq=0x1e), length 136
15:15:47.170081 IP 203.0.113.100 > 198.51.100.100: ESP(spi=0xc90fad30,seq=0xe), length 136

ESPにカプセル化されてパケットが通過していることが確認できた。

※パケットがトンネルに入るか入らないかは、IP ルーティングではなく xfrm ポリシーによって決まっている。
ip xfrm policy コマンドで確認できる。

user@vpn1:~$ sudo ip xfrm policy
src 10.0.1.0/24 dst 10.0.2.0/24
        dir out priority 375423
        tmpl src 198.51.100.100 dst 203.0.113.100
                proto esp spi 0xc17db9d8 reqid 1 mode tunnel
src 10.0.2.0/24 dst 10.0.1.0/24
        dir fwd priority 375423
        tmpl src 203.0.113.100 dst 198.51.100.100
                proto esp reqid 1 mode tunnel
src 10.0.2.0/24 dst 10.0.1.0/24
        dir in priority 375423
        tmpl src 203.0.113.100 dst 198.51.100.100
                proto esp reqid 1 mode tunnel
(snip)