LoginSignup
3
2

More than 3 years have passed since last update.

GuardDutyの検知ログをAmazonESに取り込んでみた

Last updated at Posted at 2020-02-24

はじめに

2019年11月15日にAmazon GuardDutyの検知ログをS3バケットに直接出力できるようになりました。
AWS環境の各種ログをLogstashを使ってAmazon Elasticsearch Service(以下、Amazon ES)に格納し
ログ分析することが趣味になりつつありますが、備忘録的に記事を書いてみましたw

【Amazon GuardDutyとは】
AWS CloudTrailVPC FlowLogsDNSログの3種類のログから
 機械学習、異常検出および統合された脅威インテリジェンスを使用することで
 AWS環境における潜在的な脅威を識別し、継続的にモニタリングする脅威検出サービスです。

※このDNSログは、Route53のホストゾーンに対するDNSクエリログとは異なります。
 外部からのクエリログではなく、EC2などがVPC内で参照しているDNSサーバのDNSログです。
 このDNSログはユーザに提供されていないログとなっていて、貴重な情報源になります。

【参考】
Amazon GuardDutyとは
GuardDutyの検出結果をS3にエクスポート出来るようになりました

利用環境

product version
logstash 7.5.2
Java 11.0.6
OS(EC2) Amazon Linux2 (t3.small)
AMI ID ami-011facbea5ec0363b
Amazon ES 7.1 (latest)
Region us-east-1

※投稿時点における最新版を採用しています。

【構成図】
image.png

前提条件

  • Elasticsearchへのログ出力にはElastic社のETLツールであるLogstashを利用しています。
  • Amazon Elasticsearch Service(以下、Amazon ES)は、パブリックアクセスとしています。
    (IPアドレスによるホワイトリスト制御)

【参考】
Logstashとは

実施内容

  1. IAM Role作成
  2. KMSキーの作成
  3. S3バケットの作成
  4. GuardDutyのログ出力設定
  5. Amazon ESのドメイン作成
  6. Logstashの構築
  7. Kibanaでの各設定

1. IAM Role作成

  • EC2として構築するLogstashに割り当てるIAM Roleを作成します。
  • logatashに割り当てるIAM Roleとしてlogstashinputというロールを作成し、
    AmazonS3ReadOnlyAccessという用意されているIAM Policyを割り当てます。
    ※LogstashからS3バケット内のGuardDutyのログにアクセスできるようにします。 image.png
AmazonS3ReadOnlyAccess
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Resource": "*"
        }
    ]
}

2. KMSキーの作成

  • [Key Management Service] > [カスタマー管理型のキー]からキーの作成をクリックします。
    image.png

  • 暗号と復号で利用するので、[対称]のまま[次へ]をクリックします。
    image.png

  • エイリアスに任意の鍵名を入力し、[次へ]をクリックします。
    image.png

  • キーの管理アクセスに適切なIAMユーザを指定します。
    image.png

  • [次へ]をクリックします。
    image.png

  • 今回はEC2のLogstashがS3に蓄積された暗号化されたGuardDutyのログを触るため
    EC2に割り当てるIAMロール(logstashinput)にKMSキーへの利用アクセス権限を付与します。
    image.png

  • GuardDutyが暗号化してログ出力するため、KMSキーにアクセスするための権限を付与します。
    image.png

  • これでKMSキーの作成は完了です。
    image.png

  • 適用したKMSキーポリシーは以下の通りです。

KMSキーポリシー
{
    "Id": "key-consolepolicy-3",
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<AWSアカウント>:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Sid": "Allow access for Key Administrators",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<AWSアカウント>:user/<IAM>ユーザ>"
            },
            "Action": [
                "kms:Create*",
                "kms:Describe*",
                "kms:Enable*",
                "kms:List*",
                "kms:Put*",
                "kms:Update*",
                "kms:Revoke*",
                "kms:Disable*",
                "kms:Get*",
                "kms:Delete*",
                "kms:TagResource",
                "kms:UntagResource",
                "kms:ScheduleKeyDeletion",
                "kms:CancelKeyDeletion"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::<AWSアカウント>:role/logstashInput",
                    "arn:aws:iam::<AWSアカウント>:user/<IAM>ユーザ>"
                ]
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow attachment of persistent resources",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::<AWSアカウント>:role/logstashInput",
                    "arn:aws:iam::<AWSアカウント>:user/<IAM>ユーザ>"
                ]
            },
            "Action": [
                "kms:CreateGrant",
                "kms:ListGrants",
                "kms:RevokeGrant"
            ],
            "Resource": "*",
            "Condition": {
                "Bool": {
                    "kms:GrantIsForAWSResource": "true"
                }
            }
        },
        {
            "Sid": "Allow GuardDuty to use the key",
            "Effect": "Allow",
            "Principal": {
                "Service": "guardduty.amazonaws.com"
            },
            "Action": "kms:GenerateDataKey",
            "Resource": "*"
        }
    ]
}

