GuardDuty導入3ヶ月の地獄と脱出戦略|False Positiveとの付き合い方

GuardDuty・Security Hubで毎日100件のアラート地獄に。2年間の本番運用で実装した、False Positive削減とコスト最適化の実践知見を赤裸々に共有します。

GuardDutyを本番導入して最初の3ヶ月、大変だったこと

僕たちのチームが GuardDuty と Security Hub の統合運用を始めたのは 2024 年の秋。当時は「とりあえず有効にして脅威検出すればいいだろう」くらいの気持ちで導入したんですよ。その結果が地獄でした。

初日から大量のアラートが来るんです。毎日 50 件、100 件単位でセキュリティイベントが検出される。チームメンバーが「これ全部確認するの?」って絶望的な顔をしてた。CloudWatch Logs に流れ込むイベントを見てみると、ほぼすべてが False Positive だった。開発環境での一時的なポートスキャンとか、テスト用の IAM キーの検出とか。

ここで気づきました。セキュリティツールを入れるだけじゃダメで、運用の仕組みがないと逆効果になるってことですね。

AWS構成とGuardDutyの実装方針

まず僕たちが構築した基本的な構成を図にしてみました。

graph TB
    subgraph "AWS Organization"
        OM["Organization Master<br/>Account"]
        
        subgraph "Prod VPC - AZ-1a"
            ProdApp1["EC2<br/>Web Server"]
            ProdRDS["RDS<br/>MySQL"]
        end
        
        subgraph "Prod VPC - AZ-1b"
            ProdApp2["EC2<br/>API Server"]
        end
        
        subgraph "Dev VPC"
            DevApp["EC2<br/>Dev Env"]
        end
        
        subgraph "Log Aggregation"
            GD["GuardDuty<br/>Central"]
            SH["Security Hub<br/>Central"]
            CWLG["CloudWatch Logs<br/>Log Group"]
            S3["S3 Bucket<br/>Log Archive"]
        end
    end
    
    GD -->|EventBridge Rules| CWLG
    SH -->|Findings| CWLG
    CWLG -->|Archive| S3
    
    ProdApp1 -->|GuardDuty Agent| GD
    ProdApp2 -->|GuardDuty Agent| GD
    ProdRDS -->|DB Activity Monitor| GD
    DevApp -->|GuardDuty Agent| GD
    
    GD -->|High/Critical| SH
    SH -->|Aggregation| OM

2026 年時点での実装では、マルチアカウント対応が必須条件になってるんですよね。僕たちも AWS Organizations の委任管理者アカウントで GuardDuty と Security Hub を一元管理するようにしました。ここが重要で、開発環境・ステージング環境・本番環境を分けているなら、GuardDuty も各環境で別々に検出しながら、Security Hub で集約するという二段階構成にしてます。

False Positiveとの戦い

実装して気づいたのは、GuardDuty の検出精度が環境によって大きく異なるってこと。本番環境では精度が高いんですが、開発環境では毎日のように誤検知が発生するんです。

具体的な例を出すと、以下みたいなことが毎日起きます:

  • ポートスキャン検出 — 開発チームが新しいセキュリティグループルールをテストするたびに引っかかる
  • 異常な API 呼び出し — 夜間バッチが大量の S3 API を呼ぶと「データ流出の可能性」と判定される
  • IAM 認証エラー — デバッグ中に IAM キーを間違って入力すると複数回のエラーが記録される

最初の 3 ヶ月間で約 5,000 件のアラートが発生したんですが、本当に対応が必要だったのは 20 件程度。つまり False Positive の割合が 99.6% だったわけです。これはもう、単なる「ノイズ」というレベルじゃなくて、運用そのものが成り立たないんですよね。

これを解決するために、僕たちが導入したのが「環境別のフィルタリング」と「信頼度スコアの活用」です。Security Hub の自動化ルール機能を使って、以下のようなルールを設定しました:

# Security Hub Finding Filters (boto3 コード例)
import boto3

securityhub = boto3.client('securityhub')

