StaticRoutingで簡単にsite-to-siteVPN冗長化


# 背景

昨今、VyOSやらVyattaやらで簡単に高機能なルータ的なものにさわれる機会が多くなり、またパブリッククラウドでVPNつないだりなどもあたりまえ（？）の時代になってきました。
しかし、site-to-siteのVPN冗長化って、BGPやらなんやらのDynamicRouting使ったり、VRRPやHSRPなどでゲートウェイの冗長化っぽいことしたり、ネットワークに詳しい方でないとなかなか難しかったり難しくなかったりします。
そこで、VyOSのVTIとStaticRoutingを利用して、お手軽にVPN冗長化をする方法を書いておきます。
今回は、AWSを利用した例でやってみます。
※VyOS 1.1.x は 12/15現在、VTIの不具合がありRoutingされません。下記例をVyOSを使ってやってみる場合は、1.0.5をご利用ください。

# 練習用構成

たとえば、下記のようなAWS上のVPC間をVyOSのIPSecでつないでみます。

* VPC1 10.1.0.0/16
 * Public Subnet
     * AZ-a 10.1.1.0/24
         * VyOS
             * GlobalIP a.a.a.a
             * LocalIP  10.1.1.9
     * AZ-b 10.1.2.0/24
         * VyOS
             * GlobalIP b.b.b.b
             * LocalIP  10.1.2.9
 * Private Subnet
     * AZ-a 10.1.9.0/24
     * AZ-b 10.1.10.0/24

* VPC2 10.2.0.0/16
 * Public Subnet
     * AZ-a 10.2.1.0/24
         * VyOS
             * GlobalIP c.c.c.c
             * LocalIP  10.2.1.9
     * AZ-b 10.2.2.0/24
         * VyOS
             * GlobalIP d.d.d.d
             * LocalIP  10.2.2.9
 * Private Subnet
     * AZ-a 10.2.9.0/24
     * AZ-b 10.2.10.0/24

各VPCのAZごとのPublicSubnetに、VPN Router/NAT InstanceとしてVyOSを置きます。

# VyOSの設定

## WAN(VPN)側の冗長化

共通のConfig

```shell-session:common
# Timezoneはお好きに
set system time-zone 'Asia/Tokyo'

# AWSっぽいIPSecのパラメータ設定
set vpn ipsec esp-group AWSIPSEC compression 'disable'
set vpn ipsec esp-group AWSIPSEC lifetime '3600'
set vpn ipsec esp-group AWSIPSEC mode 'tunnel'
set vpn ipsec esp-group AWSIPSEC pfs 'enable'
set vpn ipsec esp-group AWSIPSEC proposal 1 encryption 'aes128'
set vpn ipsec esp-group AWSIPSEC proposal 1 hash 'sha1'
set vpn ipsec ike-group AWSIPSEC dead-peer-detection action 'restart'
set vpn ipsec ike-group AWSIPSEC dead-peer-detection interval '15'
set vpn ipsec ike-group AWSIPSEC dead-peer-detection timeout '30'
set vpn ipsec ike-group AWSIPSEC lifetime '28800'
set vpn ipsec ike-group AWSIPSEC proposal 1 dh-group '2'
set vpn ipsec ike-group AWSIPSEC proposal 1 encryption 'aes128'
set vpn ipsec ike-group AWSIPSEC proposal 1 hash 'sha1'

# eth0を使ってIPSecします
set vpn ipsec ipsec-interfaces interface 'eth0'

# パケットがアディオスらないようにMSSを
set policy route LANTCPMSS rule 10 destination address '0.0.0.0/0'
set policy route LANTCPMSS rule 10 protocol 'tcp'
set policy route LANTCPMSS rule 10 set tcp-mss '1387'
set policy route LANTCPMSS rule 10 tcp flags 'SYN,!ACK,!FIN,!RST'
set interfaces ethernet eth0 policy route 'LANTCPMSS'

```

各VPCのVyOSごとのConfig

