AWS VPC流量日志允许你记录VPC中网络接口之间的流量信息。此外,这些日志可以存储在AWS S3或发送到AWS CloudWatch Logs,而启用流量日志并不以任何方式影响网络接口的性能。
让我们简单回顾一下基本概念,以及可用的设置,并为VPC设置流量日志,将数据传输到CloduWatch Logs进行分析。
VPC流量日志概述
可以为整个VPC、一个子网或一个外部表面启用日志。如果为整个VPC启用 - 日志将为VPC的所有接口启用。
你可以使用流量日志的服务:
- 弹性负载平衡
- 亚马逊RDS
- 亚马逊ElastiCache
- 亚马逊Redshift
- 亚马逊WorkSpaces
- NAT网关
- 转运网关
该数据被记录为一个 流量日志记录,并使用一个带有预定义字段的记录。
VPC流量日志的使用案例
用流量日志可以跟踪什么?
- SecuirtyGroup/网络访问列表规则 - 被阻止的请求将被标记为REJECTED
- 我们实施日志的目的是什么 - 了解VPC和服务之间的流量情况,以便了解谁消耗的流量最多,在哪里以及有多少跨A区的流量,等等
- 监测系统的远程登录 - 监测端口22(SSH),3389(RDP)。
- 端口扫描跟踪
流量日志记录--字段
日志中的每个条目都是关于聚合区间内收到的IP流量的数据,是一行用空格隔开的字段,每个字段都包含数据传输的信息,例如 - 源IP、目的IP和一个协议。
默认情况下,使用以下格式:
${version} ${account-id} ${interface-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${packets} ${bytes} ${start} ${end} ${action} ${log-status}
见文档中的可用字段表,版本2栏中的所有内容都包含在默认格式中。
当创建流量日志时,我们可以使用默认格式,或者创建我们自己的格式--我们将在下面考虑。
VPC流量日志的局限性
- 不能与EC2-Classic实例一起使用
- 你不能为VPC对等物创建日志,如果它们通向不同账户的VPC。
- 创建日志后,你不能改变其配置或记录格式
此外,请记住,。
- 到亚马逊DNS的记录不被记录,但如果你自己的DNS被使用,就会被写入日志
- 往返于169.254.169.254地址以获取EC2实例元数据的流量不被记录
- EC2网络接口和AWS网络负载平衡器接口之间的流量不被记录。
请参阅流量日志限制中的所有限制。
创建VPC流量日志
要创建一个流量日志,我们需要指定:
- 我们要写日志的资源 - VPC、子网或特定网络接口
- 我们要记录的流量类型(接受的流量,拒绝的流量,或所有流量)
- 我们将把数据写到哪里--写到S3桶,或者写到CloudWatch日志。
现在,让我们看看CloudWatch Logs发生了什么,下次我们将尝试在Kibana中进行可视化。
CloudWatch Logs日志组
创建一个日志组:
IAM策略和IAM角色
为了让Flow Logs服务能够写入我们的CloudWatch,我们需要配置其访问权限。
进入AWS IAM,并创建一个IAM策略和一个IAM角色。
从一个IAM策略开始:
添加规则:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
保存:
现在,创建一个IAM角色。
进入IAM角色,创建一个新的角色,类型为EC2:
找到我们在上面创建的策略,并附加上它:
设置其名称,保存:
进入角色信任关系 (见AWS: IAM AssumeRole - описание, примеры),编辑它 - 对于Service
字段,设置vpc-flow-logs.amazonaws.com。
设置:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "vpc-flow-logs.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
保存:
VPC - 启用流量日志
最后,去VPC启用日志 - 点击流量日志>创建:
在目的地选择CloudWatch日志,指定日志组和IAM角色:
格式 - 保留默认。
检查状态:
几分钟后,我们将看到我们的数据:
在日志组中,你可以找到第一个由弹性网络接口命名的数据流,数据就是从那里来的:
CloudWatch Logs Insights
让我们快速浏览一下CloudWatch Logs Insights。
点击查询以获得一些提示:
例如,找到前15名的主机,这些主机提供了大部分的数据包:
或者按传输的数据量:
stats sum(bytes) as BytesSent by srcAddr, dstAddr
| sort BytesSent desc
好的,这很好。但是其他的形式呢?
例如,我想看到一个请求的方向(出口/出口),以及pkt-dstaddr
字段的值。
VPC流量日志 - 自定义格式
请看更多关于流量日志记录的例子。
现在,我们可以设置以下格式:
region vpc-id az-id subnet-id instance-id interface-id flow-direction srcaddr dstaddr srcport dstport pkt-srcaddr pkt-dstaddr pkt-src-aws-service pkt-dst-aws-service traffic-path packets bytes action
在CloudWatch日志中创建一个新的日志组,将其称为bttrm-eks-dev-1-21-vpc-fl-custom,不要忘记保留:
回到VPC,创建一个新的流量日志,并将其称为bttrm-eks-dev-1-21-vpc-fl-custom:
选择自定义格式和字段,这是我们想要看到的。在这样做的时候,要考虑到你在这里指定的字段的顺序将被用来排列日志中的记录。
也就是说,如果第一个字段是 "区域" - 那么在最终的日志中,它也将被设置为第一个字段:
结果是:
${region} ${vpc-id} ${az-id} ${subnet-id} ${instance-id} ${interface-id} ${flow-direction} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${pkt-srcaddr} ${pkt-dstaddr} ${pkt-src-aws-service} ${pkt-dst-aws-service} ${traffic-path} ${packets} ${bytes} ${action}
流量日志自定义格式和CloudWatch日志洞察力
但是,如果我们现在去CloudWatch Logs Insights,并尝试之前使用的任何查询,我们将不会得到我们设置的字段:
所以,我们可以看到数据,但我们如何将其分割成字段?
在我们的项目中,我认为我们不会经常使用CloudWatch Logs,很可能数据会被发送到S3桶,然后再发送到(logz.io),因此,我不会在这里深入讨论,但让我们看看操作原理--它在以后与ELK的工作中会很有用。
CloudWatch Logs默认创建了几个元字段,我们可以在请求中使用:
@message
:"原始 "数据--文本中的整个消息@timestamp
: 事件发生的时间@logStream
: 一个sLog流的名称
为了让自定义格式看到这些字段,我们需要使用 parse
并把@message
,这样它就会按我们指定的字段解析内容:
parse @message "* * * * * * * * * * * * * * * * * * *"
| as region, vpc_id, az_id, subnet_id, instance_id, interface_id,
| flow_direction, srcaddr, dstaddr, srcport, dstport,
| pkt_srcaddr, pkt_dstaddr, pkt_src_aws_service, pkt_dst_aws_service,
| traffic_path, packets, bytes, action
| sort start desc
在这里,@message
中的星号 "*
" 的数量必须是相同的,与我们设置的字段一样多 -${vpc-id}
и т.д.
另外,字段的名称必须不包含破折号。例如,我们需要把${vpc-id}
的名称作为vpc_id
(或vpcID
- 随你喜欢)。
检查一下:
哇!现在,我们得到了所有的字段:
除了parse
,我们还可以使用filter
、display
、stats
。请参阅CloudWatch Logs Insights查询语法中的所有内容。
Logs Insights例子
让我们试着做几个查询,例如 - 获取所有被SecuirtyGroup/Network Access List阻止的请求 - 它们将被标记为REJECTED。
让我们来看看我们之前的查询:
parse @message "* * * * * * * * * * * * * * * * * * * * * *"
| as start, end, region, vpc_id, az_id, subnet_id, instance_id, interface_id,
| flow_direction, srcaddr, dstaddr, srcport, dstport, protocol,
| pkt_srcaddr, pkt_dstaddr, pkt_src_aws_service, pkt_dst_aws_service,
| traffic_path, packets, bytes, action
并在那里添加:
filter action="REJECT"
stats count(action) as redjects by srcaddr
sort redjects desc
这里:
- 通过应用于数据包的操作进行过滤 - 选择所有的REJECTED
- 通过提交的动作计算事件的数量,通过源的IP地址选择,并在redjects 列中显示它
- 并按拒绝数排序
因此,现在的完整查询将是:
parse @message "* * * * * * * * * * * * * * * * * * *"
| as region, vpc_id, az_id, subnet_id, instance_id, interface_id,
| flow_direction, srcaddr, dstaddr, srcport, dstport,
| pkt_srcaddr, pkt_dstaddr, pkt_src_aws_service, pkt_dst_aws_service,
| traffic_path, packets, bytes, action
| filter action="REJECT"
| stats count(action) as redjects by srcaddr
| sort redjects desc
以及它的结果:
我们还可以使用负数过滤器,并将其与and
/or
操作符相结合。
例如,要从输出中删除所有以162.142.125开头的IP - 添加一个过滤器filter (srcaddr not like "162.142.125.")
:
...
| filter action="REJECT"
| filter (srcaddr not like "162.142.125.")
| stats count(action) as redjects by srcaddr
| sort redjects desc
见样本查询。
并添加一个过滤器,只选择进入的请求 -flow_direction
==ingress:
...
| filter action="REJECT"
| filter (srcaddr not like "162.142.125.") and (flow_direction like "ingress")
| stats count(action) as redjects by flow_direction, srcaddr, dstaddr, pkt_srcaddr, pkt_dstaddr
| sort redjects desc
现在,我们得到了被拒绝的请求的顶部,当安全组或VPC网络访问列表规则发挥作用时。
让我们检查一下dstaddr
中的IP是什么 - 谁是最终的目的地?
进入EC2 > 网络接口,通过私人IP找到:
找到 "Elastic IP地址所有者":
OK,是负载均衡器中的一个。
如果在AWS中找不到一个IP,它可能是一个Kubernetes端点,用以下方法检查它:
kubectl get endpoints --all-namespaces | grep 10.1.55.140
dev-ios-check-translation-nsios-check-translation-backend-svc 10.1.55.140:300058d
dev-ios-check-translation-nsios-check-translation-frontend-svc 10.1.55.140:8058d
实际上,这就是全部。