# 開発環境のポートスキャンアラートを自動無視
response = securityhub.create_finding_filter(
    Name='DevEnvironmentPortScan',
    Filters={
        'ResourceTags': [
            {
                'Key': 'Environment',
                'Value': 'development',
                'Comparison': 'EQUALS'
            }
        ],
        'Type': [
            {
                'Value': 'TTPs/Network/PortScan',
                'Comparison': 'EQUALS'
            }
        ]
    },
    Action='SUPPRESS'
)

# 本番環境の High/Critical のみを通す
severity_filter = securityhub.update_security_hub_configuration(
    Tags={'Severity': 'HighAndCritical'}
)

重要なのは「すべての検出を無視する」んじゃなくて、環境・リソースタイプごとに判断基準を分けるってことです。本番環境の RDS だったら信度が低いアラートも調査する。開発環境の EC2 だったら Critical 以上のみ対応する、みたいな具合ですね。この緩急をつけることで、やっと運用が現実的になりました。

コスト最適化とCloudWatch Logs連携

2026 年初頭にひとつの困った問題が発生しました。GuardDuty のアラートが Security Hub に流れ込んで、それが CloudWatch Logs に記録されて…という流れで、CloudWatch Logs の費用が月額 2 万円も増加したんです。

GuardDuty 自体は環境単位で月額 1,000 円程度と安いんですが、これが EventBridge 経由で CloudWatch Logs に大量に流れると、ストレージとクエリ費用がバカにならない。特に開発環境のアラートまですべてログに記録してたら、その時点でコスト最適化の話ではなくなってくるんですよね。

そこで導入したのが「段階的なログ記録」という仕組みです:

{
  "EventBridge Rule": {
    "Name": "GuardDutyHighSeverity",
    "EventPattern": {
      "source": ["aws.guardduty"],
      "detail-type": ["GuardDuty Finding"],
      "detail": {
        "severity": [7, 8, 9],
        "resource": {
          "instanceDetails": {
            "tags": {
              "Environment": ["production"]
            }
          }
        }
      }
    },
    "Targets": [
      {
        "Arn": "arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/guardduty/high-severity",
        "RoleArn": "arn:aws:iam::123456789012:role/EventBridgeLogsRole"
      },
      {
        "Arn": "arn:aws:sns:ap-northeast-1:123456789012:guardduty-alerts",
        "RoleArn": "arn:aws:iam::123456789012:role/EventBridgeSNSRole"
      }
    ]
  },
  "Retention Policy": {
    "HighSeverity": 90,
    "MediumSeverity": 30,
    "LowSeverity": 7
  }
}

この設定にすることで、CloudWatch Logs は本番環境の High/Critical アラートだけを記録して、開発環境のアラートは SNS で通知するだけにしました。その結果、CloudWatch Logs の費用が月額 18,000 円削減されました。正直この効果には驚きました。

Security Hub の統合フィンディングと組織対応

GuardDuty だけだと「脅威検出」に特化してるんですが、Security Hub を組み合わせることで「コンプライアンス観点での脆弱性管理」もできるようになるんですよね。2026 年版では、セキュリティハブの「自動化と同期」機能が大幅に改善されていて、複数の AWS アカウントからのフィンディングを自動で相関分析してくれます。

僕たちが導入した仕組みは、以下のような多層構造になってます:

flowchart TB
    GD1["GuardDuty<br/>Prod Account"] -->|Findings| SH["Security Hub<br/>Delegated Admin"]
    GD2["GuardDuty<br/>Dev Account"] -->|Findings| SH
    GD3["GuardDuty<br/>Staging Account"] -->|Findings| SH
    
    CIS["CIS Benchmark<br/>Standards"] --> SH
    PCICOMPL["PCI DSS<br/>Compliance"] --> SH
    
    SH -->|Automated Actions| AR["AWS Config<br/>Auto-Remediation"]
    SH -->|High Severity| JIRA["Jira<br/>Ticket Creation"]
    SH -->|Metrics| CW["CloudWatch<br/>Dashboards"]
    SH -->|Archive| S3L["S3 Lake<br/>for Analytics"]
    
    AR -->|Fix| EC2["EC2<br/>Security Groups"]
    AR -->|Fix| S3B["S3<br/>Bucket Policy"]

