AWS GWLB对访问ALB流量做安全检测
一、架构图
B站视频: https://www.bilibili.com/video/BV1Rd4y1F7Fc/?spm_id_from=333.999.0.0
上一篇介绍了GWLB结合Network Load Balancer
的场景,这里介绍一下GWLB结合Application Load Balancer
的场景,主要区别还是在于路由表的设计。另外因为ALB可以关联AWS WAF,所以在代码里面顺带为ALB关联了一个WAF策略,策略只允许来自中国地区的IP访问,来自其他国家地区的请求会被拒绝。
这个架构图高清图片我放到百度网盘了(博客不能添加百度网盘链接,请移步到公众号查看)

实验环境一共有两个VPC,左边的是业务VPC,里面有两个APP模拟HTTP的业务,EC2放在私有子网里面,在不同的AZ。
有一个面向互联网的Application Load Balancer,向公网发布了这个HTTP的服务,这样互联网上的用户,就可以通过ALB访问后面的业务。我们要做的是把这个流量,引导到防火墙上去,做安全检测。这里使用Linux的iptables来模拟防火墙。
另外,APP可以通过NAT GW上网,这个APP主动访问互联网的流量,也需要送到防火墙上去,做安全检测。所以,APP有两种流量都需要送到防火墙上去做安全检测,下面看一下APP的两种流量路径。
一、来自于互联网对ALB访问的流量路径。
-
首先,互联网上的用户,对ALB的公有DNS发起请求,这个DNS请求,会解析到ALB的两个公网IP地址,然后流量通过ISP路由,到达AWS的IGW,然后抵达ALB。 -
流量到达ALB之后,需要转发给APP,但是去往本VPC CIDR段的流量指向了Endpoint,所以ALB会依据路由表将流量发送到Endpoint上,这里假设解析ALB的主IP地址是Public Subnet1,所以流量会给到Endpoint1。 -
Endpoint1收到流量之后,会通过Private Link,把流量发送到GWLB上。 -
GWLB会通过GENEVE封装报文,把流量发送到防火墙。 -
防火墙做完安全检测之后,又会把流量送回给GWLB,然后通过Private Link,送到GWLB Endpoint1。 -
到达GWLB Endpoint1之后,匹配到local路由,流量最终发送到APP1上。
继续看一下回包流程。
-
APP1收到了来自于ALB的流量,APP1看到的源IP地址是ALB弹性接口的私有IP地址,APP1关联的路由表匹配到10.120.0.0/16,将流量发送的Endpoint1。 -
接下来又是一样的流程,流量会经过Private Link到防火墙绕一圈再回来。 -
流量回到GWLB Endpoint1上之后,会匹配到默认路由,将流量发送到NAT GW1。 -
流量到NAT GW1之后,匹配到默认路由,流量通过IGW发送回客户端。
以上就是完整的从互联网对ALB发起请求和回包的流程。
二、APP1主动访问互联网的流量路径
-
APP1对互联网地址发起请求,APP1查询子网关联的路由表,匹配到默认路由,流量送到Endpoint1。 -
流量到GWLB Endpoint1之后,通过Private Link把流量送到防火墙检测,然后再发回来。 -
Endpoint1收到流量之后,会匹配到默认路由,将流量发送到NAT GW1。 -
流量到NAT GW1之后,匹配到默认路由,流量通过IGW发送到目的地。
继续看回包流程。
-
互联网上的主机收到报文以后,源地址是NAT GW1的公网IP地址,报文通过ISP路由,流量到达NAT GW1。 -
到达NAT GW1之后查询转换表项,准备将流量发送到APP1的私有IP地址,NAT GW1去往本VPC CIDR段的流量指向了Endpoint1,所以流量发送到Endpoint1。 -
流量到GWLB Endpoint1之后,通过Private Link把流量送到防火墙检测,然后再发回来。 -
Endpoint1收到流量之后,匹配到local路由,将流量发送到APP1。
二、创建实验环境
堆栈大概需要8分钟左右的时间创建完成。
上传堆栈文件。
编辑堆栈名称,修改实例密钥。
允许创建IAM资源。
Parameters:
EC2InstanceAmiId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
Environment:
Type: String
AllowedValues:
- dev
- prod
Default: dev
MyKeyPair:
Description: Amazon EC2 Key Pair
Type: AWS::EC2::KeyPair::KeyName
Default: Global_Tokyo_KeyPair
WebServerPort:
Description: Apache Http Server Port
Type: String
Default: 8443
AllowedValues:
- 8443
- 8888
- 8088
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: PrivatelianceInstanceAccess
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
#=========================================SecVpc========================================#
# 创建SecVpc
SecVpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.100.10.0/16
EnableDnsSupport: 'true'
EnableDnsHostnames: 'true'
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-SecVpc
# 创建IGW并且关联到VPC
SecVpcIGW:
Type: "AWS::EC2::InternetGateway"
Properties:
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-SecVpcIGW
SecVpcAttachIgw:
Type: "AWS::EC2::VPCGatewayAttachment"
Properties:
VpcId: !Ref SecVpc
InternetGatewayId: !Ref SecVpcIGW
#---------------------------SecVpc创建6个子网-------------------------------------#
# SecVpc AZ1内创建公有子网
SecVpcAz1PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SecVpc
CidrBlock: 10.100.10.0/24
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ""
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-SecVpc-AZ1-Public-Subnet
# SecVpc AZ2内创建公有子网
SecVpcAz2PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SecVpc
CidrBlock: 10.100.20.0/24
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: ""
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-SecVpc-AZ2-Public-Subnet
# SecVpc AZ1内创建私有子网
SecVpcAz1PrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SecVpc
CidrBlock: 10.100.30.0/24
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ""
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-SecVpc-AZ1-Private-Subnet
# SecVpc AZ2内创建私有子网
SecVpcAz2PrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SecVpc
CidrBlock: 10.100.40.0/24
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: ""
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-SecVpc-AZ2-Private-Subnet
# SecVpc AZ1内创建TGW子网
SecVpcAz1TgwSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SecVpc
CidrBlock: 10.100.50.0/24
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ""
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-SecVpc-AZ1-TGW-Subnet
# SecVpc AZ2内创建TGW子网
SecVpcAz2TgwSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SecVpc
CidrBlock: 10.100.60.0/24
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: ""
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-SecVpc-AZ2-TGW-Subnet
#---------------------------SecVpc创建路由表-------------------------------------#
# 公有子网路由表及关联
SecVpcAz1PublicRouteTable:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref SecVpc
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-SecVpc-AZ1-Public-RouteTable
SecVpcAz1PublicRouteTableAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
RouteTableId: !Ref SecVpcAz1PublicRouteTable
SubnetId: !Ref SecVpcAz1PublicSubnet
SecVpcAz2PublicRouteTable:
Type: "AWS::EC2::RouteTable"
Properties: