亚马逊AWS官方博客

DirectConnect 与 VPN 主备高可用组网

1. 方案背景与方案设计

客户初期上云过程中为了确保通信安全性兼顾成本原因,通常会采用IPSec隧道(VPN)满足需求,随着业务发展对网络稳定性要求提高,开始建设专线。可参考AWS专线高弹性方案通过双专线提供高可用及冗余,链接 https://docs.aws.amazon.com/zh_cn/directconnect/latest/UserGuide/high_resiliency.html

本文将介绍在单专线情况下,利用已有VPN形成高弹性架构的可选方案,并介绍亚马逊云科技一个客户的高可用架构和具体步骤。

2.可选的VPN加专线架构

共有三种可选架构,三种架构专线均接入Transit Gateway,区别在于VPN的实现方式。

架构1  Transit Gateway(TGW)一体化接入架构

架构利用TGW作为统一接入点,并结合BGP协议,实现云端的主备线路自动切换。

方案参见链接 https://docs.aws.amazon.com/whitepapers/latest/hybrid-connectivity/vpn-connection-as-a-backup-to-aws-dx-connection-example.html

架构2 Transit Gateway Connect+ VPN设备架构

部分客户为了方便统一管理,在云端及本地采用相同第三方厂商的网络设备,构建VPN隧道。此架构中,需要新建专用VPC,并在云端第三方厂商设备与TGW间构建GRE隧道,利用BGP协议,可以实现主备线路自动切换。注TGW connect有支持的第三方厂商列表。

方案参见链接 https://aws.amazon.com/blogs/networking-and-content-delivery/simplify-sd-wan-connectivity-with-aws-transit-gateway-connect/

兼容厂商列表:https://aws.amazon.com/transit-gateway/partners/

路由优先级说明参见链接 https://docs.aws.amazon.com/vpc/latest/tgw/how-transit-gateways-work.html   参见Route evaluation order一节。

架构3 Transit Gateway + 开源/其他VPN设备架构

多数客户初始采用开源软件构建VPN,并且采用静态路由简化管理和配置,架构3中采用独立VPC部署VPN,方便未来云端多VPC扩展以及统一管理主备链路切换。此种架构与专线之间实现主备链路自动切换存在一定困难,要么需要对VPN路由协议进行改造并增加一条云端VPN到TGW的隧道,实现类似TGW Connect功能;要么利用主机或Lambda的监控脚本,根据探测结果,实现主备链路的自动切换。

架构对比与选择

方案 优点 缺点
Transit Gateway 一体化接入 实施简单 北京和宁夏区域不支持
Transit Gateway Connect + VPN 通过端到端BGP,自动切换路由 VPN兼容设备有要求
Transit Gateway + 开源VPN

成本低

复用主机节点或Lambda作为监控
无需修改原有VPN配置

需要开发脚本并进行调试

本文将主要介绍我的客户利用架构3结合监控切换脚本实现主备链路自动切换,客户专线采用BGP路由协议,VPN采用静态路由协议。客户因使用习惯,要求通过在主机层面使用脚本而非Lambda实现。

3. 脚本检测方案设计说明

  1. 检测脚本部署在云上主机,使用ping作为健康检测机制,连续10个失败数据包作为切换条件;
  2. 选用专线两端路由器的地址作为云端和本地健康检测目标端
  3. 创建Managed prefix list,包含所有需要通信的本地IP地址段(3.0.0/18);
  4. 默认使用专线通信,当满足切换条件后,检测脚本自动切换TGW路由,添加Managed prefix list路由指向VPN VPC attatchment。当专线恢复后,检测脚本自动切回专线,在TGW路由删除Managed prefilx list路由。
  5. 客户机房侧,客户利用第三方防火墙实现机房到云上的链路检测设计,根据检测的结果进行VPN与专线的路由切换。

4.脚本检测实施步骤

实施前提条件:VPN,专线分别已经部署成功,并且点对点路由测试通过,生产VPC已经切换为Direct Connect专线。

1、EC2主机(10.0.0.7)安装aws cli,确认automatic recovery已启用。

2、给EC2主机(10.0.0.7)绑定IAM Role,授权EC2允许修改TGW的prefix路由

1)创建IAM 策略 TGW_prefix_policy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ec2:CreateTransitGatewayRoutePrefixListReference",
                "ec2:DeleteTransitGatewayRoutePrefixListReference"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

2)创建IAM角色 EC2_TGW_Prefix_Role,绑定新建的策略 TGW_prefix_policy

3)在EC2上绑定新建的角色EC2_TGW_Prefix_Role

3、路由设置

1)检查生产VPC(10.0.0.0/18)的子网路由中,目的地是客户机房IP地址段(10.3.0.0/18),下一跳路由指向Transit Gateway

2)VPC中设置 Managed prefix list, VPC->Managed prefix lists -> Create prefix list ,设置客户机房的IP地址段(10.3.0.0/18)。


再新建一个测试的managed prefix list,用于调试验证,prefix的IP地址设置一个不使用的IP地址段,例如173.0.0.5/32