```shell-session:VPC1_AZ-a
# NAT Instanceも兼ねてしまう
set nat source rule 100 outbound-interface 'eth0'
set nat source rule 100 source address '10.1.0.0/16'
set nat source rule 100 destination address '!10.0.0.0/8'
set nat source rule 100 translation address 'masquerade'

# VTIインタフェースの作成
set interfaces vti vti1 description 'VPC tunnel 1 to VPC2 AZ-a'
set interfaces vti vti1 mtu '1436'
set interfaces vti vti2 description 'VPC tunnel 2 to VPC2 AZ-b'
set interfaces vti vti2 mtu '1436'

# IPSecの設定
set vpn ipsec site-to-site peer c.c.c.c authentication id 'a.a.a.a'
set vpn ipsec site-to-site peer c.c.c.c authentication mode 'pre-shared-secret'
set vpn ipsec site-to-site peer c.c.c.c authentication pre-shared-secret 'PreKey12345$$##Pre'
set vpn ipsec site-to-site peer c.c.c.c authentication remote-id 'c.c.c.c'
set vpn ipsec site-to-site peer c.c.c.c connection-type 'initiate'
set vpn ipsec site-to-site peer c.c.c.c description 'VPC tunnel 1 to VPC2 AZ-a'
set vpn ipsec site-to-site peer c.c.c.c ike-group 'AWSIPSEC'
set vpn ipsec site-to-site peer c.c.c.c local-address '10.1.1.9'
set vpn ipsec site-to-site peer c.c.c.c vti bind 'vti1'
set vpn ipsec site-to-site peer c.c.c.c vti esp-group 'AWSIPSEC'

set vpn ipsec site-to-site peer d.d.d.d authentication id 'a.a.a.a'
set vpn ipsec site-to-site peer d.d.d.d authentication mode 'pre-shared-secret'
set vpn ipsec site-to-site peer d.d.d.d authentication pre-shared-secret 'PreKey12345$$##Pre'
set vpn ipsec site-to-site peer d.d.d.d authentication remote-id 'd.d.d.d'
set vpn ipsec site-to-site peer d.d.d.d connection-type 'initiate'
set vpn ipsec site-to-site peer d.d.d.d description 'VPC tunnel 2 to VPC2 AZ-b'
set vpn ipsec site-to-site peer d.d.d.d ike-group 'AWSIPSEC'
set vpn ipsec site-to-site peer d.d.d.d local-address '10.1.1.9'
set vpn ipsec site-to-site peer d.d.d.d vti bind 'vti2'
set vpn ipsec site-to-site peer d.d.d.d vti esp-group 'AWSIPSEC'

# VPC Subnetごとにinterface-routeで設定
set protocols static interface-route 10.2.0.0/16 next-hop-interface vti1 distance '201'
set protocols static interface-route 10.2.1.0/24 next-hop-interface vti1 distance '201'
set protocols static interface-route 10.2.9.0/24 next-hop-interface vti1 distance '201'

set protocols static interface-route 10.2.0.0/16 next-hop-interface vti2 distance '201'
set protocols static interface-route 10.2.2.0/24 next-hop-interface vti2 distance '201'
set protocols static interface-route 10.2.10.0/24 next-hop-interface vti2 distance '201'
```

```shell-session:VPC1_AZ-b
# NAT Instanceも兼ねてしまう
set nat source rule 100 outbound-interface 'eth0'
set nat source rule 100 source address '10.1.0.0/16'
set nat source rule 100 destination address '!10.0.0.0/8'
set nat source rule 100 translation address 'masquerade'

# VTIインタフェースの作成
set interfaces vti vti1 description 'VPC tunnel 1 to VPC2 AZ-a'
set interfaces vti vti1 mtu '1436'
set interfaces vti vti2 description 'VPC tunnel 2 to VPC2 AZ-b'
set interfaces vti vti2 mtu '1436'

# IPSecの設定
set vpn ipsec site-to-site peer c.c.c.c authentication id 'b.b.b.b'
set vpn ipsec site-to-site peer c.c.c.c authentication mode 'pre-shared-secret'
set vpn ipsec site-to-site peer c.c.c.c authentication pre-shared-secret 'PreKey12345$$##Pre'
set vpn ipsec site-to-site peer c.c.c.c authentication remote-id 'c.c.c.c'
set vpn ipsec site-to-site peer c.c.c.c connection-type 'initiate'
set vpn ipsec site-to-site peer c.c.c.c description 'VPC tunnel 1 to VPC2 AZ-a'
set vpn ipsec site-to-site peer c.c.c.c ike-group 'AWSIPSEC'
set vpn ipsec site-to-site peer c.c.c.c local-address '10.1.2.9'
set vpn ipsec site-to-site peer c.c.c.c vti bind 'vti1'
set vpn ipsec site-to-site peer c.c.c.c vti esp-group 'AWSIPSEC'

set vpn ipsec site-to-site peer d.d.d.d authentication id 'b.b.b.b'
set vpn ipsec site-to-site peer d.d.d.d authentication mode 'pre-shared-secret'
set vpn ipsec site-to-site peer d.d.d.d authentication pre-shared-secret 'PreKey12345$$##Pre'
set vpn ipsec site-to-site peer d.d.d.d authentication remote-id 'd.d.d.d'
set vpn ipsec site-to-site peer d.d.d.d connection-type 'initiate'
set vpn ipsec site-to-site peer d.d.d.d description 'VPC tunnel 2 to VPC2 AZ-b'
set vpn ipsec site-to-site peer d.d.d.d ike-group 'AWSIPSEC'
set vpn ipsec site-to-site peer d.d.d.d local-address '10.1.2.9'
set vpn ipsec site-to-site peer d.d.d.d vti bind 'vti2'
set vpn ipsec site-to-site peer d.d.d.d vti esp-group 'AWSIPSEC'

# VPC Subnetごとにinterface-routeで設定
set protocols static interface-route 10.2.0.0/16 next-hop-interface vti1 distance '201'
set protocols static interface-route 10.2.1.0/24 next-hop-interface vti1 distance '201'
set protocols static interface-route 10.2.9.0/24 next-hop-interface vti1 distance '201'

set protocols static interface-route 10.2.0.0/16 next-hop-interface vti2 distance '201'
set protocols static interface-route 10.2.2.0/24 next-hop-interface vti2 distance '201'
set protocols static interface-route 10.2.10.0/24 next-hop-interface vti2 distance '201'
```

