B站视频链接:https://www.bilibili.com/video/BV1xR4y1D7JN
微信公众号:自刘地
一、背景
因为疫情的推动,居家办公已经成为常态化的趋势,员工居家办公的场景下,需要安全的访问企业内网。思科的AnyConnect RA-VPN(Remote Access VPN)是比较常见的解决方案,这篇文档介绍在亚马逊云科技上构建高可用的思科远程访问VPN架构。
在AWS Marketplace上,提供思科的ASAv和FTDv这两款防火墙产品,都可以用来部署AnyConnect RA-VPN,这里介绍更加常见的,通过ASAv防火墙来部署。
RA-VPN会作为员工访问内网的入口,一旦出现故障,将会影响所有员工的远程访问,所以为RA-VPN部署高可用架构是非常重要的。
在AWS上,可以通过两种方式来构建思科RA-VPN的高可用架构:
- Router 53的DNS负载均衡。将VPN的域名配置两个权重相同的
A
记录,分别指向两台ASAv的公网地址,当用户通过VPN域名拨号时,平均来说,Router 53会负载分担的返回两台ASAv的公网IP地址,用户从而拨入到不同的ASAv上。
- Network Load Balancer进行负载均衡。创建一个面向互联网的NLB,关联两台ASAv实例,为VPN的域名设置
CNAME
记录,指向NLB的DNS名称。这样用户通过VPN域名拨号时,会解析到NLB的DNS名称,NLB会将流量负载分担到两台ASAv上。
更加推荐使用第一种高可用架构,基于Router 53的DNS负载均衡来构建RA-VPN的高可用。这可以灵活的控制两台防火墙的流量比例,当其中一台防火墙需要维护升级时,也更容易无感知下线。
二、实验介绍
本次实验会创建两台ASAv防火墙,分别在两个可用区。Router 53 为VPN的域名vpn.demonwcd.com
配置两条权重相同的A
记录,当用户通过域名拨号时,会将流量负载分担到两台ASAv防火墙的公网IP地址上,从而实现远程访问VPN的高可用架构。
用户通过AnyConnect客户端拨号后,获取的IP地址段并不属于VPC CIDR段,思科将这种地址池称为“ghost pool”。通过这种方式,可以让客户端保留源IP地址去访问其他系统,而不用配置源NAT转换。这种配置方式可以与Transit Gateway结合,客户端可以保留源IP地址访问其他VPC。
当使用“ghost pool”之后,路由表需要配置回包路由,指向防火墙的接口,否则客户端无法访问该子网内的系统。
ASAv使用BYOL授权模式的AMI镜像,运行9.18.1
的软件版本,不额外导入授权的情况下,默认对流量限速100kbps、100个最大会话。
三、配置部署
CloudFormation代码如下,代码默认在东京区(ap-northeast-1)运行,如果想要在其他区域运行,需要修改AsavBYOL9181
对应的AMI ID信息。
ASAv已经在User Data中完成了SSLVPN的配置,堆栈创建完成后,可以直接使用ASAv的公网IP地址拨号测试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722
| AWSTemplateFormatVersion: '2010-09-09'
Mappings: RegionMap: ap-northeast-1: AsavBYOL9181: ami-022666395753eceb7
Parameters: MyKeyPair: Description: Amazon EC2 Key Pair Type: AWS::EC2::KeyPair::KeyName Default: Global_Tokyo_KeyPair EC2InstanceAmiId: Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id> Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
Resources:
BastionSsmRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - 'sts:AssumeRole' Path: /
BastionSsmPolicy: Type: AWS::IAM::Policy Properties: PolicyName: ApplianceInstanceAccess PolicyDocument: Statement: - Effect: Allow Action: - ssm:DescribeAssociation - ssm:GetDeployablePatchSnapshotForInstance - ssm:GetDocument - ssm:DescribeDocument - ssm:GetManifest - ssm:GetParameter - ssm:GetParameters - ssm:ListAssociations - ssm:ListInstanceAssociations - ssm:PutInventory - ssm:PutComplianceItems - ssm:PutConfigurePackageResult - ssm:UpdateAssociationStatus - ssm:UpdateInstanceAssociationStatus - ssm:UpdateInstanceInformation Resource: "*" - Effect: Allow Action: - ssmmessages:CreateControlChannel - ssmmessages:CreateDataChannel - ssmmessages:OpenControlChannel - ssmmessages:OpenDataChannel Resource: "*" - Effect: Allow Action: - ec2messages:AcknowledgeMessage - ec2messages:DeleteMessage - ec2messages:FailMessage - ec2messages:GetEndpoint - ec2messages:GetMessages - ec2messages:SendReply Resource: "*" Roles: - !Ref BastionSsmRole
BastionSsmProfile: Type: AWS::IAM::InstanceProfile Properties: Path: / Roles: - !Ref BastionSsmRole
SSLVPN: Type: AWS::EC2::VPC Properties: CidrBlock: '10.1.0.0/16' EnableDnsSupport: 'true' EnableDnsHostnames: 'true' Tags: - Key: Name Value: SSLVPN
SSLVPNIgw: Type: "AWS::EC2::InternetGateway" Properties: Tags: - Key: Name Value: !Sub SSLVPNIGW
SSLVPNAttachIgw: Type: "AWS::EC2::VPCGatewayAttachment" Properties: VpcId: !Ref SSLVPN InternetGatewayId: !Ref SSLVPNIgw
SSLVPNPublicSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref SSLVPN CidrBlock: 10.1.1.0/24 AvailabilityZone: Fn::Select: - 0 - Fn::GetAZs: "" Tags: - Key: Name Value: !Sub SSLVPN-public-subnet1
SSLVPNPublicSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref SSLVPN CidrBlock: 10.1.2.0/24 AvailabilityZone: Fn::Select: - 1 - Fn::GetAZs: "" Tags: - Key: Name Value: !Sub SSLVPN-public-subnet2
SSLVPNPrivateSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref SSLVPN CidrBlock: 10.1.3.0/24 AvailabilityZone: Fn::Select: - 0 - Fn::GetAZs: "" Tags: - Key: Name Value: !Sub SSLVPN-private-subnet1
SSLVPNPrivateSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref SSLVPN CidrBlock: 10.1.4.0/24 AvailabilityZone: Fn::Select: - 1 - Fn::GetAZs: "" Tags: - Key: Name Value: !Sub SSLVPN-private-subnet2
SSLVPNPrivateSubnet3: Type: AWS::EC2::Subnet Properties: VpcId: !Ref SSLVPN CidrBlock: 10.1.5.0/24 AvailabilityZone: Fn::Select: - 0 - Fn::GetAZs: "" Tags: - Key: Name Value: !Sub SSLVPN-private-subnet3
SSLVPNPrivateSubnet4: Type: AWS::EC2::Subnet Properties: VpcId: !Ref SSLVPN CidrBlock: 10.1.6.0/24 AvailabilityZone: Fn::Select: - 1 - Fn::GetAZs: "" Tags: - Key: Name Value: !Sub SSLVPN-private-subnet4
SSLVPNPublicRouteTable1: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref SSLVPN Tags: - Key: Name Value: !Sub SSLVPN-public-routetable
SSLVPNPublicRouteTable1Association1: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: RouteTableId: !Ref SSLVPNPublicRouteTable1 SubnetId: !Ref SSLVPNPublicSubnet1
SSLVPNPublicRouteTable1Association2: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: RouteTableId: !Ref SSLVPNPublicRouteTable1 SubnetId: !Ref SSLVPNPublicSubnet2
SSLVPNPrivateRouteTable1: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref SSLVPN Tags: - Key: Name Value: !Sub SSLVPN-private-routetable1
SSLVPNPrivateRouteTable1Association: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: RouteTableId: !Ref SSLVPNPrivateRouteTable1 SubnetId: !Ref SSLVPNPrivateSubnet1
SSLVPNPrivateRouteTable2: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref SSLVPN Tags: - Key: Name Value: !Sub SSLVPN-private-routetable2
SSLVPNPrivateRouteTable2Association: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: RouteTableId: !Ref SSLVPNPrivateRouteTable2 SubnetId: !Ref SSLVPNPrivateSubnet2
SSLVPNNatGatewayEip1: Type: AWS::EC2::EIP Properties: Tags: - Key: Name Value: !Sub SSLVPN-natgateway-eip1
SSLVPNNatGateway1: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt SSLVPNNatGatewayEip1.AllocationId SubnetId: !Ref SSLVPNPublicSubnet1 Tags: - Key: Name Value: !Sub SSLVPN-natgateway1
SSLVPNNatGatewayEip2: Type: AWS::EC2::EIP Properties: Tags: - Key: Name Value: !Sub SSLVPN-natgateway-eip2
SSLVPNNatGateway2: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt SSLVPNNatGatewayEip2.AllocationId SubnetId: !Ref SSLVPNPublicSubnet2 Tags: - Key: Name Value: !Sub SSLVPN-natgateway2
SSLVPNPublicSubnetRoute1: Type: "AWS::EC2::Route" DependsOn: SSLVPNIgw Properties: RouteTableId: !Ref SSLVPNPublicRouteTable1 DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref SSLVPNIgw
SSLVPNPublicSubnetRoute2: Type: "AWS::EC2::Route" DependsOn: Asav1OutsideEni Properties: RouteTableId: !Ref SSLVPNPublicRouteTable1 DestinationCidrBlock: 10.2.1.0/24 NetworkInterfaceId: !Ref Asav1OutsideEni
SSLVPNPublicSubnetRoute3: Type: "AWS::EC2::Route" DependsOn: Asav1OutsideEni Properties: RouteTableId: !Ref SSLVPNPublicRouteTable1 DestinationCidrBlock: 10.2.2.0/24 NetworkInterfaceId: !Ref Asav2OutsideEni
SSLVPNPrivate1SubnetRoute1: DependsOn: SSLVPNNatGateway1 Type: AWS::EC2::Route Properties: RouteTableId: !Ref SSLVPNPrivateRouteTable1 DestinationCidrBlock: '0.0.0.0/0' NatGatewayId: !Ref SSLVPNNatGateway1
SSLVPNPrivate1SubnetRoute2: Type: "AWS::EC2::Route" DependsOn: Asav1OutsideEni Properties: RouteTableId: !Ref SSLVPNPrivateRouteTable1 DestinationCidrBlock: 10.2.1.0/24 NetworkInterfaceId: !Ref Asav1OutsideEni
SSLVPNPrivate1SubnetRoute3: Type: "AWS::EC2::Route" DependsOn: Asav1OutsideEni Properties: RouteTableId: !Ref SSLVPNPrivateRouteTable1 DestinationCidrBlock: 10.2.2.0/24 NetworkInterfaceId: !Ref Asav2OutsideEni
SSLVPNPrivate2SubnetRoute1: DependsOn: SSLVPNNatGateway2 Type: AWS::EC2::Route Properties: RouteTableId: !Ref SSLVPNPrivateRouteTable2 DestinationCidrBlock: '0.0.0.0/0' NatGatewayId: !Ref SSLVPNNatGateway2
SSLVPNPrivate2SubnetRoute2: Type: "AWS::EC2::Route" DependsOn: Asav1OutsideEni Properties: RouteTableId: !Ref SSLVPNPrivateRouteTable2 DestinationCidrBlock: 10.2.1.0/24 NetworkInterfaceId: !Ref Asav1OutsideEni
SSLVPNPrivate2SubnetRoute3: Type: "AWS::EC2::Route" DependsOn: Asav1OutsideEni Properties: RouteTableId: !Ref SSLVPNPrivateRouteTable2 DestinationCidrBlock: 10.2.2.0/24 NetworkInterfaceId: !Ref Asav2OutsideEni
SSLVPNBastionSg: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: SG to test ping VpcId: !Ref SSLVPN SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 - IpProtocol: icmp FromPort: -1 ToPort: -1 CidrIp: 0.0.0.0/0 - IpProtocol: -1 FromPort: -1 ToPort: -1 CidrIp: 10.1.0.0/16 Tags: - Key: Name Value: !Sub SSLVPN-bastion-sg
AsavSg: Type: AWS::EC2::SecurityGroup DependsOn: SSLVPN Properties: GroupDescription: Permit SSH HTTP/8443 ICMP VpcId: Ref: SSLVPN SecurityGroupIngress: - IpProtocol: -1 FromPort: -1 ToPort: -1 CidrIp: 10.1.0.0/16 - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 8443 ToPort: 8443 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: 0.0.0.0/0 - IpProtocol: icmp FromPort: -1 ToPort: -1 CidrIp: 0.0.0.0/0
Asav1OutsideEip: Type: "AWS::EC2::EIP" Properties: Tags: - Key: Name Value: asav1-outside-eip
Asav1OutsideEni: Type: "AWS::EC2::NetworkInterface" Properties: SourceDestCheck: 'false' GroupSet: - Ref: "AsavSg" SubnetId: Ref: "SSLVPNPublicSubnet1" Tags: - Key: Name Value: asav1-outside-eni
Asav1InsideEni: Type: "AWS::EC2::NetworkInterface" Properties: SourceDestCheck: 'false' GroupSet: - Ref: "AsavSg" SubnetId: Ref: "SSLVPNPrivateSubnet1" Tags: - Key: Name Value: asav1-inside-eni
Asav1MgmtEni: Type: "AWS::EC2::NetworkInterface" Properties: GroupSet: - Ref: "AsavSg" SubnetId: Ref: "SSLVPNPrivateSubnet3" Tags: - Key: Name Value: asav1-mgmt-eni
Asav1OutsideEniAssociation: DependsOn: Asav1Instance Type: AWS::EC2::EIPAssociation Properties: AllocationId: !GetAtt Asav1OutsideEip.AllocationId NetworkInterfaceId: !Ref Asav1OutsideEni
Asav2OutsideEip: Type: "AWS::EC2::EIP" Properties: Tags: - Key: Name Value: asav2-outside-eip
Asav2OutsideEni: Type: "AWS::EC2::NetworkInterface" Properties: SourceDestCheck: 'false' GroupSet: - Ref: "AsavSg" SubnetId: Ref: "SSLVPNPublicSubnet2" Tags: - Key: Name Value: asav2-outside-eni
Asav2InsideEni: Type: "AWS::EC2::NetworkInterface" Properties: SourceDestCheck: 'false' GroupSet: - Ref: "AsavSg" SubnetId: Ref: "SSLVPNPrivateSubnet2" Tags: - Key: Name Value: asav2-inside-eni
Asav2MgmtEni: Type: "AWS::EC2::NetworkInterface" Properties: GroupSet: - Ref: "AsavSg" SubnetId: Ref: "SSLVPNPrivateSubnet4" Tags: - Key: Name Value: asav2-mgmt-eni
Asav2OutsideEniAssociation: DependsOn: Asav2Instance Type: AWS::EC2::EIPAssociation Properties: AllocationId: !GetAtt Asav2OutsideEip.AllocationId NetworkInterfaceId: !Ref Asav2OutsideEni
Asav1Instance: Type: AWS::EC2::Instance Properties: ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", AsavBYOL9181] NetworkInterfaces: - NetworkInterfaceId: !Ref Asav1MgmtEni DeviceIndex: 0 - NetworkInterfaceId: !Ref Asav1OutsideEni DeviceIndex: 1 - NetworkInterfaceId: !Ref Asav1InsideEni DeviceIndex: 2 InstanceType: c5.xlarge Tags: - Key: Name Value: SSLVPN-cisco-asav1 KeyName: !Ref MyKeyPair UserData: Fn::Base64: !Sub | ! ASA Version 9.18(1) hostname asav enable password democisco username asavuser password PBTjhqPgdrYZWx6EwAn privilege 15 aaa authentication ssh console LOCAL ! interface Management0/0 management-only no shutdown nameif management security-level 100 ! interface TenGigabitEthernet0/0 no shutdown nameif outside ip address dhcp ! interface TenGigabitEthernet0/1 no shutdown nameif inside ip address dhcp ! route outside 0 0 10.1.1.1 ! crypto key generate rsa modulus 2048 ! ssh 0 0 management ssh 0 0 outside ssh timeout 60 ! logging enable logging timestamp logging buffered informational ! dns domain-lookup outside DNS server-group DefaultDNS name-server 114.114.114.114 ! clock timezone Beijing 8 name 114.118.7.163 ntp.ntsc.ac.cn ntp server ntp.ntsc.ac.cn source outside ! http 0 0 management http 0 0 outside http server enable ! same-security-traffic permit inter-interface same-security-traffic permit intra-interface ! access-list anyconnect_split standard permit 10.1.0.0 255.255.0.0 access-list anyconnect_split standard permit 10.3.0.0 255.255.0.0 ip local pool anyconnect_client_pool 10.2.1.1-10.2.1.254 mask 255.255.255.0 ! webvpn port 8443 enable outside anyconnect enable ! group-policy anyconnect internal group-policy anyconnect attributes vpn-idle-timeout 7200 vpn-session-timeout 7200 vpn-tunnel-protocol ssl-client ssl-clientless split-tunnel-policy tunnelspecified split-tunnel-network-list value anyconnect_split address-pools value anyconnect_client_pool ! username vpnuser password vpnpassword username vpnuser attributes vpn-group-policy anyconnect
Asav2Instance: Type: AWS::EC2::Instance Properties: ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", AsavBYOL9181] NetworkInterfaces: - NetworkInterfaceId: !Ref Asav2MgmtEni DeviceIndex: 0 - NetworkInterfaceId: !Ref Asav2OutsideEni DeviceIndex: 1 - NetworkInterfaceId: !Ref Asav2InsideEni DeviceIndex: 2 InstanceType: c5.xlarge Tags: - Key: Name Value: SSLVPN-cisco-asav2 KeyName: !Ref MyKeyPair UserData: Fn::Base64: !Sub | ! ASA Version 9.18(1) hostname asav enable password democisco username asavuser password PBTjhqPgdrYZWx6EwAn privilege 15 aaa authentication ssh console LOCAL ! interface Management0/0 management-only no shutdown nameif management security-level 100 ! interface TenGigabitEthernet0/0 no shutdown nameif outside ip address dhcp ! interface TenGigabitEthernet0/1 no shutdown nameif inside ip address dhcp ! route outside 0 0 10.1.2.1 ! crypto key generate rsa modulus 2048 ! ssh 0 0 management ssh 0 0 outside ssh timeout 60 ! logging enable logging timestamp logging buffered informational ! dns domain-lookup outside DNS server-group DefaultDNS name-server 114.114.114.114 ! clock timezone Beijing 8 name 114.118.7.163 ntp.ntsc.ac.cn ntp server ntp.ntsc.ac.cn source outside ! http 0 0 management http 0 0 outside http server enable ! same-security-traffic permit inter-interface same-security-traffic permit intra-interface ! access-list anyconnect_split standard permit 10.1.0.0 255.255.0.0 access-list anyconnect_split standard permit 10.3.0.0 255.255.0.0 ip local pool anyconnect_client_pool 10.2.2.1-10.2.2.254 mask 255.255.255.0 ! webvpn port 8443 enable outside anyconnect enable ! group-policy anyconnect internal group-policy anyconnect attributes vpn-idle-timeout 7200 vpn-session-timeout 7200 vpn-tunnel-protocol ssl-client ssl-clientless split-tunnel-policy tunnelspecified split-tunnel-network-list value anyconnect_split address-pools value anyconnect_client_pool ! username vpnuser password vpnpassword username vpnuser attributes vpn-group-policy anyconnect
SSLVPNApp1: Type: AWS::EC2::Instance Properties: IamInstanceProfile: !Ref BastionSsmProfile ImageId: !Ref EC2InstanceAmiId KeyName: !Ref MyKeyPair InstanceType: t2.micro SecurityGroupIds: - !Ref SSLVPNBastionSg SubnetId: !Ref SSLVPNPrivateSubnet1 Tags: - Key: Name Value: !Sub SSLVPN-App1
SSLVPNApp2: Type: AWS::EC2::Instance Properties: IamInstanceProfile: !Ref BastionSsmProfile ImageId: !Ref EC2InstanceAmiId KeyName: !Ref MyKeyPair InstanceType: t2.micro SecurityGroupIds: - !Ref SSLVPNBastionSg SubnetId: !Ref SSLVPNPrivateSubnet2 Tags: - Key: Name Value: !Sub SSLVPN-App2
|
将CloudFormation代码复制到文本文件中,创建堆栈。
设置堆栈名称,选择EC2的密钥。
允许创建IAM资源,提交创建堆栈请求。
需要5分钟左右,堆栈创建完成。
3.2 Router 53 加权路由策略简介
Router53可以配置基于权重(Weight)的路由策略,流量会按照指定的比例路由到不同的资源上。
权重可以在0~255之间任意指定,任何一个资源记录被选中的概率,取决于其占组中所有记录总权重的比例。例如为www.example.com
设置了三个A记录,权重设置为1(25%)、1(25%)、2(50%)(总和=4),平均而言,Route53选择前面两个A记录每一个的时间为四分之一,选择第三个记录的时间为二分之一。如果将权重设置为100、100、200,流量分配的比例不会发生变化。
基于权重的路由策略,常见的应用场景:
- 区域(region)间负载均衡。NLB无法在区域间进行负载均衡,通过DNS加权路由策略可以在区域间进行负载均衡。
- A/B测试和试用软件新的版本,例如将测试环境设置1%的权重,将会有1%的流量引导到测试环境。
加权路由策略支持关联健康检查,当资源记录关联的健康检查失败后,Router53不会返回对应的资源记录。[1]
3.3 Router 53 配置加权路由策略
记录防火墙的公网IP地址,这里asav1的地址为35.73.113.152,asav2的地址为54.65.246.122。
创建Route 53 健康检查。
配置健康监测信息,设置协议为HTTPS,IP地址设置为asav1的公网地址,端口设置为8443(SSLVPN的端口)。测试环境下,为了快速切换,设置10秒检测一次,2次探测失败修改状态。
配置健康监测信息,设置协议为HTTPS,IP地址设置为asav2的公网地址,端口设置为8443(SSLVPN的端口)。测试环境下,为了快速切换,设置10秒检测一次,2次探测失败修改状态。
查看健康检测策略。
创建资源记录。
在Router 53上创建A
记录,域名为vpn.demonwcd.com
,指向asav1的IP地址35.73.113.152。路由策略设置为基于权重负载,权重设置为100。关联asav1的健康监测策略。设置一个唯一的Record ID值。
继续在Router 53上创建A
记录,域名为vpn.demonwcd.com
,指向asav2的IP地址54.65.246.122。路由策略设置为基于权重负载,权重设置为100。关联asav2的健康监测策略。设置一个唯一的Record ID值。
查看创建的两个A记录,域名vpn.demonwcd.com
分别指向两个asav的公网IP地址。因为设置了相同的权重,所以DNS请求会在不同IP之间进行负载均衡。
可以访问https://ipw.cn/dns,用于测试国内不同地区对于`vpn.demonwcd.com`域名的解析情况 [2]。这里可以看出不同地区的DNS请求,会解析到asav1或者asav2的公网IP地址,TTL是默认的300秒。
或者访问https://dnschecker.org,用于测试全球不同地区对于对于`vpn.demonwcd.com`域名的解析情况 [3]。
也可以通过SSM的方式登录APP1,多次解析vpn.demonwcd.com
域名,会解析到asav1或者asav2的公网IP地址。通过上述测试,可以确认DNS请求会进行负载分担。
可以进一步测试故障切换的场景,这里可以通过Stop asav1来模拟实例故障。点击Stop实例后,状态从Stopping变化为Stopped需要两分钟左右,只有状态成为为Stopped,才会停止转发流量,从而健康监测失败。
如果想要更快的模拟故障,也可以停止asav1的webvpn服务,这会更快的模拟出故障。
1 2
| ciscoasa(config)# webvpn ciscoasa(config-webvpn)# no enable outside
|
当Router53 发现82%以上的监测点,都检测到Failure状态,那么资源将会被设置为Unhealthy
。[4]
再次查询vpn.demonwcd.com
域名,现在只会解析到asav2的公网IP地址。
全球不同地区只只会解析到asav2的公网IP地址,可以确认基于DNS的故障切换是有效的。
四、SSLVPN拨号测试
通过Cisco Secure Client 5.0.00556
进行拨号测试(需要登录思科账号,并且有相应权限才能下载)[5] ,Secure Client客户端是AnyConnect的升级版本。AnyConnect Client和Secure Client安装包已经放在百度网盘 [6]。
这里防火墙没有导入受信任的证书,所以客户端会有证书告警提示。
输入用户名为vpnuser
,密码为vpnpass
。
VPN拨入成功。
拨入后查看获取到的IP地址,这里拨入的是asav1,ping测试到APP1和APP2的连通性。
在客户端上多次拨入测试,当域名解析到asav2上时,也会拨入到asav2上,同样ping测试到APP1和APP2的连通性。
五、文档链接