3)Transit Gateway设置一条32位掩码的点对点静态路由,目的地是Ping检测的客户机房的IP(10.109.2.1),下一跳指向DirectConnectGateway。配置位置VPC->Transit Gateway route tables -> [transitGateway的ID] -> Create static route

Attachment选择DirectConnectGateway

4)VPN所在的VPC(10.1.0.0/18),目的地是客户机房IP地址段(10.3.0.0/18),下一跳路由指向VPN(10.1.0.5所在主机的ENI)。目的地是生产VPC的IP地址段(10.0.0.0/18),下一跳路由指向Transit Gateway。默认路由走公网,目的地地址是全0,指向IGW。

5)客户机房的Fortinet切换和路由设置,由客户机房的IT工程是配置完成。

4、维护脚本

1)脚本三个shell脚本组成。

a、监控切换脚本HAmonitor.sh,可以灵活设置目标测的IP地址,Ping的累积失败的个数,Ping的检测周期等。脚本内容如下:

#!/bin/bash

dxTargetIP=127.0.0.1
tgwRT=tgw-rtb-0d86bcd71877f6d88
idcPrId=pl-0d81338f99b4770b6
vpnAttId=tgw-attach-0f21402e36c7c65ed
period=1
failCount=10
connectionStatus=0
dxFail=0
dxFailCount=0
pingTimeout=1

switchTGWRouteTableToVPN(){
    echo "add vpn prefix preference in tgw route table "
/usr/bin/aws ec2 create-transit-gateway-prefix-list-reference  \
--transit-gateway-route-table-id  $tgwRT \
--prefix-list-id  $idcPrId \
--transit-gateway-attachment-id $vpnAttId
}

switchTGWRouteTableToDx(){
    echo "delete vpn prefix preference in tgw route table"
/usr/bin/aws ec2 delete-transit-gateway-prefix-list-reference  \
--transit-gateway-route-table-id $tgwRT \
--prefix-list-id=$idcPrId
}

echo "default we use dx when this script begin, this is reset to default"
connectionStatus=0
switchTGWRouteTableToDx

while :; do
#dx monitoring
if ping -c 1 -w $pingTimeout $dxTargetIP &> /dev/null
then
echo "dx test success"
if [ $dxFailCount -lt 2 ]
then
dxFailCount=0
dxFail=0
else
dxFailCount=$[$dxFailCount-1]
fi
else
echo "dx ping test fail "
dxFailCount=$[$dxFailCount+1]
fi

#dx status set
if [ $dxFailCount -gt $failCount ]
then
echo  "dx status is  fail "
dxFailCount=$[$failCount+1]
dxFail=1
fi

if [ $connectionStatus -eq 0 ]
then
echo "dxFail = $dxFail"
if [ $dxFail -eq 1 ]
then
echo "trigger switch from dx to vpn a"
connectionStatus=0
switchTGWRouteTableToVPN
echo "trigger switch from dx to vpn b"
fi
# $connectionStatus=1 so route is vpn
elif [ $connectionStatus -eq 1 ]
then
if [ $dxFail -eq 0 ]
then
echo "trigger switch from vpn to dx a"
connectionStatus=0
switchTGWRouteTableToDx
echo "trigger switch from vpn to dx b"
fi
fi
sleep $period
done

b、守护脚本HAwatch.sh,当发现检测脚本异常退出之后,会重新启动检测。脚本内容如下:

#! /bin/sh

#nohup /home/ec2-user/monitor/HAwatcher.sh > /home/ec2-user/monitor/log/HAwatcher`date '+%Y%m%d%H%M'`.log 2>&1 &
#进程名字可修改
PRO_NAME=HAmonitor.sh
basePath=/home/ec2-user/monitor
chmod +x ${basePath}/HAmonitor.sh
#find /home/ec2-user/monitor/log/ -mmin +120 -name "*.log" -exec rm -rf {} \;
find ${basePath}/log/ -mtime +4 -name "*.log" -exec rm -rf {} \;
while true ; do
     #用ps获取$PRO_NAME进程数量
     NUM=`ps aux | grep -w ${PRO_NAME} | grep -v grep |wc -l`
     #echo $NUM
     #少于1,重启进程
     if [ "${NUM}" -lt "1" ];then
         echo "${PRO_NAME} was killed"
         LogNameDATE=`date '+%Y%m%d%H%M'`
         nohup ${basePath}/${PRO_NAME} > ${basePath}/log/${PRO_NAME}${LogNameDATE}.log 2>&1 &
    #大于1,杀掉所有进程,重启
    elif [ "${NUM}" -gt "1" ];then
        echo "more than 1 ${PRO_NAME},killall ${PRO_NAME}"
         killall -9 -I $PRO_NAME
        ${PRO_NAME} -d
     fi
     #kill僵尸进程
     NUM_STAT=`ps aux | grep -w ${PRO_NAME} | grep T | grep -v grep | wc -l`
     if [ "${NUM_STAT}" -gt "0" ];then
         echo "kill zombie ${PRO_NAME}"
         killall -9 -I ${PRO_NAME}
         ${PRO_NAME} -d
     fi
     sleep 5s
 done
 exit 0