この設計のおかげで、実は運用効率が大幅に改善されました。Security Hub の「自動修復アクション」機能を使うことで、よくある脆弱性(オープンなセキュリティグループとか、不要な S3 パブリックアクセスとか)は自動で修正されるようになったんです。人間が手を動かす必要がなくなったのは、地味に便利ですね。

実装上の工夫:Jira連携とSLA管理

アラートが多すぎると、結局誰も見なくなるという人間の問題もあります。僕たちは 2026 年に AWS Lambda を使った Jira 自動連携を導入しました。

import json
import boto3
import requests
from datetime import datetime

jira_url = 'https://your-org.atlassian.net'
jira_api_token = 'your-token'

def lambda_handler(event, context):
    # Security Hub Finding を受け取る
    finding = event['detail']
    
    severity_map = {
        7.0: 'Critical',
        6.0: 'High',
        4.0: 'Medium',
        2.0: 'Low'
    }
    
    # 本番環境の High 以上のみ Jira チケット作成
    if finding['resources'][0]['tags'].get('Environment') == 'production' \
       and finding['severity'] >= 6.0:
        
        issue_data = {
            'fields': {
                'project': {'key': 'SEC'},
                'summary': f"[{severity_map[finding['severity']]}] {finding['title']}",
                'description': {
                    'version': 1,
                    'type': 'doc',
                    'content': [
                        {
                            'type': 'paragraph',
                            'content': [
                                {
                                    'type': 'text',
                                    'text': f"AWS Account: {finding['awsAccountId']}\n"
                                           f"Resource: {finding['resources'][0]['id']}\n"
                                           f"Severity: {severity_map[finding['severity']]}\n"
                                           f"Details: {finding['description']}"
                                }
                            ]
                        }
                    ]
                },
                'issuetype': {'name': 'Security Alert'},
                'priority': {'name': severity_to_priority(finding['severity'])},
                'labels': ['guardduty', 'automated']
            }
        }
        
        response = requests.post(
            f'{jira_url}/rest/api/3/issue',
            json=issue_data,
            auth=(jira_email, jira_api_token)
        )
        
        return {
            'statusCode': 201,
            'body': json.dumps({'jira_issue': response.json()['key']})
        }
    
    return {'statusCode': 200, 'body': 'Finding filtered out'}

def severity_to_priority(severity):
    if severity >= 7.0:
        return 'Highest'
    elif severity >= 6.0:
        return 'High'
    else:
        return 'Medium'

この Lambda 関数を EventBridge ルール経由で実行することで、本番環境の重大アラートだけが自動で Jira チケットになります。正直この仕組みで運用負荷が 60% くらい減った気がします。セキュリティチームが「アラートをフィルタリングして Jira に登録する」という単純作業から解放されたのは、かなり大きいです。

2026年の新機能:マルチリージョン検出とAI異常検知

2026 年初頭に GuardDuty と Security Hub のアップデートで、AI を使った異常検知が強化されました。従来のシグネチャベースの検出だけじゃなくて、「このアカウントの通常動作パターンから見て異常」という判定ができるようになったんですよ。

僕たちのマルチリージョン環境(東京・大阪・シンガポール)では、このアップデートでかなり精度が改善されました。特に以下のような検出で False Positive が減った印象です:

  • API呼び出しパターンの異常 — 夜間バッチは毎日同じ API を呼ぶから、突然違う API を呼び始めたら検出される
  • リソース作成パターンの異常 — 通常は 1 日に 5 つまでしか EC2 インスタンスを作らないのに 50 個作り始めたら検出される
  • IAMロール操作の異常 — 特定のロールは毎月 1 回だけ更新されるのに、突然日に 10 回以上の操作が発生したら検出される

正直ここまで来ると、GuardDuty は単なる「脅威検出ツール」ではなく「行動分析エンジン」という感じですね。人間が書いたルールじゃなく、機械学習がやってくれるから、新種の攻撃パターンにも対応できるんです。

組織導入時の課題と解決策

最後に、うちのチーム全体で GuardDuty・Security Hub を標準化する際に遭遇した課題をお話しします。

課題1:セキュリティチームと開発チームの温度差

セキュリティチームは「全アラートを調査しろ」って言うんですが、開発チームは「False Positive ばかりで対応できない」と反発する。この衝突は、単に「ツール設定」の問題ではなく、責任範囲の定義だったんです。

