1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AthenaでCloudTrailログを楽々検索!

Posted at

はじめに

AWSアカウント内のリソースの操作について過去ログを辿りたい時、皆さんCloudTrailを使っていると思います。

しかしCloudTrailのコンソール画面からだと検索できるのは過去3か月であり、一部の操作ログはそこから検索できなかったりもします。

そんな時はAthenaを使用して、CloudTrailのログを検索しましょう。

CloudTrailのログの実体はS3に保存されているので、Athenaでテーブルを作成することでS3に保存されたログを検索することができます。

テーブル作成

以下のDDLを、虫食い部分を埋めてAthenaで実行すればOKです。

CREATE EXTERNAL TABLE IF NOT EXISTS `default`.`cloudtrail_logs` (
  `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
      >,
      ec2RoleDelivery: string,
      webIdFederationData: map <
        string,
        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,
  `tlsDetails` struct <
    tlsVersion: string,
    cipherSuite: string,
    clientProvidedHostHeader: string
  >
)
PARTITIONED BY (region string, date string)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
STORED AS INPUTFORMAT 'com.amazon.emr.cloudtrail.CloudTrailInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION 's3://{対象のバケット名}/AWSLogs/{AWSアカウントID}/'
TBLPROPERTIES (
    'projection.enabled' = 'true',
    'projection.date.type' = 'date',
    'projection.date.range' = '{任意の開始日(yyyy/MM/dd形式で)},NOW',
    'projection.date.format' = 'yyyy/MM/dd',
    'projection.date.interval' = '1',
    'projection.date.interval.unit' = 'DAYS',
    'projection.region.type' = 'enum',
    'projection.region.values'='us-east-1,us-east-2,us-west-1,us-west-2,af-south-1,ap-east-1,ap-south-1,ap-northeast-2,ap-southeast-1,ap-southeast-2,ap-northeast-1,ca-central-1,eu-central-1,eu-west-1,eu-west-2,eu-south-1,eu-west-3,eu-north-1,me-south-1,sa-east-1',
    'storage.location.template' = 's3://{対象のバケット名}/AWSLogs/{AWSアカウントID}/CloudTrail/${region}/${date}',
    'classification'='cloudtrail',
    'compressionType'='gzip',
    'typeOfData'='file',
    'classification'='cloudtrail'
);

虫食い箇所

  • {対象のバケット名}: CloudTrailログが保存されているS3バケット名
  • {AWSアカウント番号}: 作業しているAWSのアカウントID
  • {任意の開始日(yyyy/MM/dd形式で)}: CloudTrailログの保存開始日

実際に埋めるとこんな感じになります。

  • s3://my-cloudtrail-logs-bucket/AWSLogs/123456789012/
  • 'projection.date.range' = '2019/01/01,NOW'

パーティショニングについて詳細解説

PARTITIONED BY (region string, date string)

この部分でパーティションとするキーを指定しています。今回はリージョンと日付。

S3に存在するTrailのデータ内にはこの情報はないのですが、S3のPrefixとしてリージョンと日付が切られた形で出力されているため、このようなパーティショニングが可能です。

    'projection.date.type' = 'date',
    'projection.date.range' = '{任意の開始日(yyyy/MM/dd形式で)},NOW',
    'projection.date.format' = 'yyyy/MM/dd',
    'projection.date.interval' = '1',
    'projection.date.interval.unit' = 'DAYS',

この部分で、カラムとしてのdateについての設定をしています。見てわかる通りですが、型や日付書式、いつからいつまでの範囲でパーティションを作成するか、などを指定しています。

    'projection.region.type' = 'enum',
    'projection.region.values'='us-east-1,us-east-2,us-west-1,us-west-2,af-south-1,ap-east-1,ap-south-1,ap-northeast-2,ap-southeast-1,ap-southeast-2,ap-northeast-1,ca-central-1,eu-central-1,eu-west-1,eu-west-2,eu-south-1,eu-west-3,eu-north-1,me-south-1,sa-east-1',

次はregionについての設定です。リージョンはenum型で、この値でパーティションが切られているよという指定です。

ちなみにここで指定する各リージョンを示す文字列は間違っていても問題はなく、単純にその値で検索してもヒットするものが0件になります。(パーティションが正しく認識されないため)

上記 CREATE EXTERNAL TABLE 文を実行した際も、 SELECT 文を実行した際もエラーとはならないため、ご注意を。

    'storage.location.template' = 's3://{対象のバケット名}/AWSLogs/{AWSアカウントID}/CloudTrail/${region}/${date}',

最後に、パーティションの位置についての設定です。

${region}${date}の部分で、これまで設定してきたパーティションの値はS3のパス上のココに入るよ、ということを示しています。

上記のようなパーティショニングが無いとTrailのログを全て読み込むことになり、非常にAthenaの利用料が高くなります。

検索例文

WHERE句に対象期間は必ず入れましょう!

そうしないとAthenaの利用料が大爆発します。

そもそも検索も遅くなってしまうので、逆に検索したらやけに遅いな…という場合は正しくパーティションを使えていない可能性があるので急ぎ、実行をキャンセルしましょう。

操作の内容で検索

SELECT * FROM cloudtrail_logs
WHERE eventname = 'CreateBucket'
AND date BETWEEN '2021-01-01' AND '2021-01-31'

あの操作の詳細情報が見たい、このリソースを作ったのは誰だ?なんて時に。

サービスの種類で検索

SELECT * FROM cloudtrail_logs
WHERE eventsource = 's3.amazonaws.com'
AND date BETWEEN '2021-01-01' AND '2021-01-31'

サービス単位で操作を追いたい時に。

特定ユーザーの操作すべてを検索

SELECT * FROM cloudtrail_logs
WHERE useridentity.userName = 'myuser'
AND date BETWEEN '2021-01-01' AND '2021-01-31'

ストーキング…

特定のリソース名で検索

正直これはオススメしません。

なぜなら、サービスごとにどのようなキーに対してどういう値で検索すれば良いかが異なるため、調査や試行錯誤に無駄に時間を取られがちです。

このリソースは誰が作ったんだ?という場合は、そのリソースを作成するAPIの機能名で検索するのが良いでしょう。(操作の内容で検索)

一応、特定のLambda関数を例にした検索クエリを以下に記載します。

SELECT * FROM cloudtrail_logs
WHERE requestParameters like '%arn:aws:lambda:ap-northeast-1:123456789012:function:my-function%'
AND date BETWEEN '2021-01-01' AND '2021-01-31'

まとめ

今回のパーティションの追加の仕方は、Partition Projectionという方式を使っています。

手動でパーティションを追加していく方法もありますが、これは非常に手間がかかるので、せめてGlueのCrawlerを使わないとやってられないです…

それでは、よきTrail検索ライフを。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?