c、Cron脚本HAcron.sh, 利用CronJob来做二次保护,默认每周一早晨8点运行一次,清理日志,重置状态。脚本会固定清除4天前的日志,在HAwatch.sh中,可以根据需要调整。脚本内容如下:

#! /bin/sh

basePath=/home/ec2-user/monitor
PRO_NAME=HAwatch.sh
PRO_NAME2=HAmonitor.sh

# 每周重启一次
killall -9 -I $PRO_NAME
killall -9 -I $PRO_NAME2
while true ; do
     #用ps获取$PRO_NAME进程数量
     NUM=`ps aux | grep -w ${PRO_NAME} | grep -v grep |wc -l`
     #echo $NUM
     #少于1,重启进程
     if [ "${NUM}" -lt "1" ];then
         echo "${PRO_NAME} was killed"
         LogNameDATE=`date '+%Y%m%d%H%M'`
         echo "$LogNameDATE restart ${PRO_NAME}  ${PRO_NAME}"
         nohup ${basePath}/${PRO_NAME} > ${basePath}/log/${PRO_NAME}${LogNameDATE}.log 2>&1 &
         break
    #大于1,杀掉所有进程,重启
    elif [ "${NUM}" -gt "1" ];then
        echo "more than 1 ${PRO_NAME},killall ${PRO_NAME}"
         killall -9 $PRO_NAME
        ${PRO_NAME} -d
     fi
     #kill僵尸进程
     NUM_STAT=`ps aux | grep -w ${PRO_NAME} | grep T | grep -v grep | wc -l`
     if [ "${NUM_STAT}" -gt "0" ];then
         killall -9 ${PRO_NAME}
         ${PRO_NAME} -d
    fi
 done

 exit 0

2)将三个脚本放入monitor目录,放入/home/ec2-user/monitor/, 注意如果放在别的目录,需要修改脚本中的路径。

3)添加脚本的执行权限

chmod +x HAcron.sh
chmod +x HAwatch.sh
chmod +x HAmonitor.sh
mkdir log

4)修改HAmonitor.sh脚本中和环境相关的关键字段,包括以下字段

注意先把testTemp的PrefixID填入到脚本中,先用于调试,避免调试时影响生产环境的业务。

#用于检测的,客户机房IP地址
dxTargetIP=10.109.2.1
#transitGateway的路由表
tgwRT=tgw-rtb-0d86*****77f6d88
#添加的客户机房的Managed Prefix List
idcPrId=pl-0d813*****4770b6
#transitGateway上VPN的VPC的Attachment
vpnAttId=tgw-attach-0f21*****6c7c65ed

注意

脚本默认路径为 /home/user2

5、部署脚本

执行Crontab命令,添加Cron表达式

crontab -e -u root
#添加如下内容
10 8 * * 1 /bin/bash /home/ec2-user/monitor/HAcron.sh > /home/ec2-user/monitor/log/HAcron`date '+\%Y\%m\%d\%H\%M'`.log 2>&1 &

重启Crond服务

sudo service crond restart

查看日志

/home/ec2-user/monitor/log

6、脚本部署完成之后,对修改参数后的脚本进行备份,并对EC2进行SnapShot备份

7、调试测试:脚本此时使用的是临时的模拟的ManagedPrefixList(ManagedPrefixList 包含不影响生产的IP地址端,例如173.0.0.0/18),使用它做测试。验证当专线正常时,TransitGateway 上的prefix路由是没有的。手工修改10.0.0.5的安全组,出方向禁止Ping后,专线ping检测失败,这时会发生切换,观察TransitGateway上的prefix路由,如果成功创建出prefix路由,则测试成功。

8、正式测试,修改HAmonitor.sh中prefixID为机房IDC(10.3.0.0/18地址段的Prefix),kill HAmonitor.sh的进程,HAwatch.sh守护程序会自动拉起新的HAmonitor.sh,之后与业务预约时间,进行生产环境的故障转移测试。

生产测试,可以测两个用例。

第一个测试,手工在AWS上的directConnect界面上虚接口上触发test,将BGP down掉,观察切换效果。触发操作参考链接 https://docs.aws.amazon.com/directconnect/latest/UserGuide/resiliency_failover.html

效果检查

1)查看HAMonitor.sh日志,观察切换日志。

2)在TransitGateway上观察到,Prefix Reference路由正常加上

3) 观察Ping的Trace Route查看走了VPN。BGPUp后,专线切换回到专线上。

第二个测试,将IDC的router(10.109.2.1)路由器端口Down掉做测试,一样会正常切换。

方案总结

该方案通过切换脚本实现专线和VPN的切换方案,是一个成本低廉且架构简单的方案。

本篇作者

王跃

亚马逊云科技解决方案架构师,负责基于亚马逊云科技云平台的解决方案咨询和设计,在系统架构、大数据、网络、应用研发领域有丰富的研发和实践经验。

陈浩贤

亚马逊云科技解决方案架构师,负责基于亚马逊云科技云平台的解决方案咨询和设计,在系统架构、大数据和机器学习、网络、应用研发领域有丰富的研发和实践经验。