Memo/AmazonWebServices/Athena/CloudTrail

https://dexlab.net:443/pukiwiki/index.php?Memo/AmazonWebServices/Athena/CloudTrail
 


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」を指定する

クエリの例

  • IAM userのイベントだけにしたい。AWSがAssumeRoleで自動的に実行するイベントは除外したい
    WHERE
      userIdentity.arn != ''
      AND userIdentity.username != 'null'
  • Create系のイベント(EC2の起動も)を抽出したいが、CreateLogStream, CreateLogGroupが多いので除外したい。
    WHERE
      regexp_like(eventName, '^(Create|RunInstances)')
      AND NOT(regexp_like(eventName, '^(CreateLog)'))

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が失敗する。
  • 失敗した方法
    • s3 bucket ACLにアカウントの正規ユーザIDで読み取りを許可する。
      aws s3api list-buckets --query Owner.ID --output text --profile account-b
    • 明示的にIAM権限で許可してみる
    • Principalではなく、ConditionでIAM roleを指定する。

ログイン監査の作成

CloudTrailはAPIのログが残るので、API名(eventName)を知る必要がある。

  • SwitchRole:
    • roleを切り替えた時。複数アカウントある環境で、別アカウントへの切替(AssumeRole)もこのログになる。
    • switch元は「additionalEventData.SwitchFrom」にarnがある

サンプル:

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

  • organizationsの場合、s3 bucket pathに「o-abc123」のようなorg idが入る
    s3://<bucket>/AWSLogs/<org id>/<accountid>/CloudTrail/<region>/<date>/<object.gz>

都度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
  • 実際のクエリ: 誰が作ったを調べる。
    • 「requestparameters=<resource id>」APIのパラメータの中で、ユニークになりそうなIDを指定する。例:RDSのcreate-db-instance APIなら、db-instance-identifier。
    • region, year, month, dayで絞り込む程、高速、低価格になる。
      SELECT *
      FROM cloudtrail_logs_allregion
      WHERE (requestparameters LIKE '%dev-web01%')
              AND region = 'ap-northeast-1'
              AND YEAR = '2019'
              AND MONTH = '01'
              AND DAY = '02'
      ORDER BY  eventtime ASC LIMIT 10;

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。
    • accountid, region, date(YYYY/MM/DD)で絞り込む。
    • dateはSTRING型なので、月間の場合「date LIKE '2019/01/%'」のように指定する。
    • dateはパーティション絞り込み用で、厳密なログの日時ではない。ログの日時を指定したい場合eventTimeも指定する。YYYY/MM/01/に02日のログが一部入っていたりする。
      SELECT *
      FROM cloudtrail_logs_allregion
      WHERE (requestparameters LIKE '%dev-web01%')
              AND accountid = '123456789012'
              AND region = 'ap-northeast-1'
              AND DATE = '2019/01/02'
      ORDER BY  eventtime ASC LIMIT 10;

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2020-10-16 (金) 13:07:15 (10d)