```shell-session:VPC2_AZ-a
# NAT Instanceも兼ねてしまう
set nat source rule 100 outbound-interface 'eth0'
set nat source rule 100 source address '10.2.0.0/16'
set nat source rule 100 destination address '!10.0.0.0/8'
set nat source rule 100 translation address 'masquerade'

# VTIインタフェースの作成
set interfaces vti vti1 description 'VPC tunnel 1 to VPC1 AZ-a'
set interfaces vti vti1 mtu '1436'
set interfaces vti vti2 description 'VPC tunnel 2 to VPC1 AZ-b'
set interfaces vti vti2 mtu '1436'

# IPSecの設定
set vpn ipsec site-to-site peer a.a.a.a authentication id 'c.c.c.c'
set vpn ipsec site-to-site peer a.a.a.a authentication mode 'pre-shared-secret'
set vpn ipsec site-to-site peer a.a.a.a authentication pre-shared-secret 'PreKey12345$$##Pre'
set vpn ipsec site-to-site peer a.a.a.a authentication remote-id 'a.a.a.a'
set vpn ipsec site-to-site peer a.a.a.a connection-type 'initiate'
set vpn ipsec site-to-site peer a.a.a.a description 'VPC tunnel 1 to VPC1 AZ-a'
set vpn ipsec site-to-site peer a.a.a.a ike-group 'AWSIPSEC'
set vpn ipsec site-to-site peer a.a.a.a local-address '10.2.1.9'
set vpn ipsec site-to-site peer a.a.a.a vti bind 'vti1'
set vpn ipsec site-to-site peer a.a.a.a vti esp-group 'AWSIPSEC'

set vpn ipsec site-to-site peer b.b.b.b authentication id 'c.c.c.c'
set vpn ipsec site-to-site peer b.b.b.b authentication mode 'pre-shared-secret'
set vpn ipsec site-to-site peer b.b.b.b authentication pre-shared-secret 'PreKey12345$$##Pre'
set vpn ipsec site-to-site peer b.b.b.b authentication remote-id 'b.b.b.b'
set vpn ipsec site-to-site peer b.b.b.b connection-type 'initiate'
set vpn ipsec site-to-site peer b.b.b.b description 'VPC tunnel 2 to VPC1 AZ-b'
set vpn ipsec site-to-site peer b.b.b.b ike-group 'AWSIPSEC'
set vpn ipsec site-to-site peer b.b.b.b local-address '10.2.1.9'
set vpn ipsec site-to-site peer b.b.b.b vti bind 'vti2'
set vpn ipsec site-to-site peer b.b.b.b vti esp-group 'AWSIPSEC'

# VPC Subnetごとにinterface-routeで設定
set protocols static interface-route 10.1.0.0/16 next-hop-interface vti1 distance '201'
set protocols static interface-route 10.1.1.0/24 next-hop-interface vti1 distance '201'
set protocols static interface-route 10.1.9.0/24 next-hop-interface vti1 distance '201'

set protocols static interface-route 10.1.0.0/16 next-hop-interface vti2 distance '201'
set protocols static interface-route 10.1.2.0/24 next-hop-interface vti2 distance '201'
set protocols static interface-route 10.1.10.0/24 next-hop-interface vti2 distance '201'
```

