AWS GuardDutyで実現するVPC内通信の包括的脅威検知
目的
• VPC内通信の不正アクセスをリアルタイムで検知
セキュリティパイプラインの現状
| No. | サービス | 目的 | 
|---|---|---|
| 1 | Amazon GuardDuty | 脅威検知(VPC Flow Logs + 脅威インテリジェンス) | 
| 2 | EventBridge | アラート通知(Slack連携) | 
| 3 | Amazon Detective | インシデント調査・フォレンジック | 
| 4 | Security Lake | 長期保存・相関分析 | 
VPC Flow Logsの監視対象通信
1. 内部通信
• 同一/異なるサブネット間のEC2通信
• すべてのプロトコル(TCP/UDP/ICMP等)のプライベートIP間通信
2. 外部通信
• Internet Gateway経由の通信
• NAT Gateway経由のインターネットアクセス
• Elastic IP宛の着信通信
3. AWS サービス連携
• VPCエンドポイント(Interface/Gateway)経由の通信
• ロードバランサー関連トラフィック
• マネージドサービス(Lambda/EKS/RDS等)のENI通信
4. ハイブリッド接続
• VPN/Direct Connect経由のオンプレミス通信
• VPCピアリングによるVPC間通信
• Transit Gateway経由の通信
GuardDuty中心の検知アーキテクチャ
データソースと検知内容
| データソース | 主な検知内容 | 特徴 | 
|---|---|---|
| VPC Flow Logs | ・不審な外部通信 ・ポートスキャン ・異常な通信パターン  | 
ネットワークレベルの脅威検知 | 
| CloudTrail | ・権限昇格 ・設定変更 ・異常なAPI呼び出し  | 
管理アクションの監視 | 
| DNS クエリ | ・C2通信 ・DNSトンネリング ・DGAドメインアクセス  | 
マルウェア活動の早期発見 | 
| EKS 監査ログ | ・コンテナ環境の異常 ・権限昇格 ・不正アクセス  | 
コンテナセキュリティ | 
追加検討オプション
Malware Protection for S3
- コスト目安(1TBのS3バケットの場合):
- 初回フルスキャン:約¥1,024(一回限り)
 - 月間運用コスト:
- 低更新率(5%/月):約¥51/月
 - 中更新率(10%/月):約¥102/月
 - 高更新率(20%/月):約¥205/月
 
 - 年間運用コスト:
- 低更新率:約¥612/年
 - 中更新率:約¥1,224/年
 - 高更新率:約¥2,460/年
 
 
 
検知から対応までのフロー
- GuardDutyによる自動検知
 - EventBridgeによるSlack通知
 - Detectiveを用いた原因調査
 - 必要に応じた対応アクション実行
 
