[アップデート] GuardDuty の検出結果を S3 にエクスポート出来るようになりました

先日のアップデートで GuardDuty の検出結果を直接 S3 に保存することが可能になりました。

なにが嬉しいのか

これまで GuardDuty の標準機能としてログを保管する仕組みはありませんでしたので、CloudWatch Events から Lambda や Kinesis Firehose を連携させて S3 にアウトプットする。といった作り込みが必要でした。

これが標準機能として S3 に保存できるようになりますので、ログ保管の実装が非常に簡単になります。

検証環境

今回は以下の環境で検証しています。

  • GuardDuty、S3、KMS すべて東京リージョン
  • ログ用バケットは同一アカウント内の S3 を指定

すべてのリージョンの GuardDuty 検出結果を1つのリージョンに集約したり、複数のアカウントの GuardDuty 検出結果を1つのアカウントに集約することも可能ですが、今回はサクッと検証するためにシンプルな環境で行っています。

事前準備

KMS キー

エクスポートされるログは指定するバケットと同一リージョンの KMS キーを使って暗号化されます。そのため、暗号化に使用する KMS キーを事前に作成しておく必要があります。既存の KMS キーをお使いの場合も GuardDuty サービスに権現を与える必要があります。新規 or 既存のいずれにおいても、以下のステートメントを対象のキーポリシーに追加しておきます。

{
    "Sid": "Allow GuardDuty to use the key",
    "Effect": "Allow",
    "Principal": {
        "Service": "guardduty.amazonaws.com"
            },
            "Action": "kms:GenerateDataKey",
            "Resource": "*"
}

S3 バケット

検証ではログ設定画面から新規バケットを作成していますが、既存バケットを利用される場合は GuardDuty がアクセスできるようにバケットポリシーを設定しておく必要があります。ボリュームが多いので、詳細は公式ガイドを参照ください。

設定してみる

GuardDuty のダッシュボードから[設定]-[結果のエクスポートオプション]を開きます。エクスポートの頻度は15分/1時間/6時間から指定できます。今回はすぐに確認できるように15分ごとにしました。[今すぐ設定する]をクリックし先に進みます。

メニューに従い、S3バケットおよび KMS キーを指定します。

さいごに[保存]をクリックして完了です。

KMS キーポリシーのアクセス権限がないとき

KMS キーのキーポリシーで権限付与を忘れていた場合、以下のようなエラーが表示されました。ご参考まで。

確認

意図的に EC2 の22番ポートをパブリック公開に設定し、すぐに検出されるようにしました。特にプレフィックスを指定していない場合、以下のような階層でログ出力されます。

s3://{LOG_BUCKET_NAME}/AWSLogs/GuardDuty/{ACCOUNT_ID}/{REGION}/YYYY/MM/DD/

ログ出力の内容

