审计(Audit)是所有平台都需要的一个非常重要的基础功能。云计算平台的租户众多,需要审计每个租户的操作。AWS CloudTrail就是用以审计租户行为的一款产品。
从CloudTrail的Release Notes可以看出,这款产品2013-11-13发布了第一个版本,历史非常悠久,发展到今天,几乎所有的云产品都支持CloudTrail。生产者众多,消费者也不少,CloudTrail可以跟S3、CloudWatch和Macie打通,为用户分析审计数据提供良好的支持。下面一一盘点一下CloudTrail的主要特性和功能。
- CloudTrail两个功能分别是七天事件和跟踪。七天事件免费对用户开放,数据包含全局事件和本region服务产生的写事件。七天事件只保留七天,不能做任何定制。跟踪则用于满足用户多样的需求。
Your event history contains the create, modify, and delete activities for supported services taken by
people, groups, or AWS services in your AWS account. To view a complete log of your CloudTrail
events, create a trail and then go to your Amazon S3 bucket or CloudWatch Logs.
根据我的测试,七天事件并不会收集AssumeRole接口的信息,可能AWS觉得这是一个读操作吧。
$ aws sts assume-role --role-arn arn:aws:iam::978343370577:role/YQ001 --role-session-name henshao_test
{
"AssumedRoleUser": {
"AssumedRoleId": "AROAJM25OSMMTTRM3B6ZS:henshao_test",
"Arn": "arn:aws:sts::978343370577:assumed-role/YQ001/henshao_test"
},
"Credentials": {
"SecretAccessKey": "leSTW6PYPqV3s6Ut7/pSqq8N8EmcMI1qS0Gk+9ED",
"SessionToken": "FQoDYXdzEIf//////////wEaDCCm1qu+F6fmVTpbZiLwAQKu/hnQZ+kOVtZk9tyv/Ly406iNIMlMEF8naS9kzRWtq5eJHRV+hl8Uk+S0w3zTX7sq28CJQgS6MMVCGgRRweKgcT3370js+hYldyTykuVLTo5vNw2FKgK47kXv+eGZ3AS85LJbodk+WKTUx2jMLjyofL1G4h7pzm8L5pd3eqi+Wf7NElcETD7Pka9EMAC4pw7zEqECnNCAqUjoOKx4OT5s/VsdLFdGIShcC+jW+y7mAJBbObJbEoivK7N+5icG5KYoTZl9EEKm/hoh/8DxA+SwjKXJ0uc3bSTD1h8zc9YYqArAg1RNz3b4eqQb6PkRkyiql4XQBQ==",
"Expiration": "2017-11-07T06:59:06Z",
"AccessKeyId": "ASIAJYMPMMFBKWSSRTBQ"
}
}
$ sleep 300 && aws cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRole
{
"Events": []
}
为了进一步验证这个结论。我分别创建一个Management Event All和Write-only的trail,使用cli做AssumeRole之后,将S3 Bucket同步到本地查了一下,只有All的trail才会有AssumeRole事件,Write-only的不会有。另外一点要注意的是,STS作为一个Global Service,它在每个region也有自己的endpoint。如果用户没有显式去deactive,那么会优先使用region的endpoint,这样日志也就记到了各个region里面了。详细信息请查看文档:Activating and Deactivating AWS STS in an AWS Region。
$ zgrep -r -l AssumeRole yq001-all yq001-write-only
yq001-all/.swp
yq001-all/AWSLogs/978343370577/CloudTrail/us-east-1/2017/11/08/978343370577_CloudTrail_us-east-1_20171108T0245Z_g9di7CwMhfzOIbRA.json.gz
yq001-all/AWSLogs/978343370577/CloudTrail/us-west-2/2017/11/08/978343370577_CloudTrail_us-west-2_20171108T0235Z_e1E521h8mjVNkrYi.json.gz
yq001-all/AWSLogs/978343370577/CloudTrail/us-west-2/2017/11/08/978343370577_CloudTrail_us-west-2_20171108T0240Z_E0X7iric1I1qrM1q.json.gz
yq001-all/AWSLogs/978343370577/CloudTrail/us-west-2/2017/11/08/978343370577_CloudTrail_us-west-2_20171108T0245Z_r4nygsE720Iwzb2q.json.gz
yq001-all/AWSLogs/978343370577/CloudTrail/us-west-2/2017/11/08/978343370577_CloudTrail_us-west-2_20171108T0250Z_nxVTzr1IAjQCOcNa.json.gz
yq001-all/AWSLogs/978343370577/CloudTrail/us-west-2/2017/11/08/978343370577_CloudTrail_us-west-2_20171108T0255Z_i680lZ9QzaD0sOKd.json.gz
CloudTrail支持将多个账号的审计事件投递到一个账号的S3 Bucket中。投递到CloudWatch则不支持这样做。跨账号授权服务写自己的S3 Bucket,对于用户来讲是难于理解和配置的。但是S3 Bucket Policy简化了这个问题,它居然可以允许任何用户的CloudTrail写自己的S3 Bucket。详细信息请参考文档:Receiving CloudTrail Log Files from Multiple Accounts。
CloudTrail支持用户自定义
Event Selector
,以帮助用户对收集采集做更多精细的控制。用户可以在selector中指定收集哪些数据源的事件。目前支持S3的object-level API事件和Lambda函数调用事件。
$ aws cloudtrail get-event-selectors --trail-name yq0001
{
"EventSelectors": [
{
"IncludeManagementEvents": true,
"DataResources": [
{
"Values": [
"arn:aws:s3"
],
"Type": "AWS::S3::Object"
},
{
"Values": [
"arn:aws:lambda:ap-southeast-1:978343370577:function:CQLambda"
],
"Type": "AWS::Lambda::Function"
}
],
"ReadWriteType": "All"
}
],
"TrailARN": "arn:aws:cloudtrail:us-east-1:978343370577:trail/yq0001"
}
CloudTrail支持AWS几乎所有的产品,每个云产品的文档都会有一个章节描述如何使用CloudTrail收集本产品的信息,显示了AWS强大的顶层设计和执行能力。比如EC2的文档里面有一节Logging API Calls Using AWS CloudTrail。
审计是为了记录谁在什么时间做了什么事情,得到什么结果。CloudTrail产出的event有丰富字段,可以在CloudTrail Record Contents文档中了解这些字段的含义。
用户可以创建多个trail,trail可以应用到所有region,也可以只用在一个region上。将trail应用到所有region时,会在各个region创建同名的shadow trail。S3 bucket按照
AWSLogs/${account_id}/CloudTrail/${region_id}/${year}/${month}/${day}
命名格式保存事件日志。
每个trail有一个HomeRegion
属性,用于标识这个trail是哪个region创建的。AWS CLI默认会把shadow trail显示出来。需要带上--no-include-shadow-trails
参数才不会显示shadow trail。
$ aws cloudtrail describe-trails
{
"trailList": [
{
"IncludeGlobalServiceEvents": true,
"Name": "test001",
"TrailARN": "arn:aws:cloudtrail:us-east-2:978343370577:trail/test001",
"LogFileValidationEnabled": true,
"IsMultiRegionTrail": true,
"HasCustomEventSelectors": false,
"S3BucketName": "cloudtrail-yq002-s3",
"HomeRegion": "us-east-2"
},
{
"IncludeGlobalServiceEvents": true,
"Name": "test001",
"TrailARN": "arn:aws:cloudtrail:us-east-1:978343370577:trail/test001",
"LogFileValidationEnabled": false,
"IsMultiRegionTrail": false,
"HasCustomEventSelectors": false,
"S3BucketName": "cloudtrail-yq002-s3",
"HomeRegion": "us-east-1"
}
]
}
比如我在us-east-2(Ohio)
创建了foo这个trail,切换到us-east-1(Virginia)
也能看到这个trail,但是如果要修改这个trail,必须切换到us-east-2(Ohio)
才行。
- 所有的trail,不管是不是应用到所有region,都将收到全局事件。为了验证这个特点,我创建了两个trail,一个应用到所有region(在Ohio region),另外一个没有(在Virginia region)。
接着在IAM里面创建一个名为hs001
的子账号,然后去这两个trail的S3 bucket里面查看日志。可以发现这两个bucket里面包含了相同的日志文件。
该事件具体信息如下所示。
{
"eventVersion": "1.02",
"userIdentity": {
"type": "Root",
"principalId": "978343370577",
"arn": "arn:aws:iam::978343370577:root",
"accountId": "978343370577",
"accessKeyId": "ASIAJYGQDQLTAMBTNF4A",
"sessionContext": {
"attributes": {
"mfaAuthenticated": "false",
"creationDate": "2017-10-25T17:29:43Z"
}
}
},
"eventTime": "2017-10-26T02:56:57Z",
"eventSource": "iam.amazonaws.com",
"eventName": "CreateUser",
"awsRegion": "us-east-1",
"sourceIPAddress": "42.120.74.107",
"userAgent": "console.amazonaws.com",
"requestParameters": {
"userName": "hs001"
},
"responseElements": {
"user": {
"path": "/",
"arn": "arn:aws:iam::978343370577:user/hs001",
"userId": "AIDAJW6ORA5TRHZCPZYWC",
"createDate": "Oct 26, 2017 2:56:57 AM",
"userName": "hs001"
}
},
"requestID": "54c485da-b9f9-11e7-aa4f-633c5c77f490",
"eventID": "32cec936-d4e1-4ed9-9bc7-0f673b262c0c",
"eventType": "AwsApiCall",
"recipientAccountId": "978343370577"
}
#通过AWS CLI将bucket同步到本地,然后使用zgrep去查找相应的事件。
$ aws s3 sync s3://cloudtrail-cq001-s3 cloudtrail-cq001-s3
$ aws s3 sync s3://cloudtrail-yq003-s3 cloudtrail-yq003-s3
$ zgrep -r -l CreateUser cloudtrail-cq001-s3/* cloudtrail-yq003-s3/*
cloudtrail-cq001-s3/AWSLogs/978343370577/CloudTrail/us-east-1/2017/10/26/978343370577_CloudTrail_us-east-1_20171026T0300Z_P8mz77tfnWK5AWqp.json.gz
cloudtrail-yq003-s3/AWSLogs/978343370577/CloudTrail/us-east-1/2017/10/26/978343370577_CloudTrail_us-east-1_20171026T0300Z_2Mccc89EFYGv0QB9.json.gz
$ md5 cloudtrail-cq001-s3/AWSLogs/978343370577/CloudTrail/us-east-1/2017/10/26/978343370577_CloudTrail_us-east-1_20171026T0300Z_P8mz77tfnWK5AWqp.json.gz cloudtrail-yq003-s3/AWSLogs/978343370577/CloudTrail/us-east-1/2017/10/26/978343370577_CloudTrail_us-east-1_20171026T0300Z_2Mccc89EFYGv0QB9.json.gz
MD5 (cloudtrail-cq001-s3/AWSLogs/978343370577/CloudTrail/us-east-1/2017/10/26/978343370577_CloudTrail_us-east-1_20171026T0300Z_P8mz77tfnWK5AWqp.json.gz) = a76c3f4910953ff0b3ce15b5c5871e25
MD5 (cloudtrail-yq003-s3/AWSLogs/978343370577/CloudTrail/us-east-1/2017/10/26/978343370577_CloudTrail_us-east-1_20171026T0300Z_2Mccc89EFYGv0QB9.json.gz) = a76c3f4910953ff0b3ce15b5c5871e25
示意图如下所示。
从Logging IAM Events with AWS CloudTrail文档可以看出STS global endpoint的日志是要记录到us-east-1
的,但是文档中没有提到IAM的endpoint:https://iam.amazonaws.com 日志会记录到哪个region,应该也是us-east-1
。
另外七天事件是trail的数据源,每个region的七天事件都包含了全局服务的事件,所以这个地方是有冗余的。结合起来的示意图如下所示。
从lookup-events接口也可以看出来,切换到不同的region,能搜索到同样的全局的事件。
- 关于trail命名的问题。一个region下不能创建同名的trail,但是可以创建跟shadow trail同名的trail。
$ aws cloudtrail create-trail --name test001 --s3-bucket-name cloudtrail-yq002-s3
An error occurred (TrailAlreadyExistsException) when calling the CreateTrail operation: Trail test001 already exists for customer: 978343370577
#接口默认会获取本region是Home Region的trail的信息
$ export AWS_DEFAULT_REGION='us-east-1'; aws cloudtrail get-trail-status --name test001
{
"LatestDeliveryAttemptTime": "",
"LatestNotificationAttemptSucceeded": "",
"LatestDeliveryAttemptSucceeded": "",
"IsLogging": false,
"TimeLoggingStarted": "",
"LatestNotificationAttemptTime": "",
"TimeLoggingStopped": ""
}
$ export AWS_DEFAULT_REGION='us-east-2'; aws cloudtrail get-trail-status --name test001
{
"LatestNotificationAttemptSucceeded": "",
"LatestDeliveryAttemptTime": "2017-10-26T08:23:28Z",
"LatestDeliveryTime": 1509006208.65,
"LatestDeliveryAttemptSucceeded": "2017-10-26T08:23:28Z",
"IsLogging": true,
"TimeLoggingStarted": "2017-10-26T03:27:07Z",
"StartLoggingTime": 1508988427.631,
"LatestDigestDeliveryTime": 1509021950.222,
"LatestNotificationAttemptTime": "",
"TimeLoggingStopped": ""
}
#对于shadow trail,会提示不存在。
$ export AWS_DEFAULT_REGION='us-west-2'; aws cloudtrail get-trail-status --name test001
An error occurred (TrailNotFoundException) when calling the GetTrailStatus operation: Unknown trail: test001 for the user: 978343370577
- CloudTrail支持管理事件和数据事件这两种事件类型。目前数据事件只支持S3,还不支持数据库等别的类型。而国家等保要求是要对数据库做审计的,所以这个功能的缺失会导致客户过不了一些合规要求。S3 Bucket level API产出管理事件,Object level API产出数据事件。需要S3的Bucket打开
Object-level logging
,CloudTrail才能收集到这个Bucket的数据事件。管理事件只有出现复制时,才对复制的事件收费;数据事件都要收费的。具体的收费规则请参看:AWS CloudTrail Pricing。
- 如果S3配置有误,比如S3 Bucket被删除了,S3 Bucket Policy配置不对,CloudTrail在控制台会给出提示。在Personal Health Dashboard里面并没有给出提示。
- CloudTrail支持将日志事件投递到CloudWatch。在控制台里面指定log group,同时要创建需要的role。
CloudTrail跟CloudWatch结合起来之后,就可以利用CloudWatch更强大的Filter and Pattern Syntax分析日志。
使用CloudWatch还可以针对CloudTrail收集到的事件创建Metric和Alarm,这样做监控报警也是非常方便的。CloudTrail跟CloudWatch Events结合起来就更加强大了,可以通过事件触发执行自定义的Lambda函数,做更加丰富和复杂的事情。参考文章:Creating CloudWatch Alarms for CloudTrail Events: Examples、Creating a CloudWatch Events Rule That Triggers on an AWS API Call Using AWS CloudTrail。
CloudTrail跟ELK中的Kibana结合起来,会拥有更加强大的数据分析能力。可以自己在EC2上搭建Kibana服务,也有专门提供这种服务的公司,比如logz.io,参考文章:AWS CloudTrail Log Analysis with the ELK Stack。
CloudTrail是一个重要的基础设施,AWS也不指望CloudTrail赚钱。但是如果产生照副本事件,这是要收费的,所以要慎重创建多余的trail。因为所有的trail都会接受到全局事件,而创建应用到所有region的trail更是会产生大量的副本事件。当然S3存储、SNS通知的费用是另算的。
为了保证审计的可靠性和私密性,CloudTrail支持数据加密和完整性验证。
CloudTrail的实时性在五分钟左右。如果使用AWS Kinesis这样流式计算平台来处理日志,应该可以提高实时性。
CloudTrail提供CPL库(CloudTrail Processing Library)给用户做日志分析。CloudTrail配置好SNS接受S3文件发布消息,SNS里面配置好使用SQS来订阅消息。应用程序引入CPL之后,从SQS里面获取文件消息。用户只需实现Event Processor。不过我感觉CPL这套处理机制已经过时了,通过S3 trigger Lambda执行,是一种更加简单的解决方案。
- 使用Athena来分析CloudTrail的日志也是一件非常有趣的事情。我猜测CloudTrail Event History里面的搜索也是使用Athena来实现的。不知道实时性是否能满足需求。配置文档:Querying AWS CloudTrail Logs。
AWS今年还发布了一款高端产品:Macie,通过机器学习自动发现、分类和保护 AWS 中的敏感数据。Macie分析的数据主要来自于CloudTrail。
CloudTrail依赖IAM、S3、SNS这些更底层的基础设施实现自身的功能,又将自身变成AWS一个非常重要的基础设施。AWS这种逐渐积累、相互依赖,在不同层次为用户提供功能丰富的产品的方式非常棒。
参考资料。
- Limits in AWS CloudTrail