AWS SDK for Python (Boto3)を使用してGuard DutyのマルウェアスキャンをEC2に試してみた

# 目次
[1.はじめに](#1-はじめに)
[2.前提条件](#2-前提条件)
[3.実装内容について](#3-実装内容について)
[4.Lambda関数の中身](#4-Lambda関数の中身)
[5.まとめ](#5-まとめ)
[6.参考資料](#6-参考資料)

# 1. はじめに

どうも！アウトプット用にブログを書き始めた駆け出していないエンジニアのたきたです。
2022年にGuardDutyがマルウェアスキャンに対応しましたよね!
（一年前かよとツッコミはせず・・・）
実際の名はGuardDuty Malware Protectionさんです。

ただこいつ検知→マルウェアスキャン開始となるので、潜在的な脅威からは救えないのかなと思いました。
（たしかフローログとかで怪しいトラフィックを見ている）

そこでLambda関数でマルウェアスキャンを検知していなくても、定期的に実行できればセキュアな環境ができるかなと・・・

今回はインスタンス単位での実装を試したので、記載していきたいと思います。

# 2. 前提条件

pythonでlambda関数を作成します。

Lambdaの標準インストールされているBoto3のバージョンを確認しましょう。
　└動作要件はBoto3 1.26.146以上です。

動作要件を満たしていない場合は、Lambda layerを作成しましょう

スキャン対象のインスタンスIDを確認してメモしておく

Lambda関数を実行するIAMロールに以下のポリシーをアタッチしましょう。

・[AmazonEC2ReadOnlyAccess](https://docs.aws.amazon.com/ja_jp/aws-managed-policy/latest/reference/AmazonEC2ReadOnlyAccess.html)

・[AmazonGuardDutyFullAccess](https://docs.aws.amazon.com/ja_jp/guardduty/latest/ug/security-iam-awsmanpol.html)

# 3. 実装内容について

Lambdaで実装します。
ランタイムは、boto3を使用するので、pythonを使用します。
せっかくなのでバージョンはサポート最新のpython3.10
関数を作成していきたいと思います。
必要な情報
・対象のEC2のARN
・ARNに必要な要素
　└リージョン、インスタンスID、アカウントID

マルウェアスキャンに必要な情報はARNのみの認識です。（引用）

~~~
Request Syntax
response = client.start_malware_scan(
    ResourceArn='string'
)
~~~

~~~
PARAMETERS:
ResourceArn (string) –

[REQUIRED]
Amazon Resource Name (ARN) of the resource for which you invoked the API.
~~~

引用元：[start_malware_scan](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/guardduty/client/start_malware_scan.html)

EC2のARNがあればスキャンできます。ドキュメンテーションを参照してください。

上記を踏まえて、関数の中身の構成は以下にしたいと思います。

・環境変数からEC2インスタンスIDを取得

・boto3リソース（EC2）とクライアント（Guard Duty）を作成

・EC2インスタンスのARNを取得

・STSを使用してアカウントIDを取得

・ARN情報を作成

・GuardDutyでマルウェアスキャンを開始

・最後に期待したARNができているか出力して確認

以下のような形で記載すれば、環境変数を使用することが実装可能です。これはほかのところでもよく使うものなので覚えておくとよいでしょう。

~~~
import os
"変数名" = os.environ[‘Lambdaに設定する環境変数Name’]
~~~

# 4. Lambda関数本体

~~~関数本体
import boto3
import os

def lambda_handler(event, context):
    # 環境変数からEC2インスタンスIDを取得します
    instance_id = os.getenv('Lambdaに設定する環境変数Name')

    # boto3リソース（EC2）とクライアント（Guard Duty）を作成します
    ec2 = boto3.resource('ec2')
    guardduty_client = boto3.client('guardduty')

    # EC2インスタンスのARNを取得します
    region_name = "EC2を展開しているリージョン名"
    ec2 = boto3.resource('ec2', region_name=region_name)
    # STSを使用してアカウントIDを取得します
    sts = boto3.client('sts')
    account_id = sts.get_caller_identity()["Account"]

    instance = ec2.Instance(instance_id)
    # 使用するARN情報を作成します
    arn = 'arn:aws:ec2:' + region_name + ':' + account_id + ':instance/' + instance_id

    # GuardDutyでマルウェアスキャンを開始します
    response = guardduty_client.start_malware_scan(ResourceArn=arn)

    print(f"マルウェアスキャン開始！！！！！. Scan ID: {response['ScanId']}")

 # 期待したARNができているか確認する処理
def GuardDutyscan(arn):
    response = guardduty_client.start_malware_scan(ResourceArn=arn)
    return response
~~~

エラー処理は、お試しなのでつけてません、つけたい方はif文とかで実装したり、スキャン結果を取得する関数を追加して再実行とかでもいいかもしれません。

作成した関数をeventbridgeで定時実行させるようにすれば、設定した時間にスキャンをすることが可能です。

# 5. まとめ

ただここまで来るのにattribute errorを吐かれて悩んでいました。
コード上は表記があっているのにもかかわらず実行できなかったためです。

問題だったのは、Lambdaの標準インストールされているboto3のバージョンが「start_malware_scan」を使用できるバージョンではなかったためでした。
これも学びですよね・・・・

そのため、boto3が「start_malware_scan」を使えるバージョンのLambda layerを作成して関数にアタッチしました。

私は上記で実行することができました！
記事書いている人がいなかったので、誰かの助けになればいいかなと思います!!!!!!

# 6. 参考資料

[AWS Lambda のドキュメント](https://docs.aws.amazon.com/ja_jp/lambda/index.html)
[Boto3 のドキュメンテーション](https://boto3.amazonaws.com/v1/documentation/api/latest/index.html)
[Amazon GuardDuty のドキュメンテーション](https://docs.aws.amazon.com/ja_jp/guardduty/index.html)
[Python 3.10の公式ドキュメンテーション](https://docs.python.org/3.10/)