AWS ConfigによるS3バケットのタグ監視 - EventBridgeとSNSで通知

# はじめに

AWSにおけるリソース管理の一環として、S3バケットに「Name」タグが適切に設定されていることを確認することは、リソースの整理や識別を容易にするために重要です。本記事では、AWS Configを用いてS3バケットのタグ付けを監視し、タグが欠如している場合にAmazon EventBridgeとAmazon SNSを利用して通知を行うインフラ構成を紹介します。これにより、不要なリソースの存在の有無を即座に検知し、迅速な対応が可能になります。


以下が作成したレポジトリーです

https://github.com/sugiyama404/practice_aws_config

参考にした記事です

https://blog.serverworks.co.jp/notice-config-noncompliant

https://repost.aws/ja/knowledge-center/config-resource-non-compliant

https://iret.media/96893

# 目的

本記事の目的は、AWS Configルールを新規作成してS3バケットの「Name」タグを監視し、タグが付与されていない場合にAmazon EventBridgeが検知し、SNSを通じてEメール通知を送信する仕組みを構築する方法を解説することです。

# インフラ構成

本構成では以下のAWSサービスを使用します：

![aws.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/f5e22831-ec01-fcbb-f2d5-d0ab1e858483.png)


+ **S3**: タグ付けの対象となるバケットをホスティングします
+ **AWS Config**: S3バケットの「Name」タグを監視するルールを設定します
+ **Amazon EventBridge**: AWS Configルールの違反を検知し、イベントを発生させます
+ **Amazon SNS**: EventBridgeからのイベントを受信し、通知を送信します

以下に各サービスの設定方法を順を追って説明します。

## 1. S3バケットの作成
S3バケットを作成し、適切なタグを設定します。タグ付けはリソースの識別に役立ちます。

## 2. AWS Configルールの作成
AWS Configを設定し、新規ルールを作成します。このルールでは、すべてのS3バケットに「Name」タグが含まれているかをチェックします。

## 3. Amazon EventBridgeの設定
AWS Configのルール違反を検知するために、Amazon EventBridgeを設定します。EventBridgeは違反を検知すると、指定されたターゲットにイベントを送信します。

## 4. Amazon SNSの設定
SNSトピックを作成し、EventBridgeからのイベントを受信するように設定します。SNSは受信したイベントに基づいてEメール通知を送信します。

# 実装方法

# S3

S3バケットを作成します。このバケットには一意の名前が付与され、タグ「Name」にアプリケーション名が含まれます。また、バケットのバージョニングを有効にします。

```terraform:infra/modules/s3/aws_s3_bucket.tf
resource "aws_s3_bucket" "main" {
  bucket        = "main-${random_string.s3_unique_key.result}"
  force_destroy = true

  tags = {
    Name = "${var.app_name}-main"
  }
}

resource "random_string" "s3_unique_key" {
  length  = 10
  upper   = false
  lower   = true
  numeric = true
  special = false
}
```

次に、バケットのバージョニングを有効にするための設定を行います。

```terraform:infra/modules/s3/aws_s3_bucket_versioning.tf
resource "aws_s3_bucket_versioning" "versioning" {
  bucket = aws_s3_bucket.main.id
  versioning_configuration {
    status = "Enabled"
  }
}
```

# iam

AWS Config用のIAMロールを作成します。このロールにはAWS Configサービスがアサインできるようにするためのポリシーが含まれています。

```terraform:infra/modules/iam/aws_iam_role.tf
resource "aws_iam_role" "config_role" {
  name = "config-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "config.amazonaws.com"
        }
      }
    ]
  })
  tags = {
    Name = "${var.app_name}-iam-role-for-config"
  }
}
```

次に、このロールに必要な権限を付与するためのIAMポリシーを作成します。

```terraform:infra/modules/iam/aws_iam_policy.tf
resource "aws_iam_policy" "config_role_policy" {

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "s3:*",
          "sns:*",
          "config:*",
          "cloudwatch:*",
          "events:*"
        ]
        Effect   = "Allow"
        Resource = "*"
      }
    ]
  })
}
```

最後に、作成したIAMポリシーをIAMロールにアタッチします。

```terraform:infra/modules/iam/aws_iam_policy_attachment.tf
resource "aws_iam_policy_attachment" "config_attach" {
  name       = "${var.app_name}-ecr-attach"
  roles      = ["${aws_iam_role.config_role.name}"]
  policy_arn = aws_iam_policy.config_role_policy.arn
}
```

次に、AWS Configルール、Amazon EventBridge、およびAmazon SNSの設定方法を順を追って説明します。これにより、S3バケットに「Name」タグが欠如している場合に通知を受け取る仕組みを構築します。

# Config

AWS Configを使用して、S3バケットのタグ付けを監視し、不足している場合に通知を受ける方法を以下に示します。

まず、AWS Configルールを使用してS3バケットのタグ付けを監視するための設定を行います。

```terraform:infra/modules/config/aws_config_config_rule.tf
resource "aws_config_config_rule" "s3_bucket_tag" {
  name = "required-tags"

  source {
    owner             = "AWS"
    source_identifier = "REQUIRED_TAGS"
  }

  scope {
    compliance_resource_types = [
      "AWS::S3::Bucket"
    ]
  }

  input_parameters = jsonencode({
    tag1Key = "Name",
  })
}
```

次に、AWS Configの設定記録機能を有効にします。これにより、リソースの設定の変更やコンプライアンスの評価結果を記録し、後で分析やレポートを生成することが可能になります。