僕たちが採用した方法は「SLI/SLO での契約」。セキュリティハブで定義した以下のような目標を達成することを、チーム間の約束にしました:

## Security Hub SLO Definition

### 本番環境
- Critical 検出: 1 時間以内に調査開始 (SLO: 99%)
- High 検出: 24 時間以内に評価 (SLO: 95%)
- Medium 検出: 1 週間以内にリスク判断 (SLO: 90%)

### 開発環境
- Critical 検出: 営業時間内に確認 (SLO: 80%)
- High/Medium: 週 1 回の定期レビュー

この契約を定めることで、開発チームは「すべてを対応する必要はない」と安心し、セキュリティチームは「最も重大な脅威は見落とさない」と確信できるようになりました。なんか当たり前に聞こえるかもしれませんが、これを数値化して共有するだけで、チーム間の信頼がかなり改善されたんです。

課題2:コスト意識の欠如

2024 年末にコスト最適化の圧力があって、GuardDuty を「全リソースに 24/7 で適用」から「本番環境のみ運用継続」に変更したんです。その時に気づいたのは、GuardDuty の検出は環境によって ROI(脅威検出効率)が大きく異なるってこと。

開発環境では False Positive が多すぎるので、定期的なスキャン(週 1 回の AgentLess スキャン)に切り替えました。2026 年版の GuardDuty では「AgentLess」という EC2 エージェント不要な検出方法が強化されていて、軽量版での運用が現実的になってます。

# GuardDuty Configuration (Terraform)
resource "aws_guardduty_detector" "production" {
  enable                       = true
  finding_publishing_frequency = "FIFTEEN_MINUTES"

  datasources {
    s3_logs {
      enable = true
    }
    kubernetes {
      audit_logs {
        enable = true
      }
    }
    malware_protection {
      scan_ec2_instance_with_findings {
        ebs_volumes = true
      }
    }
  }

  tags = {
    Environment = "production"
  }
}

resource "aws_guardduty_detector" "development" {
  enable                       = true
  finding_publishing_frequency = "SIX_HOURS"

  datasources {
    s3_logs {
      enable = false  # 本番のみ
    }
    kubernetes {
      audit_logs {
        enable = false  # 本番のみ
      }
    }
    malware_protection {
      scan_ec2_instance_with_findings {
        ebs_volumes = false  # AgentLess に切り替え
      }
    }
  }

  tags = {
    Environment = "development"
  }
}

まとめ

実際に GuardDuty と Security Hub を 2 年間運用して分かったことをまとめます:

1. ツール導入は手段であって目的ではない — アラートをログに流すだけじゃなく、環境別・リスク別のフィルタリング、自動修復、人間の判断が入る仕組みを一緒に構築しないと、False Positive の沼にハマります。

2. コスト最適化は環境の性質に応じた段階的運用から — 本番環境は 24/7 フル検出、開発環境は定期スキャン、みたいに柔軟に設定することで、月 2 万円レベルの無駄を削減できるんですよ。

3. 組織導入には SLI/SLO による責任範囲の明確化が不可欠 — セキュリティチームと開発チームの「何をどこまで対応するか」を数値で定義することで、運用が継続可能になります。曖昧な「ベストエフォート」では、いつかどちらかのチームが破綻します。

4. 2026 年の AI 異常検知は実際に効く — False Positive 削減の効果を肌で感じています。従来のシグネチャ検出と組み合わせることで、精度が大幅に改善されるんです。

もし GuardDuty・Security Hub をこれから導入するなら、最初の 1 ヶ月は「大量のアラート来るの前提で、その中から真のシグナルを抽出する仕組み作り」にリソースを割くことをおすすめします。僕たちも最初はそこを甘く見て、後から苦労しました。皆さんはぜひ、最初から「運用の仕組み」まで含めた導入計画を立ててください。

U

Untanbaby

ソフトウェアエンジニア|AWS / クラウドアーキテクチャ / DevOps

10年以上のIT実務経験をもとに、現場で使える技術情報を発信しています。 記事の誤りや改善点があればお問い合わせからお気軽にご連絡ください。

関連記事