Inspector v2の脆弱性診断内容を「Slackベース」で管理する

# はじめに

ご覧いただきありがとうございます。

以前[Amazon Inspector Classic](https://qiita.com/gahirosan/items/7a95ccc86e1cec205859)について記事を書きました。

最近 現行バージョンであるInspector v2で検知を行ったところ、検知精度に差があることがわかり、「Classic⇒v2」への移行を行っているところです。

今回はSlack画面で、Inspector v2の脆弱性検知結果を管理できるようにしたいと思います。


# 概要

1. 事前準備
2. Slack ~ Lambda間の連携
3. Lambda ~ Slack間の連携
4. Lambda関数の作成
5. 動作確認


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697264/95a99621-0a5e-55c7-ffd3-3703d08dbdbe.png)


Slackのプライベートチャンネルでコマンドを実行すると、Lambda関数が実行されます。
Lambda関数はInspector v2の診断結果から「重要度が"High"」かつ「Active」の脆弱性を探して、Slackに通知します。


# 1. 事前準備

### Inspector v2の有効化

[公式](https://docs.aws.amazon.com/inspector/latest/user/getting_started_tutorial.html)のユーザーガイドで、設定方法を確認します。

以下の設定が必要です。

- Amazon Inspectorをアカウントで有効化する。
- SSMエージェントをインストール

![](https://storage.googleapis.com/zenn-user-upload/ea87b989e3c3-20220717.png)

Amazon Inspectorのページを開くと、上記の画面が表示されます。
「使用を開始する」をクリック。

![](https://storage.googleapis.com/zenn-user-upload/fd853202dbd0-20220717.png)

「Inspectorを有効化」をクリックします。

![](https://storage.googleapis.com/zenn-user-upload/88c1dcbf3eb8-20220717.png)

Amazon Inspectorが動作する環境ができました。

次にSSMの設定を行います。

- EC2用に「AmazonSSMManagedInstanceCore」が付与されたIAMロールを作成
- 脆弱性診断対象のEC2を1台作成
- EC2にIAMロールを付与して、マネージドインスタンス(Systems Manager)にする

### Inspectorのページで設定反映確認

Inspectorのページで、EC2が認識されているかを確認します。


![](https://storage.googleapis.com/zenn-user-upload/9d8b6aa6041b-20220717.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697264/1e48fae0-3d33-d106-9372-fb0056b0c16a.png)


「検出結果」⇒「インスタンス別」から、EC2インスタンス別に検出結果の確認ができます。
対象のEC2インスタンスを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697264/dff2bc06-2b0b-a7b4-8eb9-06b6ba5f426a.png)


選択したEC2インスタンスについて、重要度が"CRITICAL","HIGH","MEDIUM"別に、検知された脆弱性が表示されます。
今回は"HIGH"の脆弱性6件をユーザーに通知するように設定していきます。




# 2. Slack ~ Lambda間の連携

### AWS Chatbotの設定

Slack ~ Lambda間で連携を行うように設定していきます。

![](https://storage.googleapis.com/zenn-user-upload/7c0d94a58bf7-20220626.png)

AWS Chatbotのページに移動します。
クライアントの設定で「Slack」を選択します。

![](https://storage.googleapis.com/zenn-user-upload/bf1d2332e78d-20220626.png)

今回利用するワークスペースを入力します。

![](https://storage.googleapis.com/zenn-user-upload/9861eb3614d5-20220627.png)

権限リクエストを許可します。

設定が完了すると、AWS Chatbotの設定済クライアントにワークスペースが表示されます。

### Slack側でチャンネル作成

プライベートチャンネルを作成します。

### AWS Chatbot側でチャネル設定

「新しいチャネルを設定」をクリックします。

- 設定名: 任意の名前
- チャネルタイプ: プライベート
- チャネルID: チャンネルID
- ロール設定: チャネルIAMロール
- チャネルIAMロール: テンプレートを使用してIAMロールを作成する
- ロール名: 任意の名前
- ポリシーテンプレート: 「読み取り専用コマンドのアクセス許可」「Lambda呼び出しコマンドのアクセス許可」


上記の設定を行い、チャネルを作成します。

![](https://storage.googleapis.com/zenn-user-upload/46f31c92efca-20220627.png)

### AWS ChatbotをSlackワークスペースに追加

Slackのプライベートチャンネルで
```
/invite @aws
```
を入力して、招待を行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697264/2b571c36-fdfa-f594-498d-f621c89d05a7.png)

SlackのプライベートチャンネルにAWSが招待されました。

これでSlack ~ AWS間の連携ができました。
Slackで入力するコマンドで、Lambda関数を実行できるようになります。

# 3. Lambda ~ Slack間の連携

### Incoming Webhookの設定

続いてLambda ~ Slack間が連携するように設定していきます。

[Incoming Webhook](https://slack.com/intl/ja-jp/help/articles/115005265063-Slack-%E3%81%A7%E3%81%AE-Incoming-Webhook-%E3%81%AE%E5%88%A9%E7%94%A8)を使用します。
外部ソースからの情報を簡単にワークスペースと共有できます。

Slack画面の「App」の画面で、「Appディレクトリ」を選択。

![](https://storage.googleapis.com/zenn-user-upload/4b13e7ee4701-20220626.png)

「ビルド」を選択します。

![](https://storage.googleapis.com/zenn-user-upload/c7780e38fd5c-20220626.png)

次に「Create an app」を選択。

![](https://storage.googleapis.com/zenn-user-upload/44496c6e05eb-20220626.png)

「From scratch」を選択します。

![](https://storage.googleapis.com/zenn-user-upload/d06bbb9ec0f3-20220626.png)

使用するワークスぺースを選択します。

![](https://storage.googleapis.com/zenn-user-upload/e282ac8cc5a6-20220627.png)

「Basic Information」から「Incoming Webhooks」を選択。

![](https://storage.googleapis.com/zenn-user-upload/a44cf6949273-20220627.png)

Webhookをアクティブ化した上で、「Add New Webhook to WorkSpace」を選択。

![](https://storage.googleapis.com/zenn-user-upload/91ea90f00d2c-20220627.png)

通知を送るチャンネルを指定して、「許可する」を選択。

![](https://storage.googleapis.com/zenn-user-upload/512e4a67f5f4-20220626.png)


次のセクションでWebhook URLを使用するので、コピーしておきます。

# 4. Lambda関数の作成

### Lambda関数の作成

- オプション: 一から作成
- 関数名: ※任意の名前
- ランタイム: Python3.8
- アーキテクチャ: x86_64
- アクセス制限: ※Lambda用のロールを付与

関数作成後、設定タブからタイムアウトの秒数を10秒に変更。

コードを作成します。

```
import urllib3
import json
import boto3
http = urllib3.PoolManager()

inspector2 = boto3.client("inspector2")
sns_client = boto3.client('sns')

instance_id = 'xxxxxxxxxxxxxxxxxxxxxxxx'
url = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
slack_channel = 'xxxxxxxxxxxx'




def lambda_handler(event, context):
    paginator = inspector2.get_paginator('list_findings')

    iterator = paginator.paginate(filterCriteria={
                'findingStatus': [
                    {
                        'comparison': 'EQUALS',
                        'value': 'ACTIVE'
                    },
                ],
                'resourceId': [
                    {
                        'comparison': 'EQUALS',
                        'value': instance_id
                    },
                ],
                'severity': [
                    {
                        'comparison': 'EQUALS',
                        'value': 'HIGH'
                    }
                ]
            })
            
    finding = inspector2.list_findings(filterCriteria={
                'findingStatus': [
                    {
                        'comparison': 'EQUALS',
                        'value': 'ACTIVE'
                    },
                ],
                'resourceId': [
                    {
                        'comparison': 'EQUALS',
                        'value': instance_id
                    },
                ],
                'severity': [
                    {
                        'comparison': 'EQUALS',
                        'value': 'HIGH'
                    }
                ]
            }
        )
        
    num = len(finding['findings'])
    
    for n in range(num):
        for i in iterator:
            title = i['findings'][n]['title']
            first_date = i['findings'][n]['firstObservedAt']
            type = i['findings'][n]['type']
            score = i['findings'][n]['inspectorScore']
            severity = i['findings'][n]['severity']
            
            message = f"脆弱性を検知しました。内容をご確認ください。\nID: {instance_id}\nTitle: {title}\nAccrual date: {first_date}\nType: {type}\nScore: {score}\nSeverity: {severity}"
            
            msg = {
                "channel": slack_channel,
                "username": "",
                "text": message,
                "icon_emoji": ""
            }
    
            encoded_msg = json.dumps(msg).encode('utf-8')
            resp = http.request('POST',url, body=encoded_msg)
    
    return 0

```
「xxxxxxxxxxxxxxxxxxxxxxxxx」は、自身の環境のものに置き換えてください。
instance_id = 対象のEC2インスタンスID
url = Webhook URL
slack_channel = Slackのプライベートチャンネル名

boto3の記述方法は[リファレンス](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/inspector2.html)、Lambda ~ Slack間の通知方法は[こちら](https://aws.amazon.com/jp/premiumsupport/knowledge-center/sns-lambda-webhooks-chime-slack-teams/)を参考にしています。

# 5. 動作確認

ではSlackのプライベートチャンネルで、下記のコマンドを入力します。

```
@aws lambda invoke xxxxxxxxxxxxxx --region ap-northeast-1
```

「xxxxxxxxxxxxxx」には、Lambda関数の名前を入力します。

Slackコマンドを入力すると、コマンドを実行するか聞かれるので、承認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697264/f911c1a8-3f67-0643-1fa1-39ab8f4942ef.png)


Slack側で6件の通知が行われました。
AWSコンソールで確認されている"High"の脆弱性の内容がSlackに通知されました。


# さいごに

以上 Amazon Inspector v2の脆弱性検知結果を、Slackで管理できるようにしました。

御覧いただき ありがとうございました！！