$ aws s3 cp s3://cm-marumo-guardduty-log/AWSLogs/GuardDuty/xxxxxxxxxxxx/ap-northeast-1/2019/11/16/82b564a7-0bb4-3a40-8d80-798669cb6051.jsonl.gz - | zcat | jq
{
  "schemaVersion": "2.0",
  "accountId": "xxxxxxxxxxxx",
  "region": "ap-northeast-1",
  "partition": "aws",
  "id": "5ab73a304a0fa36c838edba6cf864b8e",
  "arn": "arn:aws:guardduty:ap-northeast-1:xxxxxxxxxxxx:detector/eeb7399c3391590bdcd7d7329085e55e/finding/5ab73a304a0fa36c838edba6cf864b8e",
  "type": "Recon:EC2/PortProbeUnprotectedPort",
  "resource": {
    "resourceType": "Instance",
    "instanceDetails": {
      "instanceId": "i-0da77b18c2c6bf617",
      "instanceType": "t2.nano",
      "launchTime": "2019-11-16T08:42:42Z",
      "platform": null,
      "productCodes": [],
      "iamInstanceProfile": null,
      "networkInterfaces": [
        {
          "ipv6Addresses": [],
          "networkInterfaceId": "eni-0966d12be4c58549e",
          "privateDnsName": "ip-192-168-1-246.ap-northeast-1.compute.internal",
          "privateIpAddress": "192.168.1.246",
          "privateIpAddresses": [
            {
              "privateDnsName": "ip-192-168-1-246.ap-northeast-1.compute.internal",
              "privateIpAddress": "192.168.1.246"
            }
          ],
          "subnetId": "subnet-xxxxxxxx",
          "vpcId": "vpc-xxxxxxxx",
          "securityGroups": [
            {
              "groupName": "launch-wizard-11",
              "groupId": "sg-06a75f6bd6501efe3"
            }
          ],
          "publicDnsName": "ec2-18-176-14-76.ap-northeast-1.compute.amazonaws.com",
          "publicIp": "18.176.14.76"
        }
      ],
      "tags": [
        {
          "key": "Name",
          "value": "guard-duty-test"
        }
      ],
      "instanceState": "running",
      "availabilityZone": "ap-northeast-1c",
      "imageId": "ami-0064e711cbc7a825e",
      "imageDescription": "Amazon Linux 2 AMI 2.0.20191024.3 x86_64 HVM gp2"
    }
  },
  "service": {
    "serviceName": "guardduty",
    "detectorId": "eeb7399c3391590bdcd7d7329085e55e",
    "action": {
      "actionType": "PORT_PROBE",
      "portProbeAction": {
        "portProbeDetails": [
          {
            "localPortDetails": {
              "port": 22,
              "portName": "SSH"
            },
            "remoteIpDetails": {
              "ipAddressV4": "222.186.175.183",
              "organization": {
                "asn": "23650",
                "asnOrg": "AS Number for CHINANET jiangsu province backbone",
                "isp": "China Telecom",
                "org": "China Telecom jiangsu province backbone"
              },
              "country": {
                "countryName": "China"
              },
              "city": {
                "cityName": "Shanghai"
              },
              "geoLocation": {
                "lat": 31.0449,
                "lon": 121.4012
              }
            }
          }
        ],
        "blocked": false
      }
    },
    "resourceRole": "TARGET",
    "additionalInfo": {
      "threatName": "Brute Forcer",
      "threatListName": "ProofPoint"
    },
    "evidence": {
      "threatIntelligenceDetails": [
        {
          "threatListName": "ProofPoint",
          "threatNames": [
            "Scanner"
          ]
        },
        {
          "threatListName": "ProofPoint",
          "threatNames": [
            "Brute Forcer"
          ]
        }
      ]
    },
    "eventFirstSeen": "2019-11-16T13:16:14Z",
    "eventLastSeen": "2019-11-16T13:17:07Z",
    "archived": false,
    "count": 1
  },
  "severity": 2,
  "createdAt": "2019-11-16T13:21:56.767Z",
  "updatedAt": "2019-11-16T13:21:56.767Z",
  "title": "Unprotected port on EC2 instance i-0da77b18c2c6bf617 is being probed.",
  "description": "EC2 instance has an unprotected port which is being probed by a known malicious host."
}

こんな感じで出力されました。

暗号化

新規作成された S3 バケットのデフォルト暗号化は無効ですが、オブジェクト単位で指定した KMS キーで暗号化されていました。

$ aws s3api head-object --bucket cm-marumo-guardduty-log --key AWSLogs/GuardDuty/xxxxxxxxxxxx/ap-northeast-1/2019/11/16/82b564a7-0bb4-3a40-8d80-798669cb6051.jsonl.gz
{
    "AcceptRanges": "bytes",
    "ContentType": "application/json",
    "LastModified": "Sat, 16 Nov 2019 13:25:05 GMT",
    "ContentLength": 1191,
    "ContentEncoding": "gzip",
    "ETag": "\"57c9927db0cdde0edbe0178c62a3fb6c\"",
    "ServerSideEncryption": "aws:kms",
    "SSEKMSKeyId": "arn:aws:kms:ap-northeast-1:xxxxxxxxxxxx:key/739a6e32-5b43-43dc-b1b7-2df7476d4d83",
    "Metadata": {}
}

上記のとおり KMS 暗号化されているので、このログを使って何らかの処理を行う場合は、その AWS サービスやロールに KMS キーユーザのアクセス権限が必要です。KMS キーユーザーではない場合、以下のようにアクセスすることは出来ません。

$ aws s3 cp s3://cm-marumo-guardduty-log/AWSLogs/GuardDuty/xxxxxxxxxxxx/ap-northeast-1/2019/11/16/82b564a7-0bb4-3a40-8d80-798669cb6051.jsonl.gz - | zcat | jq
download failed: s3://cm-marumo-guardduty-log/AWSLogs/GuardDuty/xxxxxxxxxxxx/ap-northeast-1/2019/11/16/82b564a7-0bb4-3a40-8d80-798669cb6051.jsonl.gz to - An error occurred (AccessDenied) when calling the GetObject operation: Access Denied

さいごに

これまで GuardDuty の検出結果をログとして保管するには、CloudWatch Events を起点に Lambda や Kinesis Firehose と連携させたり、サードパーティのツールを使って実現させていましたが標準機能で実装できるようになったのは嬉しいですね!

ログが KMS 暗号化されているので、利用する場合には KMS キーへのアクセス権限が必要となる点、お忘れなく!

以上!大阪オフィスの丸毛(@marumo1981)でした!