審計(jì)(Audit)是所有平臺都需要的一個(gè)非常重要的基礎(chǔ)功能。云計(jì)算平臺的租戶眾多,需要審計(jì)每個(gè)租戶的操作。AWS CloudTrail就是用以審計(jì)租戶行為的一款產(chǎn)品。
從CloudTrail的Release Notes可以看出,這款產(chǎn)品2013-11-13發(fā)布了第一個(gè)版本,歷史非常悠久,發(fā)展到今天,幾乎所有的云產(chǎn)品都支持CloudTrail。生產(chǎn)者眾多,消費(fèi)者也不少,CloudTrail可以跟S3、CloudWatch和Macie打通,為用戶分析審計(jì)數(shù)據(jù)提供良好的支持。下面一一盤點(diǎn)一下CloudTrail的主要特性和功能。
- CloudTrail兩個(gè)功能分別是七天事件和跟蹤。七天事件免費(fèi)對用戶開放,數(shù)據(jù)包含全局事件和本region服務(wù)產(chǎn)生的寫事件。七天事件只保留七天,不能做任何定制。跟蹤則用于滿足用戶多樣的需求。
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.
根據(jù)我的測試,七天事件并不會收集AssumeRole接口的信息,可能AWS覺得這是一個(gè)讀操作吧。
$ 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": []
}
為了進(jìn)一步驗(yàn)證這個(gè)結(jié)論。我分別創(chuàng)建一個(gè)Management Event All和Write-only的trail,使用cli做AssumeRole之后,將S3 Bucket同步到本地查了一下,只有All的trail才會有AssumeRole事件,Write-only的不會有。另外一點(diǎn)要注意的是,STS作為一個(gè)Global Service,它在每個(gè)region也有自己的endpoint。如果用戶沒有顯式去deactive,那么會優(yōu)先使用region的endpoint,這樣日志也就記到了各個(gè)region里面了。詳細(xì)信息請查看文檔: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支持將多個(gè)賬號的審計(jì)事件投遞到一個(gè)賬號的S3 Bucket中。投遞到CloudWatch則不支持這樣做??缳~號授權(quán)服務(wù)寫自己的S3 Bucket,對于用戶來講是難于理解和配置的。但是S3 Bucket Policy簡化了這個(gè)問題,它居然可以允許任何用戶的CloudTrail寫自己的S3 Bucket。詳細(xì)信息請參考文檔:Receiving CloudTrail Log Files from Multiple Accounts。
CloudTrail支持用戶自定義
Event Selector,以幫助用戶對收集采集做更多精細(xì)的控制。用戶可以在selector中指定收集哪些數(shù)據(jù)源的事件。目前支持S3的object-level API事件和Lambda函數(shù)調(diào)用事件。
$ 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幾乎所有的產(chǎn)品,每個(gè)云產(chǎn)品的文檔都會有一個(gè)章節(jié)描述如何使用CloudTrail收集本產(chǎn)品的信息,顯示了AWS強(qiáng)大的頂層設(shè)計(jì)和執(zhí)行能力。比如EC2的文檔里面有一節(jié)Logging API Calls Using AWS CloudTrail。
審計(jì)是為了記錄誰在什么時(shí)間做了什么事情,得到什么結(jié)果。CloudTrail產(chǎn)出的event有豐富字段,可以在CloudTrail Record Contents文檔中了解這些字段的含義。
用戶可以創(chuàng)建多個(gè)trail,trail可以應(yīng)用到所有region,也可以只用在一個(gè)region上。將trail應(yīng)用到所有region時(shí),會在各個(gè)region創(chuàng)建同名的shadow trail。S3 bucket按照
AWSLogs/${account_id}/CloudTrail/${region_id}/${year}/${month}/${day}命名格式保存事件日志。
每個(gè)trail有一個(gè)HomeRegion屬性,用于標(biāo)識這個(gè)trail是哪個(gè)region創(chuàng)建的。AWS CLI默認(rèn)會把shadow trail顯示出來。需要帶上--no-include-shadow-trails參數(shù)才不會顯示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)創(chuàng)建了foo這個(gè)trail,切換到us-east-1(Virginia)也能看到這個(gè)trail,但是如果要修改這個(gè)trail,必須切換到us-east-2(Ohio)才行。

- 所有的trail,不管是不是應(yīng)用到所有region,都將收到全局事件。為了驗(yàn)證這個(gè)特點(diǎn),我創(chuàng)建了兩個(gè)trail,一個(gè)應(yīng)用到所有region(在Ohio region),另外一個(gè)沒有(在Virginia region)。
接著在IAM里面創(chuàng)建一個(gè)名為hs001的子賬號,然后去這兩個(gè)trail的S3 bucket里面查看日志??梢园l(fā)現(xiàn)這兩個(gè)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去查找相應(yīng)的事件。
$ 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 日志會記錄到哪個(gè)region,應(yīng)該也是us-east-1。
另外七天事件是trail的數(shù)據(jù)源,每個(gè)region的七天事件都包含了全局服務(wù)的事件,所以這個(gè)地方是有冗余的。結(jié)合起來的示意圖如下所示。

