Amazon GuardDuty Malware Protection for Amazon S3でマルウェアを検出したら削除や隔離をしてみた

2024.06.20

こんにちは、シマです。
皆さんはS3のファイルにマルウェアスキャンをしていますか?先日、S3に対するネイティブなマルウェア検出と保護の機能である「Amazon GuardDuty Malware Protection for Amazon S3」がリリースされ、それに関するブログ記事として以下のようなものがあります。

上記記事内の資料で、以下のようなマルウェア検出による削除や隔離についての構成図がありましたので、本記事ではそれを試してみました。

構築

前提条件

「Amazon GuardDuty Malware Protection for Amazon S3」の設定については、以下の記事の内容は済んでおり、S3バケットにアップロードされたファイルにスキャン結果がタグ付けされる状態になっている前提です。

Lambdaの設定

AWS管理コンソールよりLambdaのページを開き「関数の作成」を押下します。

任意の関数名を入力し、ランタイムは「Python 3.12」を選択しました。
「コード」タブ内にコードを入力し、「Deploy」を押下します。
コードの内容としてはS3タグを確認し、「GuardDutyMalwareScanStatus: THREATS_FOUND」が付与されていたらオブジェクトの移動や削除を行うものです。サンプルコードとして以下にコードを記載します。

lambda_function

import json
import boto3

def lambda_handler(event, context):
    ACTION = "quarantine" # delete or quarantine 検出時に削除か隔離か
    DST_BUCKET_NAME = "xxxxxxx" # quarantineの時に、隔離先バケット名を与える

    bucket_name = event['detail']['bucket']['name']
    key = event['detail']['object']['key']

    s3client = boto3.client('s3')
    res = s3client.get_object_tagging(
        Bucket=bucket_name,
        Key=key
    )

    for tag in res['TagSet']:
        if tag['Key'] == "GuardDutyMalwareScanStatus" and tag['Value'] == "THREATS_FOUND":
            if ACTION == "quarantine":
                s3client.copy_object(Bucket=DST_BUCKET_NAME, Key=key, CopySource={"Bucket": bucket_name, "Key": key})
                print("quarantineObject: ",bucket_name,"\\",key)
            if ACTION == "delete" or ACTION == "quarantine":
                s3client.delete_object(Bucket=bucket_name, Key=key)
                print("deleteObject: ",bucket_name,"\\",key)

「設定」タブから必要に応じてタイムアウト値を変更します。
※隔離アクションに伴うオブジェクト複製が、ファイル容量次第ではデフォルトの3秒以内に終わらないことがあります。
左ペインの「アクセス権限」から実行ロール名をクリックし、実行ロールに権限を追加します。
今回は以下のような権限を追加しました。

{
  "Effect": "Allow",
  "Action": [
    "s3:ListBucket",
    "s3:GetObject",
    "s3:PutObject",
    "s3:DeleteObject",
    "s3:GetObjectTagging"
  ],
  "Resource": [
    "arn:aws:s3:::【スキャン対象バケット名】/*",
    "arn:aws:s3:::【スキャン対象バケット名】"
  ]
},
{
  "Effect": "Allow",
  "Action": [
    "s3:ListBucket",
    "s3:PutObject",
    "s3:GetObject",
    "s3:PutObjectTagging"
  ],
  "Resource": [
    "arn:aws:s3:::【隔離先バケット名】/*",
    "arn:aws:s3:::【隔離先バケット名】"
  ]
}

EventBridgeの設定

EventBridgeの画面から、ルールを作成していきます。
任意の名前を入力し、「次へ」を押下します。
画面下部のメソッド欄で「カスタムパターン (JSON エディタ)」を選択し、イベントパターンとしてはスキャン対象バケットにタグが付与されたイベントを検出するように以下を入力し、「次へ」を押下します。

{
  "source": ["aws.s3"],
  "detail-type": ["Object Tags Added"],
  "detail": {
    "bucket": {
      "name": ["【スキャン対象バケット名】"]
    }
  }
}

ターゲットは先ほど作成したLambda関数を指定し、「次へ」を押下します。
タグについては特に設定せずに「次へ」を押下します。
設定内容を確認し、「ルールの作成」を押下します。

S3 BcuketPolicy

前提条件に記載の状態では、マルウェアからの保護のためタグに「GuardDutyMalwareScanStatus: NO_THREATS_FOUND」が付与されていないものへのアクセスは拒否されます。そのため、Lambdaからのアクションを拒否しないように設定変更します。変更内容は以下の通りです。

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "NoReadExceptForClean",
			"Effect": "Deny",
			"NotPrincipal": {
				"AWS": [
					"arn:aws:iam::999999999999:root",
					"arn:aws:iam::999999999999:role/malware-s3-tokyo-hogehoge-guardduty-plan-role",
					"arn:aws:sts::999999999999:assumed-role/malware-s3-tokyo-hogehoge-guardduty-plan-role/GuardDutyMalwareProtection",
					"arn:aws:iam::999999999999:role/service-role/【Lambda実行ロール名】",
					"arn:aws:sts::999999999999:assumed-role/【Lambda実行ロール名】/【Lambda関数名】"
				]
			},
			"Action": [
				"s3:GetObject",
				"s3:GetObjectVersion"
			],
			"Resource": [
				"arn:aws:s3:::【スキャン対象バケット名】",
				"arn:aws:s3:::【スキャン対象バケット名】/*"
			],
			"Condition": {
				"StringNotEquals": {
					"s3:ExistingObjectTag/GuardDutyMalwareScanStatus": "NO_THREATS_FOUND"
				}
			}
		}
	]
}

試してみた

早速スキャン対象バケットへ無害なテキストファイルと、有害なファイルとしてEicarテストファイルを格納して挙動を確認しました。削除時も隔離時もどちらの場合でも、無害なテキストファイルだけがスキャン対象バケットに残りました。

また、隔離処理時には隔離対象バケットにEicarテストファイルが隔離されていました。

最後に

今回はAmazon GuardDuty Malware Protection for Amazon S3のマルウェア検出による削除や隔離を試してみました。

本記事がどなたかのお役に立てれば幸いです。