FreeBSDでif_ipsec(4)を使う

policy based VPN

FreeBSDの従来のIPsecの実装では、 setkey(8) でkernel内のセキュリティデータベース(SAD)を操作し、 kernelは送受信するパケットがこのSADに一致する場合は、 SADに従ってパケットの行き先を決めて暗号化の処理を行なっています。

ルーティングテーブルの参照はこれらの処理の後に行われます。つまり、

  • IPsecで通信するパケットはSADで行き先が決まる。
  • それ以外の通常のパケットはルーティングテーブルによって行き先が決まる。

ということになります。FreeBSDハンドブックのIPsecの項目 ( 第14章 セキュリティ | FreeBSD Documentation Portal ) など多くの説明で gif(4) を使ってVPN over IPsecを構築するように書いてあるため、 こうした特徴が分かりにくくなってしまいます。 実際にはgif(4)を設定する必要はありません。

こうやってIPsecを設定して構築したVPNをpolicy-based VPNと言います。

if_ipsec(4)

FreeBSD 11で導入された if_ipsec(4) は、IPsecでroute-based VPNが実現できます。ipsecという仮想的な トンネルインターフェースを作り、そこを通るパケットがIPsecで暗号化されます。 この方法にはいくつかの利点があります。

  • パケット通信の宛先をルーティングテーブルで統一して扱える。
  • 動的ルーティングが使える。
  • SNMPを使ってVPN通信量の統計が取れる。

複数拠点を網目状に結んでIPsecで暗号化された通信を行う場合には、 route-based VPNは便利です。 一つのIPsecトンネルがトラブルで切断されても、動的なルーティングを行なっていれば 他の拠点を経由した通信に自動的に切り替わります。

実際の設定

  • FreeBSDサーバ
    • IPv4: XXX.XXX.XXX.XXX
    • IPv6: XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
    • ローカルIPv4: 192.168.1.1/24
  • 拠点A
    • IPv4: AAA.AAA.AAA.AAA
    • ローカルIPv4: 192.168.11.1/24
  • 拠点B
    • IPv6: BBBB:BBBB:BBBB:BBBB:BBBB:BBBB:BBBB:BBBB
    • ローカルIPv4: 192.168.12.1/24

FreeBSDサーバから拠点Aとの間にover IPv4IPsec VPNを、 拠点Bとの間にover IPv6IPsec VPNを構築することとします。

# ifconfig ipsec0 create reqid 100
# ifconfig ipsec0 inet tunnel XXX.XXX.XXX.XXX AAA.AAA.AAA.AAA
# ifconfig ipsec0 inet 192.168.1.1/24 192.168.11.1

# ifconfig ipsec1 create reqid 200
# ifconfig ipsec1 inet6 tunnel XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX AAAA:AAAA:AAAA:AAAA:AAAA:AAAA:AAAA:AAAA
# ifconfig ipsec1 inet 192.168.1.1/24 192.168.12.1

reqidには0以外の整数を指定します。複数のipsecインターフェースを使う場合は 別の数字を指定してください。対向するルータと同じ数字を指定する必要はありません。

/etc/rc.confには以下のように記述します。

cloned_interfaces="ipsec0 ipsec1"
ifconfig_ipsec0="reqid 100"
ifconfig_ipsec0_alias0="inet tunnel XXX.XXX.XXX.XXX AAA.AAA.AAA.AAA"
ifconfig_ipsec0_alias1="inet 192.168.1.1/24 192.168.11.1"
ifconfig_ipsec1="reqid 200"
ifconfig_ipsec1_ipv6="inet6 tunnel XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX BBBB:BBBB:BBBB:BBBB:BBBB:BBBB:BBBB:BBBB" 
ifconfig_ipsec1_alias0="inet 192.168.1.1/24 192.168.12.1"

if_ipsec(4) のマニュアルではIPsec通信の鍵を setkey(8) で固定した鍵に設定する説明になっていますが、racoonを使って 動的に鍵を交換することにします。

ということで、次回はracoonの設定をします。