```shell-session:VPC2_AZ-b
# NAT Instanceも兼ねてしまう
set nat source rule 100 outbound-interface 'eth0'
set nat source rule 100 source address '10.2.0.0/16'
set nat source rule 100 destination address '!10.0.0.0/8'
set nat source rule 100 translation address 'masquerade'

# VTIインタフェースの作成
set interfaces vti vti1 description 'VPC tunnel 1 to VPC1 AZ-a'
set interfaces vti vti1 mtu '1436'
set interfaces vti vti2 description 'VPC tunnel 2 to VPC1 AZ-b'
set interfaces vti vti2 mtu '1436'

# IPSecの設定
set vpn ipsec site-to-site peer a.a.a.a authentication id 'd.d.d.d'
set vpn ipsec site-to-site peer a.a.a.a authentication mode 'pre-shared-secret'
set vpn ipsec site-to-site peer a.a.a.a authentication pre-shared-secret 'PreKey12345$$##Pre'
set vpn ipsec site-to-site peer a.a.a.a authentication remote-id 'a.a.a.a'
set vpn ipsec site-to-site peer a.a.a.a connection-type 'initiate'
set vpn ipsec site-to-site peer a.a.a.a description 'VPC tunnel 1 to VPC1 AZ-a'
set vpn ipsec site-to-site peer a.a.a.a ike-group 'AWSIPSEC'
set vpn ipsec site-to-site peer a.a.a.a local-address '10.2.2.9'
set vpn ipsec site-to-site peer a.a.a.a vti bind 'vti1'
set vpn ipsec site-to-site peer a.a.a.a vti esp-group 'AWSIPSEC'

set vpn ipsec site-to-site peer b.b.b.b authentication id 'd.d.d.d'
set vpn ipsec site-to-site peer b.b.b.b authentication mode 'pre-shared-secret'
set vpn ipsec site-to-site peer b.b.b.b authentication pre-shared-secret 'PreKey12345$$##Pre'
set vpn ipsec site-to-site peer b.b.b.b authentication remote-id 'b.b.b.b'
set vpn ipsec site-to-site peer b.b.b.b connection-type 'initiate'
set vpn ipsec site-to-site peer b.b.b.b description 'VPC tunnel 2 to VPC1 AZ-b'
set vpn ipsec site-to-site peer b.b.b.b ike-group 'AWSIPSEC'
set vpn ipsec site-to-site peer b.b.b.b local-address '10.2.2.9'
set vpn ipsec site-to-site peer b.b.b.b vti bind 'vti2'
set vpn ipsec site-to-site peer b.b.b.b vti esp-group 'AWSIPSEC'

# VPC Subnetごとにinterface-routeで設定
set protocols static interface-route 10.1.0.0/16 next-hop-interface vti1 distance '201'
set protocols static interface-route 10.1.1.0/24 next-hop-interface vti1 distance '201'
set protocols static interface-route 10.1.9.0/24 next-hop-interface vti1 distance '201'

set protocols static interface-route 10.1.0.0/16 next-hop-interface vti2 distance '201'
set protocols static interface-route 10.1.2.0/24 next-hop-interface vti2 distance '201'
set protocols static interface-route 10.1.10.0/24 next-hop-interface vti2 distance '201'
```

## LAN側の冗長化設定は？

AWSの場合は、AWS上のRouteTableを設定変更する必要があります。
[High Availability for Amazon VPC NAT Instances: An Example](http://aws.amazon.com/articles/2781451301784570)
こちらのような感じで、各ノード間を死活監視するなり、ちょっと変えてVPNの状態を監視したりして、RouteTableの0.0.0.0/0エントリを書き換えるか、RouteTableのSubnetへのAssociationを変更し、生きている方のVyOSにルートを向けましょう。Auto ScalingやLambdaなどを使ってやるのでもいい感じかと思います。

# 仕組みは？

※絵が全然ないのでわかりづらいかと思いますが・・・
VTIを使って接続しているときにVPNがDownすると、そのVTIを使ったルートも無効になります。
例えば、VPC1_AZ-aからVPC2へは、全てVPNがUPしているときはAZごとにいい感じにルーティングされますが、VPC2_AZ-aのルータとのVPNが切れた場合は、VPC1_AZ-aのvti1がDownし、vti2の10.2.0.0/16のルートが生きてVPC2_AZ-a向けのパケットもvti2に送出されるようになります。

# 多拠点、多クラウド、多環境とつなぐ場合は？

どこかのVyOSをHubにしたり、AWSだとVirtualPrivateGatewayをHubにしたりするのもありかと思いますが、通信制御やレイテンシのことなどが気になる場合は、メッシュでつないで行くのが良いかと思っています。
こんな感じでSerfと組み合わせてフルメッシュでVPN接続するという方法もあるかと思います。
https://github.com/yaggytter/vyos-serf-vpn
現状は、ルーティングが１個しか書けない仕様ですが、複数書けるようにしてますなう中です。

# ソフトウェアルータの可能性

ShellScriptやSerfなどをはじめとして、いわゆる箱のルータ上では動かすことが困難だったものがいろいろ動かせるので、ネットワーク機器にとどまらず、可能性は無限大に感じます。ネットワークの専門家だった人ではない方々でも簡単に素敵な機能にさわれる機会を提供してくれるので、なんか良くわからなくても気軽にさわってみましょう！

以上