AWS CloudFormationを利用してGuardDutyを構築する #EventBridge

# はじめに
AWS GuardDutyは、AWSアカウントやワークロードを自動的に監視し、潜在的な脅威を検出するマネージド型の脅威検出サービスです。セキュリティ監視に役立つこのサービスは、AWSでのセキュリティ管理を効率化します。今回は、GuardDutyの構築をAWS CloudFormationを使って自動化し、さらにEventBridgeと連携することでイベント管理もシームレスに行えるようにします。

AWS CloudFormationを利用して、GuardDutyを構築するテンプレートのサンプルです。

当時、@kikutch と作業した際の内容を改良しました。

テンプレートの概要が分からない場合は、[はじめてのAWS CloudFormationテンプレートを理解する](https://qiita.com/miyabiz/items/eb7b0fa1675b5199b9b7)を参考にしてください。

今回は、akane というシステムの dev 環境を想定しています。
同じ構成で違う環境を作成する場合は、{環境名}-parameters.jsonを別途作成します。

```text:ディレクトリ構成
akane (システム)
  ├── event-bridge (スタック)
  │   ├── event-bridge.yml (CFnテンプレート)
  │   └── dev-parameters.json (dev 環境のパラメータ)
  ├── guard-duty (スタック)
  │   ├── guard-duty.yml (CFnテンプレート)
  │   └── dev-parameters.json (dev 環境のパラメータ)
  └─ sns (スタック)
      ├─ sns.yml (CFnテンプレート)
      └─ dev-parameters.json (dev 環境のパラメータ)
```

# 実行環境の準備
[AWS CloudFormationを動かすためのAWS CLIの設定](https://qiita.com/miyabiz/items/fed11796f0ea2b7608f4)を参考にしてください。

# AWS リソース構築手順
1. 下記を実行してスタックを作成

    ```
    ./create_stacks.sh
    ```

2. 下記を実行してスタックを削除

    ```
    ./delete_stacks.sh
    ```

# 構築テンプレート
**1. guard-dutyスタック**

```yaml:guard-duty.yml
AWSTemplateFormatVersion: 2010-09-09
Description: Guard Duty

# Metadata:

Parameters:
  SystemName:
    Type: String
    AllowedPattern: '[a-zA-Z0-9-]*'
  EnvType:
    Description: Environment type.
    Type: String
    AllowedValues: [all, dev, stg, prod]
    ConstraintDescription: must specify all, dev, stg, or prod.

# Mappings: 

# Conditions

# Transform

Resources:
  # GuardDuty作成
  GuardDutyDetector:
    Type: AWS::GuardDuty::Detector
    Properties:
      Enable: true
      Tags:
        - Key: Name
          Value: !Sub
          - ${SystemName}-${EnvType}-guard-duty
          - {SystemName: !Ref SystemName, EnvType: !Ref EnvType}
        - Key: SystemName
          Value: !Ref SystemName
        - Key: EnvType
          Value: !Ref EnvType
```

```json:dev-parameters.json
{
    "Parameters": [
        {
            "ParameterKey": "SystemName",
            "ParameterValue": "akane"
        },
        {
            "ParameterKey": "EnvType",
            "ParameterValue": "dev"
        }
    ]
}
```

**2. snsスタック**

```yaml:sns.yml
AWSTemplateFormatVersion: 2010-09-09
Description: SNS

# Metadata:

Parameters:
  SystemName:
    Type: String
    AllowedPattern: '[a-zA-Z0-9-]*'
  EnvType:
    Description: Environment type.
    Type: String
    AllowedValues: [all, dev, stg, prod]
    ConstraintDescription: must specify all, dev, stg, or prod.
  Endpoint:
    Type: String
  Protocol:
    Type: String

# Mappings: 

# Conditions

# Transform

Resources:
  # SNS Topic作成
  SNSTopicForGuardDuty:
    Type: AWS::SNS::Topic
    Properties:
      DisplayName: !Sub '【通知】GuardDutyが新たな脅威を検出しました'
      TopicName: !Sub
        - ${SystemName}-${EnvType}-sns-topic
        - {SystemName: !Ref SystemName, EnvType: !Ref EnvType}
      Subscription:
        - Endpoint: !Ref Endpoint
        - Protocol: !Ref Protocol
      Tags:
        - Key: Name
          Value: !Sub
          - ${SystemName}-${EnvType}-sns-topic
          - {SystemName: !Ref SystemName, EnvType: !Ref EnvType}
        - Key: SystemName
          Value: !Ref SystemName
        - Key: EnvType
          Value: !Ref EnvType

Outputs:
  SNSTopicForGuardDutyArn:
    Value: !Ref SNSTopicForGuardDuty
    Export:
      Name: !Sub
        - ${SystemName}-${EnvType}-sns-topic-arn
        - {SystemName: !Ref SystemName, EnvType: !Ref EnvType}
```

```json:dev-parameters.json
{
    "Parameters": [
        {
            "ParameterKey": "SystemName",
            "ParameterValue": "akane"
        },
        {
            "ParameterKey": "EnvType",
            "ParameterValue": "dev"
        },
        {
            "ParameterKey": "Endpoint",
            "ParameterValue": "mail@sample.com"
        },
        {
            "ParameterKey": "Protocol",
            "ParameterValue": "email"
        }
    ]
}
```

**3. event-bridgeスタック**

```yaml:event-bridge.yml
AWSTemplateFormatVersion: 2010-09-09
Description: Event Bridge

# Metadata:

Parameters:
  SystemName:
    Type: String
    AllowedPattern: '[a-zA-Z0-9-]*'
  EnvType:
    Description: Environment type.
    Type: String
    AllowedValues: [all, dev, stg, prod]
    ConstraintDescription: must specify all, dev, stg, or prod.
  State:
    Type: String
    AllowedValues: [ENABLED, DISABLED]

# Mappings: 

# Conditions

# Transform

Resources:
  # EventsRule作成
  EventsRuleGuardDuty:
    Type: AWS::Events::Rule
    Properties:
      Name: event-bridge-guard-duty
      Description: "Alert to SNS topic when find threats by GuardDuty"
      EventPattern:
        detail-type:
          - GuardDuty Finding
        source:
          - aws.guardduty
        # 深刻度が4以上のイベントのみをマッチさせる条件
        detail:
          severity:
            - numeric:
                - '>='
                - 4
      State: !Ref State
      Targets:
        - Arn:
            Fn::ImportValue: !Sub
              - ${SystemName}-${EnvType}-sns-topic-arn
              - {SystemName: !Ref SystemName, EnvType: !Ref EnvType}
          Id: CloudWatchEventsForGuardDuty
      EventBusName: default
```

```json:dev-parameters.json
{
    "Parameters": [
        {
            "ParameterKey": "SystemName",
            "ParameterValue": "akane"
        },
        {
            "ParameterKey": "EnvType",
            "ParameterValue": "dev"
        },
        {
            "ParameterKey": "State",
            "ParameterValue": "ENABLED"
        }
    ]
}
```

**4. 実行ファイル**

```sh:create_stacks.sh
#!/bin/sh

cd `dirname $0`

SYSTEM_NAME=akane

create_stack () {
    ENV_TYPE=$1
    STACK_NAME=$2
    aws cloudformation create-stack \
    --stack-name ${SYSTEM_NAME}-${ENV_TYPE}-${STACK_NAME} \
    --template-body file://./${SYSTEM_NAME}/${STACK_NAME}/${STACK_NAME}.yml \
    --cli-input-json file://./${SYSTEM_NAME}/${STACK_NAME}/${ENV_TYPE}-parameters.json

    aws cloudformation wait stack-create-complete \
    --stack-name ${SYSTEM_NAME}-${ENV_TYPE}-${STACK_NAME}
}

create_stack dev guard-duty
create_stack dev sns
create_stack dev event-bridge

exit 0
```

```sh:delete_stacks.sh
#!/bin/sh

cd `dirname $0`

SYSTEM_NAME=akane

delete_stack () {
    ENV_TYPE=$1
    STACK_NAME=$2
    aws cloudformation delete-stack \
    --stack-name ${SYSTEM_NAME}-${ENV_TYPE}-${STACK_NAME}

    aws cloudformation wait stack-delete-complete \
    --stack-name ${SYSTEM_NAME}-${ENV_TYPE}-${STACK_NAME}
}

delete_stack dev event-bridge
delete_stack dev sns
delete_stack dev guard-duty

exit 0
```

# さいごに
この記事が、AWS環境でのGuardDutyの導入やCloudFormationの自動化に役立てば幸いです。ぜひ皆さんもGuardDutyを活用し、AWS環境のセキュリティを向上させましょう。