```terraform:infra/modules/config/aws_config_configuration_recorder_status.tf
resource "aws_config_configuration_recorder_status" "main" {
  name       = aws_config_configuration_recorder.main.name
  is_enabled = true
  # Configuration Recorder と Delivery Channel への依存関係を設定
  depends_on = [
    aws_config_configuration_recorder.main,
    aws_config_delivery_channel.config_channel
  ]
}
```

次に、AWS Configの設定記録機能を有効にします。これにより、リソースの設定の変更やコンプライアンスの評価結果を記録し、後で分析やレポートを生成することが可能になります。

```terraform:infra/modules/config/aws_config_configuration_recorder.tf
resource "aws_config_configuration_recorder" "main" {
  name     = "main"
  role_arn = var.iam_role_arn_for_config

  recording_group {
    all_supported                 = true
    include_global_resource_types = true
  }
}
```

設定記録データを配信するためのAWS Config配信チャネルを設定します。

```terraform:infra/modules/config/aws_config_delivery_channel.tf
resource "aws_config_delivery_channel" "config_channel" {
  name           = "config-delivery-channel"
  s3_bucket_name = var.s3_bucket_id

  depends_on = [aws_config_configuration_recorder.main]
}
```

AWS Configを使用してS3バケットのタグ付けを監視し、不足している場合に通知を受ける設定手順を説明しました。これにより、運用上のタグ付けルールの遵守を自動化し、リソース管理を効率化することが可能です。

# event bridge

Amazon EventBridgeを使用して、AWS Configルールの準拠状態の変更を監視し、通知を設定する方法を以下に示します。

まず、CloudWatchイベントルールを使用してAWS Configルールの準拠状態の変更をトリガーする設定を行います。

```terraform:infra/modules/eventbridge/aws_cloudwatch_event_rule.tf
resource "aws_cloudwatch_event_rule" "config_rule_compliance" {
  name        = "config-rule-compliance"
  description = "Event rule for AWS Config compliance"
  event_pattern = jsonencode({
    "source" : ["aws.config"],
    "detail-type" : ["Config Rules Compliance Change"],
    "detail" : {
      "messageType" : ["ComplianceChangeNotification"],
      "configRuleName" : [var.config_rule_s3_bucket_tag_name]
    }
  })

  tags = {
    Name = "sns-event"
  }
}
```

参考記事です。

https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/how-does-config-work.html

次に、CloudWatchイベントルールがトリガーされた際に実行されるアクションを設定します。ここでは、Amazon SNSを通じて通知を送信する設定を行います。

```terraform:infra/modules/eventbridge/aws_cloudwatch_event_target.tf
resource "aws_cloudwatch_event_target" "sns" {
  rule      = aws_cloudwatch_event_rule.config_rule_compliance.name
  target_id = "sendToSNS"
  arn       = var.sns_topic_arn

  input_transformer {
    input_paths = {
      "detail-type"    = "$.detail-type",
      "source"         = "$.source",
      "time"           = "$.time",
      "region"         = "$.region",
      "configRuleName" = "$.detail.configRuleName",
      "messageType"    = "$.detail.messageType",
    }

    input_template = <<TEMPLATE
{
  "message": "Config rule violation detected:",
  "Detail-type Type": "<detail-type>",
  "Source": "<source>",
  "Time": "<time>",
  "Region": "<region>",
  "Config Rule Name": "<configRuleName>",
  "Message Type": "<messageType>"
}
TEMPLATE

  }
}
```

Amazon EventBridgeを使用してAWS Configルールの準拠状態の変更を監視し、Amazon SNSを通じて通知を設定する手順を説明しました。これにより、AWS環境でのコンプライアンスの変更をリアルタイムで把握し、適切な対応を迅速に行うことが可能です。

入力トランスフォーマの参考記事です。

https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-transform-target-input.html

# SNS

Amazon SNSを使用して、Eメール通知を設定する方法を以下に示します。

まず、Amazon SNSトピックを作成します。このトピックは通知の送信先となります。

```terraform:infra/modules/sns/aws_sns_topic.tf
resource "aws_sns_topic" "sns_topic" {
  name = "email_topic"

  tags = {
    "Name" = "${var.app_name}-email_topic"
  }
}
```

次に、SNSトピックにEメールサブスクリプションを追加します。これにより、指定したEメールアドレスに通知が送信されます。

```terraform:infra/modules/sns/aws_sns_topic_subscription.tf
resource "aws_sns_topic_subscription" "email_subscription" {
  topic_arn = aws_sns_topic.sns_topic.arn
  protocol  = "email"
  endpoint  = trimspace(file("${path.module}/src/email.txt"))
}
```

Amazon SNSを使用してEメール通知を設定する手順を説明しました。これにより、AWS環境での重要なイベントやアラートを適切な形で通知し、運用や問題解決の効率化を図ることが可能です。

# 結果

以下のメールが届きました。

![mail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/70418a3c-74d7-c065-e6b0-687c271ce66f.png)

# まとめ

AWS Configを使用してS3バケットの「Name」タグを監視し、タグの欠如を検知した場合にAmazon EventBridgeとAmazon SNSを利用して通知を行うインフラを構築する方法を解説しました。この構成により、タグ付けの不備を早期に発見し、適切な対処が可能となります。今後の運用においても、AWSのサービスを効果的に活用し、リソース管理を効率化することが期待されます。