※LogstashにKMSキーへのアクセス権限がない場合、logstash-plain.logで下記エラーが出力されます。

logstash-plain.log
[2020-02-24T20:52:47,491][WARN ][logstash.inputs.s3][guardduty] S3 input: Unable to download remote file {:remote_key=>"AWSLogs/GuardDuty/<AWSアカウント>/us-east-1/2020/02/24/091daaf6-255f-360d-a75f-b3f3811d4043.jsonl.gz", :message=>"Access Denied"}

【参考】
調査結果のエクスポート

3. S3バケットの作成

  • GuardDutyの検知ログ出力先のS3バケットを作成します。

    (今回は、既存バケットであるパブリック非公開のbuild-test01を利用します)
    image.png

  • GuardDutyからログの出力に必要なアクセス権限をバケットポリシーに追加します。
    image.png

  • 必要な権限は下記の内容になります。

バケットポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Allow GuardDuty to use the getBucketLocation operation",
            "Effect": "Allow",
            "Principal": {
                "Service": "guardduty.amazonaws.com"
            },
            "Action": "s3:GetBucketLocation",
            "Resource": "arn:aws:s3:::build-test01"
        },
        {
            "Sid": "Allow GuardDuty to upload objects to the bucket",
            "Effect": "Allow",
            "Principal": {
                "Service": "guardduty.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::build-test01/*"
        },
        {
            "Sid": "Deny unencrypted object uploads. This is optional",
            "Effect": "Deny",
            "Principal": {
                "Service": "guardduty.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::build-test01/*",
            "Condition": {
                "StringNotEquals": {
                    "s3:x-amz-server-side-encryption": "aws:kms"
                }
            }
        },
        {
            "Sid": "Deny incorrect encryption header. This is optional",
            "Effect": "Deny",
            "Principal": {
                "Service": "guardduty.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::build-test01/*",
            "Condition": {
                "StringNotEquals": {
                    "s3:x-amz-server-side-encryption-aws-kms-key-id": "arn:aws:kms:us-east-1:<AWSアカウント>:key/<KMSキーID>"
                }
            }
        },
        {
            "Sid": "Deny non-HTTPS access",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::build-test01/*",
            "Condition": {
                "Bool": {
                    "aws:SecureTransport": "false"
                }
            }
        }
    ]
}

4. GuardDutyのログ出力設定

  • [GuardDuty] > [設定]の結果のエクスポートオプションから設定します。
  • [更新された結果の頻度]は、要件に応じて設定します。(今回は、15分ごとにします)
  • [S3バケット]の[今すぐ設定する]をクリックします。
    image.png

  • 作成したS3バケットとKMSキーを指定し、[保存]をクリックします。
    image.png

  • これでOKです!
    image.png

  • [結果サンプルの生成]ボタンを押すと大量にサンプルログが出力されます。
    image.png

  • S3バケット(build-test01/AWSLogs/<AWSアカウント>/GuardDuty/<リージョン名>配下)に.gzファイルが格納されていればOKです。
    image.png

5. Amazon ESのドメイン作成

  • 下記内容でAmazon ESのドメインを作成します。
項目
リージョン us-east-1
デプロイタイプ 開発およびテスト
Elasticsearchのバージョン 7.1 (latest)
Elasticsearchのドメイン loganalytics-dev
インスタンスタイプ c5.large.elasticsearch
ノードの数 1
データノードのストレージタイプ EBS
EBS ボリュームタイプ 汎用(SSD)
EBS ボリュームサイズ 10 GiB
自動スナップショットの開始時間 00:00 UTC (デフォルト)
ネットワークアクセス パブリックアクセス
細かいアクセスコントロールを有効化 無効
Amazon Cognito認証を有効化 無効
ドメインアクセスポリシー カスタムアクセスポリシー (IPv4アドレス)
ドメインへのすべてのトラフィックにHTTPSを要求 有効
ノード間の暗号化 無効
保管時のデータの暗号化の有効化 無効

※アクセスポリシーに追加するIPは、Amazon ESにアクセスする外部IPとLogstashのIPになります。

6. Logstashの構築

  • LogstashをEC2 Amazon Linux2 (t3.small)で構築します。
  • 下記のパイプライン構成ファイル(/etc/logstash/conf.d/logstash.conf)の設定を行います。
    (このタイミングではLogstashは起動しません。)
logstash.conf
input {
  ### ログ取得元のS3バケットを指定
  s3 {
    bucket => "build-test01"
    prefix => "AWSLogs/<AWSアカウント>/GuardDuty"
    region => "us-east-1"
    interval => 5
    codec => "json_lines"
    tags => "guardduty"
  }
}

filter {
  ### dateフィールドから@timestampを抽出
  date {
    match => [ "updatedAt", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" ]
    timezone => "UTC"
    target => "@timestamp"
  }
  ### @timstampから日本時間を抽出
  ruby {
    code => "event.set('[@metadata][local_time]',event.get('[@timestamp]').time.localtime.strftime('%Y-%m-%d'))"
  }
  ### document_idに利用する一意のIDを作成
  fingerprint {
    source => "id"
    target => "[@metadata][fingerprint]"
    method => "MURMUR3"
  }
}

output {
  ### 出力先のAmazonESのIndexを指定
  elasticsearch {
    hosts => [ "https://search-loganalytics-dev-xxxxxxxxxxxxxxxxxxxxxx.us-east-1.es.amazonaws.com:443" ]
    index => "%{[service][serviceName]}-%{[@metadata][local_time]}"
    document_id => "%{[@metadata][fingerprint]}"
    ilm_enabled => false
  }
}

【2020/4/21追記】
ilm_enabled => falseは、Amazon ESのバージョン7以降を利用する場合は、記載しないとエラーになるので注意してください。
※ Logstash 7.0.0でILM(Index Lifecycle Management)の自動検出機能を追加され、これが悪さをするようです。

【参考】
s3 input
json_lines codec
date filter
ruby filter
fingerprint filter
elasticsearch output

7. Kibanaでの各設定

  • Amazon ESのKibanaのURLをクリックします。
    image.png

  • [Dev Tools]のConsoleからGuardDutyのIndex Templateを追加します。
    image.png

  • 上記で張り付けたIndex Templateは以下の通りです。

index_templete_guardduty
PUT _template/guardduty
{
  "index_patterns": ["guardduty-*"],
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas" : 1
  },
  "mappings" : {
    "dynamic_templates" : [
      {
        "message_field" : {
          "path_match" : "message",
          "mapping" : {
            "norms" : false,
            "type" : "text"
          },
          "match_mapping_type" : "string"
        }
      },
      {
        "string_fields" : {
          "mapping" : {
            "norms" : false,
            "type" : "text",
            "fields" : {
              "keyword" : {
                "ignore_above" : 256,
                "type" : "keyword"
              }
            }
          },
          "match_mapping_type" : "string",
          "match" : "*"
        }
      }
    ],
    "properties" : {
      "@timestamp" : {
        "type" : "date"
      },
      "geoip" : {
        "dynamic" : true,
        "properties" : {
          "ip" : {
            "type" : "ip"
          },
          "latitude" : {
            "type" : "half_float"
          },
          "location" : {
            "type" : "geo_point"
          },
          "longitude" : {
            "type" : "half_float"
          }
        }
      },
      "@version" : {
        "type" : "keyword"
      }
    }
  },
  "aliases" : { }
}
  • Logstashを起動します。
logstash_start
$ sudo systemctl start logstash
$ sudo systemctl status logstash
● logstash.service - logstash
   Loaded: loaded (/etc/systemd/system/logstash.service; disabled; vendor preset: disabled)
   Active: active (running) since Sun 2020-02-23 17:11:21 UTC; 4min 42s ago
 Main PID: 32168 (java)
   CGroup: /system.slice/logstash.service
           └─32168 /bin/java -Xms1g -Xmx1g -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -Djava.awt.h...

Feb 23 17:12:00 ip-172-31-37-204.ec2.internal logstash[32168]: [2020-02-23T17:12:00,242][INFO ][logstash.outputs.elasticsearch][main] New Elastic...:443"]}
Feb 23 17:12:00 ip-172-31-37-204.ec2.internal logstash[32168]: [2020-02-23T17:12:00,282][INFO ][logstash.filters.geoip   ][main] Using geoip data....mmdb"}
Feb 23 17:12:00 ip-172-31-37-204.ec2.internal logstash[32168]: [2020-02-23T17:12:00,332][INFO ][logstash.outputs.elasticsearch][main] Using defau...emplate
Feb 23 17:12:00 ip-172-31-37-204.ec2.internal logstash[32168]: [2020-02-23T17:12:00,396][INFO ][logstash.outputs.elasticsearch][main] Attempting ...field"=
Feb 23 17:12:00 ip-172-31-37-204.ec2.internal logstash[32168]: [2020-02-23T17:12:00,460][WARN ][org.logstash.instrument.metrics.gauge.LazyDelegatingGaug...
Feb 23 17:12:00 ip-172-31-37-204.ec2.internal logstash[32168]: [2020-02-23T17:12:00,467][INFO ][logstash.javapipeline    ][main] Starting pipeline {:pip...
Feb 23 17:12:01 ip-172-31-37-204.ec2.internal logstash[32168]: [2020-02-23T17:12:01,418][INFO ][logstash.javapipeline    ][main] Pipeline started..."main"}
Feb 23 17:12:01 ip-172-31-37-204.ec2.internal logstash[32168]: [2020-02-23T17:12:01,497][INFO ][logstash.agent           ] Pipelines running {:co...es=>[]}
Feb 23 17:12:01 ip-172-31-37-204.ec2.internal logstash[32168]: [2020-02-23T17:12:01,736][INFO ][logstash.agent           ] Successfully started L...=>9600}
Feb 23 17:12:14 ip-172-31-37-204.ec2.internal logstash[32168]: /usr/share/logstash/vendor/bundle/jruby/2.5.0/gems/logstash-filter-fingerprint-3.2...recated
Hint: Some lines were ellipsized, use -l to show in full.
  • Kibanaの [Management] > [Index Patterns]でCreate index patternをクリックします。

  • guardduty-*という名前でIndex Patternを作成します。
    image.png

  • @timestampを指定します。
    image.png

  • [Discover]を開き、Index Patternにguardduty-*を指定します。

  • デフォルトでは直近15分間のログが表示されます。表示されていればOKです。
    image.png

  • 取り込んだログは以下のような感じです。

gaurdduty_log
{
  "_index": "guardduty-2020-02-24",
  "_type": "_doc",
  "_id": "129922432",
  "_version": 6,
  "_score": null,
  "_source": {
    "severity": 2,
    "schemaVersion": "2.0",
    "partition": "aws",
    "service": {
      "detectorId": "36b5b031cc6ac83b7932a959d8f6e4c3",
      "resourceRole": "TARGET",
      "eventFirstSeen": "2019-06-16T13:03:20Z",
      "serviceName": "guardduty",
      "eventLastSeen": "2020-02-24T14:43:53Z",
      "additionalInfo": {},
      "archived": false,
      "action": {
        "awsApiCallAction": {
          "serviceName": "s3.amazonaws.com",
          "remoteIpDetails": {
            "organization": {
              "org": "<ISP Name>",
              "isp": "<ISP Name>",
              "asn": "xxxx",
              "asnOrg": "<ISP Name>"
            },
            "geoLocation": {
              "lon": xxx.702,
              "lat": xx.6419
            },
            "ipAddressV4": "xxx.xxx.44.xxx",
            "country": {
              "countryName": "Japan"
            },
            "city": {
              "cityName": "Meguro-ku"
            }
          },
          "api": "GetBucketPublicAccessBlock",
          "callerType": "Remote IP",
          "affectedResources": {}
        },
        "actionType": "AWS_API_CALL"
      },
      "count": 3752
    },
    "tags": [
      "guardduty"
    ],
    "type": "Policy:IAMUser/RootCredentialUsage",
    "accountId": "<AWSアカウント>",
    "resource": {
      "resourceType": "AccessKey",
      "accessKeyDetails": {
        "userType": "Root",
        "userName": "Root",
        "principalId": "<AWSアカウント>",
        "accessKeyId": "**************"
      }
    },
    "updatedAt": "2020-02-24T14:58:03.608Z",
    "description": "API GetBucketPublicAccessBlock was invoked using root credentials from IP address xxx.xxx.44.xxx.",
    "@version": "1",
    "@timestamp": "2020-02-24T14:58:03.608Z",
    "title": "API GetBucketPublicAccessBlock was invoked using root credentials.",
    "id": "48b5b0363bda3223350e73641c2e5a55",
    "region": "us-east-1",
    "arn": "arn:aws:guardduty:us-east-1:<AWSアカウント>:detector/36b5b031cc6ac83b7932a959d8f6e4c3/finding/48b5b0363bda3223350e73641c2e5a55",
    "createdAt": "2019-06-16T13:14:09.716Z"
  },
  "fields": {
    "createdAt": [
      "2019-06-16T13:14:09.716Z"
    ],
    "@timestamp": [
      "2020-02-24T14:58:03.608Z"
    ],
    "service.eventLastSeen": [
      "2020-02-24T14:43:53.000Z"
    ],
    "service.eventFirstSeen": [
      "2019-06-16T13:03:20.000Z"
    ],
    "updatedAt": [
      "2020-02-24T14:58:03.608Z"
    ]
  },
  "sort": [
    1582556403395
  ]
}

まとめ

いかがでしたでしょうか。
GuardDutyのコンソール画面ではなかなか分析に活用するのは難しいです。
Amazon ESに取り込み、他のAWS環境のログと相関分析に利用することでより高度な分析ができるのでは^^;

3
2
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
3
2