CloudTrailのログをAthena で検索する †
- Athenaはスキャンしたデータサイズによって課金される。1回のスキャンで1TBあたり$5。
- AWSアカウントID、リージョン、年、月、日等で、パーティションを作成し1回のスキャン量を減らす。
- AWS CloudTrail ログのクエリ - Amazon Athena
- AWS CloudTrail ログを検索するために Amazon Athena でテーブルを作成する
- CloudTrailの管理画面からAthenaのTableを作成すると、パーティションが設定されない。よって、日時の絞り込みが出来ず、スキャン量が大きくなり料金も高くなる。
- 「CREATE TABLE」「DROP TABLE」「SELECT」等すべて「start-query-execution」で非同期に実行する
- ワークグループ選択 > 詳細を表示 > データ使用状況の制御タブ > データの制限で1回のスキャンの上限を設定できる。1000MBにした場合は、0.005 USD(0.53円)に抑えられる。
- 「no viable alternative at input」が出る場合は、CREATE TABLE時のパラメータ順序が間違っている。「COMMENT」の後に「PARTITIONED BY」を指定する
クエリの例 †
CloudTrailのログを別アカウントから参照しようとするとエラーになる †
※ALB/ELBのログもs3 objectのownerが外部アカウントなので同じエラーが出ると思われる。
- 目的
- アカウントA(111111111111)にあるCloudTrailのログを、アカウントB(222222222222)のAthenaから参照したい。
- 現象:
- アカウントBのAthenaから、アカウントAへのs3 bucketへのqueryが失敗する。
- s3 lsは成功する。s3 cpが失敗する。
aws s3 ls --profile account-b s3://cloudtrailbucket-example/
# OK
aws s3 cp --profile account-b s3://cloudtrailbucket-example/AWSLogs/111111111111/CloudTrail/ap-northeast-1/2018/01/01/111111111111_CloudTrail_ap-northeast-1_20180101T0000Z_****.json.gz ./
fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden
- s3 bucket policyでgetやlistの権限は与えている
{
"Sid": "AthenaRead",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::222222222222:root"
},
"Action": [
"s3:GetBucketLocation",
"s3:GetObject",
"s3:ListBucket",
],
"Resource": [
"arn:aws:s3:::cloudtrailbucket-example",
"arn:aws:s3:::cloudtrailbucket-example/*"
]
}
- 理由:
- 基本はs3 objectのownerしか読み書きできない。
- s3 objectのownerがcloudtrail(aws_cloudtrail_ap-northeast-1)になっている。そのままでは、アカウントAのIAM userがs3 objectが見えなくなるので、CloudTrailのs3 bucket policy でアカウントAのオーナー(account-a)にもフルコントロールが与えられている。
aws s3api get-object-acl --profile account-a --bucket cloudtrailbucket-example --key AWSLogs/111111111111/CloudTrail/ap-northeast-1/2018/01/01/111111111111_CloudTrail_ap-northeast-1_20180101T0000Z_****.json.gz
{
"Owner": {
"DisplayName": "aws_cloudtrail_ap-northeast-1",
"ID": "***"
},
"Grants": [
{
"Grantee": {
"DisplayName": "aws_cloudtrail_ap-northeast-1",
"ID": "****",
"Type": "CanonicalUser"
},
"Permission": "FULL_CONTROL"
},
{
"Grantee": {
"DisplayName": "account-a",
"ID": "****",
"Type": "CanonicalUser"
},
"Permission": "FULL_CONTROL"
}
]
}
- この状態では、アカウントBのIAM userからはs3:GetObjectが失敗する。
- 代案
- AssumeRoleで、アカウントAのAthenaから、アカウントAのs3を検索する。
- 全object ACLにアカウントBのreadを許可する。-> Lambdaやcronで定期実行するなど、別の仕組みが必要で面倒。
ログイン監査の作成 †
CloudTrailはAPIのログが残るので、API名(eventName)を知る必要がある。
- SwitchRole:
- roleを切り替えた時。複数アカウントある環境で、別アカウントへの切替(AssumeRole)もこのログになる。
- switch元は「additionalEventData.SwitchFrom」にarnがある
- GetSessionToken, GetFederationToken, AssumeRole, AssumeRoleWithSAML, AssumeRoleWithWebIdentity:
サンプル:
SELECT eventTime,
eventSource,
eventName,
recipientAccountId,
awsRegion,
userIdentity.type AS userIdentity_type,
userIdentity.arn AS userIdentity_arn,
sourceIPAddress,
userAgent
FROM cloudtrail_logs_allregion
WHERE eventName IN ('ConsoleLogin')
AND DATE = '2019/01/02'
ORDER BY eventtime DESC LIMIT 10;
organizations †
都度ALTER TABLEが必要な基本的な方法 †
Partition Projection機能でパーティション管理を自動化する方法は次の項目参照
- Athena上で、CloudTrail用のTableを作成。CloudTrailの管理画面から作る時のDDL(CloudTrailのイベント履歴 > 「Amazon Athena で高度なクエリを実行〜」) + PARTITIONED句
- workgroup, databaseは省略すると、「primary」「default」が使われる。
ATHENA_TABLE_NAME=cloudtrail_logs_allregion
SOURCE_BUCKET=cloudtrail-example
OUTPUT_BUCKET=aws-athena-query-result-123456789012-ap-northeast-1/cloudtrail-example/output/
AWS_PROFILE=example
AWS_REGION=ap-northeasst-1
AWS_ACCOUNT_ID=123456789012
aws athena start-query-execution --profile $AWS_PROFILE --region $AWS_REGION --result-configuration OutputLocation="s3://$OUTPUT_BUCKET" --query-string \
"CREATE EXTERNAL TABLE $ATHENA_TABLE_NAME (
eventVersion STRING,
userIdentity STRUCT<
type: STRING,
principalId: STRING,
arn: STRING,
accountId: STRING,
invokedBy: STRING,
accessKeyId: STRING,
userName: STRING,
sessionContext: STRUCT<
attributes: STRUCT<
mfaAuthenticated: STRING,
creationDate: STRING>,
sessionIssuer: STRUCT<
type: STRING,
principalId: STRING,
arn: STRING,
accountId: STRING,
userName: STRING>>>,
eventTime STRING,
eventSource STRING,
eventName STRING,
awsRegion STRING,
sourceIpAddress STRING,
userAgent STRING,
errorCode STRING,
errorMessage STRING,
requestParameters STRING,
responseElements STRING,
additionalEventData STRING,
requestId STRING,
eventId STRING,
resources ARRAY<STRUCT<
arn: STRING,
accountId: STRING,
type: STRING>>,
eventType STRING,
apiVersion STRING,
readOnly STRING,
recipientAccountId STRING,
serviceEventDetails STRING,
sharedEventID STRING,
vpcEndpointId STRING
)
COMMENT 'CloudTrail table for $SOURCE_BUCKET bucket'
PARTITIONED BY (
region string,
year string,
month string,
day string
)
ROW FORMAT SERDE 'com.amazon.emr.hive.serde.CloudTrailSerde'
STORED AS INPUTFORMAT 'com.amazon.emr.cloudtrail.CloudTrailInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION 's3://$SOURCE_BUCKET/AWSLogs/$AWS_ACCOUNT_ID/CloudTrail/'
TBLPROPERTIES ('classification'='cloudtrail');"
- パーティションを設定。これが無いと全データスキャンになり、コストが高く実行も遅い。全リージョン、指定日(2019-01-02)のみ追加
PART_YEAR=2019
PART_MONTH=01
PART_DAY=02
FOR region IN $(aws ec2 describe-regions --profile $AWS_PROFILE --query 'Regions[].RegionName' | jq -r '.[]'); do \
aws athena start-query-execution --profile $AWS_PROFILE --region $AWS_REGION --result-configuration OutputLocation="s3://$OUTPUT_BUCKET" --query-string \
"ALTER TABLE $ATHENA_TABLE_NAME ADD PARTITION (region='$region',year='$PART_YEAR',month='$PART_MONTH',day='$PART_DAY') LOCATION 's3://$SOURCE_BUCKET/AWSLogs/$AWS_ACCOUNT_ID/CloudTrail/$region/$PART_YEAR/$PART_MONTH/$PART_DAY/'"; \
done
Partition Projection(射影)機能でパーティション管理を自動化 †
- CREATE TABLE: PARTITIONED, TBLPROPERTIESが変わっている
CREATE EXTERNAL TABLE $ATHENA_TABLE_NAME (
eventVersion STRING,
userIdentity STRUCT<
TYPE: STRING,
principalId: STRING,
arn: STRING,
accountId: STRING,
invokedBy: STRING,
accessKeyId: STRING,
userName: STRING,
sessionContext: STRUCT<
attributes: STRUCT<
mfaAuthenticated: STRING,
creationDate: STRING>,
sessionIssuer: STRUCT<
TYPE: STRING,
principalId: STRING,
arn: STRING,
accountId: STRING,
userName: STRING>>>,
eventTime STRING,
eventSource STRING,
eventName STRING,
awsRegion STRING,
sourceIpAddress STRING,
userAgent STRING,
errorCode STRING,
errorMessage STRING,
requestParameters STRING,
responseElements STRING,
additionalEventData STRING,
requestId STRING,
eventId STRING,
resources ARRAY<STRUCT<
arn: STRING,
accountId: STRING,
TYPE: STRING>>,
eventType STRING,
apiVersion STRING,
readOnly STRING,
recipientAccountId STRING,
serviceEventDetails STRING,
sharedEventID STRING,
vpcEndpointId STRING
)
COMMENT 'CloudTrail table for $SOURCE_BUCKET bucket'
PARTITIONED BY (
accountId string,
region string,
DATE string
)
ROW FORMAT SERDE 'com.amazon.emr.hive.serde.CloudTrailSerde'
STORED AS INPUTFORMAT 'com.amazon.emr.cloudtrail.CloudTrailInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION 's3://$SOURCE_BUCKET/AWSLogs/$AWS_ACCOUNT_ID/CloudTrail/'
TBLPROPERTIES(
"projection.enabled" = "true",
"projection.date.type" = "date",
"projection.date.range" = "2019/01/01,NOW",
"projection.date.format" = "yyyy/MM/dd",
"projection.date.interval" = "1" ,
"projection.date.interval.unit" = "DAYS",
"projection.accountid.type" = "enum",
"projection.accountid.values" = "123456789012,etc",
"projection.region.type" = "enum",
"projection.region.values" = "us-east-1,ap-northeast-1,etc",
"storage.location.template" = "s3://$SOURCE_BUCKET/AWSLogs/${accountid}/CloudTrail/${region}/${date}"
);
- 実際のクエリ: 誰が作ったを調べる。
identifier。
|
|