はじめに
2019年11月15日にAmazon GuardDutyの検知ログをS3バケットに直接出力できるようになりました。
AWS環境の各種ログをLogstashを使ってAmazon Elasticsearch Service(以下、Amazon ES)に格納し
ログ分析することが趣味になりつつありますが、備忘録的に記事を書いてみましたw
【Amazon GuardDutyとは】
・AWS CloudTrail
、VPC FlowLogs
、DNSログ
の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 |
※投稿時点における最新版を採用しています。 |
前提条件
- Elasticsearchへのログ出力にはElastic社のETLツールであるLogstashを利用しています。
- Amazon Elasticsearch Service(以下、Amazon ES)は、パブリックアクセスとしています。
(IPアドレスによるホワイトリスト制御)
【参考】
・ Logstashとは
実施内容
- IAM Role作成
- KMSキーの作成
- S3バケットの作成
- GuardDutyのログ出力設定
- Amazon ESのドメイン作成
- Logstashの構築
- Kibanaでの各設定
1. IAM Role作成
- EC2として構築するLogstashに割り当てるIAM Roleを作成します。
- logatashに割り当てるIAM Roleとして
logstashinput
というロールを作成し、
AmazonS3ReadOnlyAccess
という用意されているIAM Policyを割り当てます。
※LogstashからS3バケット内のGuardDutyのログにアクセスできるようにします。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:Get*",
"s3:List*"
],
"Resource": "*"
}
]
}
2. KMSキーの作成
-
今回はEC2のLogstashがS3に蓄積された暗号化されたGuardDutyのログを触るため
EC2に割り当てるIAMロール(logstashinput
)に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
で下記エラーが出力されます。
[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バケットの作成
{
"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バケット(
build-test01/AWSLogs/<AWSアカウント>/GuardDuty/<リージョン名>
配下)に.gzファイルが格納されていればOKです。
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は起動しません。)
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での各設定
-
上記で張り付けたIndex Templateは以下の通りです。
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を起動します。
$ 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
をクリックします。 -
[Discover]を開き、Index Patternに
guardduty-*
を指定します。 -
取り込んだログは以下のような感じです。
{
"_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環境のログと相関分析に利用することでより高度な分析ができるのでは^^;