從lookup-events接口也可以看出來,切換到不同的region,能搜索到同樣的全局的事件。

- 關(guān)于trail命名的問題。一個(gè)region下不能創(chuàng)建同名的trail,但是可以創(chuàng)建跟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
#接口默認(rèn)會獲取本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支持管理事件和數(shù)據(jù)事件這兩種事件類型。目前數(shù)據(jù)事件只支持S3,還不支持?jǐn)?shù)據(jù)庫等別的類型。而國家等保要求是要對數(shù)據(jù)庫做審計(jì)的,所以這個(gè)功能的缺失會導(dǎo)致客戶過不了一些合規(guī)要求。S3 Bucket level API產(chǎn)出管理事件,Object level API產(chǎn)出數(shù)據(jù)事件。需要S3的Bucket打開
Object-level logging,CloudTrail才能收集到這個(gè)Bucket的數(shù)據(jù)事件。管理事件只有出現(xiàn)復(fù)制時(shí),才對復(fù)制的事件收費(fèi);數(shù)據(jù)事件都要收費(fèi)的。具體的收費(fèi)規(guī)則請參看:AWS CloudTrail Pricing。

- 如果S3配置有誤,比如S3 Bucket被刪除了,S3 Bucket Policy配置不對,CloudTrail在控制臺會給出提示。在Personal Health Dashboard里面并沒有給出提示。

- CloudTrail支持將日志事件投遞到CloudWatch。在控制臺里面指定log group,同時(shí)要?jiǎng)?chuàng)建需要的role。

CloudTrail跟CloudWatch結(jié)合起來之后,就可以利用CloudWatch更強(qiáng)大的Filter and Pattern Syntax分析日志。

使用CloudWatch還可以針對CloudTrail收集到的事件創(chuàng)建Metric和Alarm,這樣做監(jiān)控報(bào)警也是非常方便的。CloudTrail跟CloudWatch Events結(jié)合起來就更加強(qiáng)大了,可以通過事件觸發(fā)執(zhí)行自定義的Lambda函數(shù),做更加豐富和復(fù)雜的事情。參考文章: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結(jié)合起來,會擁有更加強(qiáng)大的數(shù)據(jù)分析能力。可以自己在EC2上搭建Kibana服務(wù),也有專門提供這種服務(wù)的公司,比如logz.io,參考文章:AWS CloudTrail Log Analysis with the ELK Stack。
CloudTrail是一個(gè)重要的基礎(chǔ)設(shè)施,AWS也不指望CloudTrail賺錢。但是如果產(chǎn)生照副本事件,這是要收費(fèi)的,所以要慎重創(chuàng)建多余的trail。因?yàn)樗械膖rail都會接受到全局事件,而創(chuàng)建應(yīng)用到所有region的trail更是會產(chǎn)生大量的副本事件。當(dāng)然S3存儲、SNS通知的費(fèi)用是另算的。
為了保證審計(jì)的可靠性和私密性,CloudTrail支持?jǐn)?shù)據(jù)加密和完整性驗(yàn)證。
CloudTrail的實(shí)時(shí)性在五分鐘左右。如果使用AWS Kinesis這樣流式計(jì)算平臺來處理日志,應(yīng)該可以提高實(shí)時(shí)性。
CloudTrail提供CPL庫(CloudTrail Processing Library)給用戶做日志分析。CloudTrail配置好SNS接受S3文件發(fā)布消息,SNS里面配置好使用SQS來訂閱消息。應(yīng)用程序引入CPL之后,從SQS里面獲取文件消息。用戶只需實(shí)現(xiàn)Event Processor。不過我感覺CPL這套處理機(jī)制已經(jīng)過時(shí)了,通過S3 trigger Lambda執(zhí)行,是一種更加簡單的解決方案。

- 使用Athena來分析CloudTrail的日志也是一件非常有趣的事情。我猜測CloudTrail Event History里面的搜索也是使用Athena來實(shí)現(xiàn)的。不知道實(shí)時(shí)性是否能滿足需求。配置文檔:Querying AWS CloudTrail Logs。

AWS今年還發(fā)布了一款高端產(chǎn)品:Macie,通過機(jī)器學(xué)習(xí)自動(dòng)發(fā)現(xiàn)、分類和保護(hù) AWS 中的敏感數(shù)據(jù)。Macie分析的數(shù)據(jù)主要來自于CloudTrail。
CloudTrail依賴IAM、S3、SNS這些更底層的基礎(chǔ)設(shè)施實(shí)現(xiàn)自身的功能,又將自身變成AWS一個(gè)非常重要的基礎(chǔ)設(shè)施。AWS這種逐漸積累、相互依賴,在不同層次為用戶提供功能豐富的產(chǎn)品的方式非常棒。
參考資料。