logo头像
Snippet 博客主题

AWS上结合Router53构建思科远程访问VPN高可用架构

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个最大会话。

三、配置部署

3.1 通过CloudFormation创建实验环境

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:

#===============创建SSM Role===============#
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 VPC===============#
SSLVPN:
Type: AWS::EC2::VPC
Properties:
CidrBlock: '10.1.0.0/16'
EnableDnsSupport: 'true'
EnableDnsHostnames: 'true'
Tags:
- Key: Name
Value: SSLVPN

# 创建IGW并且关联到VPC
SSLVPNIgw:
Type: "AWS::EC2::InternetGateway"
Properties:
Tags:
- Key: Name
Value: !Sub SSLVPNIGW

SSLVPNAttachIgw:
Type: "AWS::EC2::VPCGatewayAttachment"
Properties:
VpcId: !Ref SSLVPN
InternetGatewayId: !Ref SSLVPNIgw

#-----------创建子网-----------#

# SSLVPN 创建公有子网
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


#-----------NAT Gateway-----------#
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

# --------------创建ASA1接口--------------

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: # 关联公网IP到弹性接口
DependsOn: Asav1Instance
Type: AWS::EC2::EIPAssociation
Properties:
AllocationId: !GetAtt Asav1OutsideEip.AllocationId
NetworkInterfaceId: !Ref Asav1OutsideEni

# --------------创建Asav2接口--------------
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: # 关联公网IP到弹性接口
DependsOn: Asav2Instance
Type: AWS::EC2::EIPAssociation
Properties:
AllocationId: !GetAtt Asav2OutsideEip.AllocationId
NetworkInterfaceId: !Ref Asav2OutsideEni

# --------------实例配置--------------

# 创建ASAv1实例
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

# 创建Asav2实例
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的连通性。

五、文档链接