主な検知シナリオ
• 不正アクセス:ブルートフォース攻撃、権限昇格
• データ漏洩:異常な大量データ転送、不審な外部通信
• マルウェア活動:C2通信、暗号通貨マイニング
• 設定ミス悪用:過剰な権限、公開設定の悪用
GuardDutyセキュリティ監視システムの要件
1. 基本的な監視要件
• GuardDuty検出器を有効化し、セキュリティ脅威の検出を行う
• 検出結果の公開頻度を6時間ごとに設定
• すべての重要度の検出結果を監視対象とする
2. データソース監視要件
• S3ログの監視を有効化
• EC2インスタンスのマルウェア保護(EBSボリュームスキャン)を有効化
3. 通知要件
• GuardDutyの検出結果をSNSトピック「guardduty-finding」に送信
• 検出結果をメールアドレス「xxxxx@xxxxx.com」に通知
• Slack通知の準備
4. イベント検知要件
• GuardDutyのすべての検出結果を検知するEventBridgeルールを設定
• GuardDuty検出結果のアーカイブ操作(ArchiveFindings、UpdateFindingsFeedback)も検知
5. 権限要件
• EventBridgeからSNSトピックへの発行権限を持つIAMロールを設定
• 適切な権限分離とセキュリティポリシーの適用
6. 運用要件
• 検出結果の管理(アーカイブ操作の追跡)
• 検出結果の通知システムの構築
• セキュリティイベントへの迅速な対応体制の整備
シーケンス図
Terraform設計
main.tf
# GuardDuty検出器の設定
resource "aws_guardduty_detector" "xxxxx" {
  enable                       = true
  finding_publishing_frequency = "SIX_HOURS"
  datasources {
    kubernetes {
      audit_logs {
        enable = false
      }
    }
    malware_protection {
      scan_ec2_instance_with_findings {
        ebs_volumes {
          enable = true
        }
      }
    }
    s3_logs {
      enable = true
    }
  }
}
# EventBridgeからSNSへの権限を持つIAMロール
resource "aws_iam_role" "eventbridge_to_sns" {
  name = "eventbridge_to_sns"
  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [{
      Effect    = "Allow",
      Principal = { Service = "events.amazonaws.com" },
      Action    = "sts:AssumeRole"
    }]
  })
}
# SNSトピックへの発行権限を定義するポリシードキュメント
data "aws_iam_policy_document" "publish_sns" {
  statement {
    sid    = "AllowPublishToGuarddutyFindingTopic"
    effect = "Allow"
    actions = [
      "sns:Publish"
    ]
    resources = [
      "arn:aws:sns:ap-northeast-1:${data.aws_caller_identity.current.account_id}:guardduty-finding"
    ]
  }
}
# SNS発行権限のIAMポリシー
resource "aws_iam_policy" "publish_sns" {
  name   = "EventBridgePublishGuarddutyFinding"
  policy = data.aws_iam_policy_document.publish_sns.json
}
# IAMポリシーをロールにアタッチ
resource "aws_iam_policy_attachment" "attach" {
  name       = "attach-eb-sns"
  roles      = [aws_iam_role.eventbridge_to_sns.name]
  policy_arn = aws_iam_policy.publish_sns.arn
}
# GuardDuty検出結果通知用SNSトピック
resource "aws_sns_topic" "guardduty_finding" {
  name         = "guardduty-finding"
  display_name = "put-slack"
  fifo_topic   = false
  tags = {
    Name = "guardduty-finding"
  }
}
# SNSトピックのメール通知設定
resource "aws_sns_topic_subscription" "email" {
  endpoint                        = "xxxxx@xxxxx.com"
  protocol                        = "email"
  topic_arn                       = aws_sns_topic.guardduty_finding.arn
  confirmation_timeout_in_minutes = 1
  endpoint_auto_confirms          = false
  raw_message_delivery            = false
}
# GuardDutyアーカイブAPI呼び出しを検知するルール
resource "aws_cloudwatch_event_rule" "gdu_finding_archive_api" {
  name           = "gdu-finding-archive-api"
  description    = "Notify when a GuardDuty finding is archived (API call)"
  event_bus_name = "default"
  state          = "ENABLED"
  event_pattern = jsonencode({
    source      = ["aws.guardduty"]
    detail-type = ["AWS API Call via CloudTrail"]
    detail = {
      eventSource = ["guardduty.amazonaws.com"]
      eventName   = ["ArchiveFindings", "UpdateFindingsFeedback"]
    }
  })
}
# GuardDutyの全検出結果を受け取るルール
resource "aws_cloudwatch_event_rule" "guardduty_finding" {
  name           = "guardduty-finding"
  description    = "GuardDutyのすべての検出結果(全重要度)をSNSトピックに送信"
  event_bus_name = "default"
  state          = "ENABLED"
  event_pattern = jsonencode({
    source      = ["aws.guardduty"]
    detail-type = ["GuardDuty Finding"]
  })
}
# アーカイブ検知をSNSトピックに送るターゲット
resource "aws_cloudwatch_event_target" "guardduty_archive_to_sns" {
  rule      = aws_cloudwatch_event_rule.gdu_finding_archive_api.name
  target_id = "guardduty-archive-notification"
  arn       = "arn:aws:sns:ap-northeast-1:${data.aws_caller_identity.current.account_id}:guardduty-finding"
  role_arn  = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/eventbridge_to_sns"
}
# 全検出結果をSNSトピックに送るターゲット
resource "aws_cloudwatch_event_target" "guardduty_finding" {
  rule      = aws_cloudwatch_event_rule.guardduty_finding.name
  target_id = "guardduty-finding"
  arn       = "arn:aws:sns:ap-northeast-1:${data.aws_caller_identity.current.account_id}:guardduty-finding"
  role_arn  = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/eventbridge_to_sns"
}
検知アラート


Discussion