GuardDuty運用3ヶ月、毎日3000件アラートの地獄から脱出した話

GuardDutyで毎日5000件のアラート地獄に陥った実体験。False Positive対策とホワイトリスト設計で、実務レベルの運用設計を解説します。

GuardDutyを有効化したら地獄が始まった

うちのチーム、先月GuardDutyとSecurity Hubを全本番環境で有効化したんですよ。

最初の週だけで、アラートが毎日3000件以上来始めて。タスク作成されたり、Slackに流れてくるたびにチーム中がパニック状態。正直、導入を後悔しました。

「セキュリティはやっぱ大事だから、ちゃんと対応しよう」という建前で始まったんですが、実際に開けてみたら大半がfalse positiveなんです。ローカルDBへの接続試行、開発環境のRDP試行、Lambdaログの正常な例外。こういうのが「potentially malicious activity detected」と判定されるわけですよ。

3ヶ月本番で運用した結果、見えてきたのは「GuardDutyは導入じゃなく、運用設計で全てが決まる」ということでした。

最初の失敗:抑止のない有効化

実装初期、うちが踏んだ地雷を赤裸々に話します。

GuardDutyは有効化するだけで、即座に現在のAWS環境を分析し始めます。CloudTrail、VPCフローログ、DNS ログの3つのデータソースを組み合わせて、不正なアクティビティを検知するんですね。

ですが「どのアラートが本当か、ガセか判定する戦略なしに有効化したら、それはカオスでしかない」ということを身をもって学びました。

初期段階でやるべきだったことは以下の3つです。

1. Trusted IP Listの作成

開発環境、スキャン用インスタンス、定期バッチ処理といった「既知の正常なアクティビティ」をホワイトリスト化する。うちの場合、AWS内部のスキャンツール(Qualysとか)が毎日数百のポートスキャンを実行してたんですが、これをTrusted IPに登録することで劇的に減りました。

{
  "TrustedIPList": {
    "S3Bucket": "s3://my-guardduty-config/trusted-ips.txt",
    "Format": "PLAINTEXT"
  },
  "IPs": [
    "10.0.0.0/8",        // Internal VPC
    "203.0.113.45/32",   // Qualys Scanner
    "203.0.113.46/32"    // Tenable Nessus
  ]
}

2. Threat Intel Feedの精査

GuardDutyが使用する脅威インテリジェンスフィードは、AWS独自のものと複数のパートナーから集約されてるんですが、企業によって「本当に脅威か」の定義は違うんですよね。

うちの場合、某大手SaaS企業のIPがfeed登録されてて、正当な業務用接続が全部flagされてた。こういう誤検知は、フィード選択で対応できます。

3. Suppression Rulesの事前構築

これが実装の肝ですね。GuardDutyのSuppression Rulesを使うと、特定の条件のアラートを自動で抑止できます。

{
  "Name": "Suppress-Lambda-Exceptions",
  "Criterion": {
    "Type": "FINDING_TYPE",
    "Value": "UnauthorizedAccess:IAMUser/PermissionDenied"
  },
  "ResourceFilters": {
    "AccountId": ["123456789012"],
    "Tags": {
      "Environment": ["development"]
    }
  },
  "Active": true
}

最初は「抑止したら脅威見落とすんじゃ?」って抵抗ありました。でも現実は逆。ノイズが多すぎると、本当の脅威が埋まるんです。人間の注意力はリソース制約があるんですよね。

AWS構成図:マルチアカウント下でのGuardDuty・Security Hub配置

実装した構成を図解します。

graph TB
    subgraph "Organization (Central)"
        ODH["🛡️ GuardDuty Delegated Admin<br/>Account"] 
        OSH["📊 Security Hub Delegated Admin<br/>Account"]
        CVPC["VPC - Central Monitoring"]
        CVPC -->|CloudTrail Events| ODH
        CVPC -->|VPC Flow Logs| ODH
    end
    
    subgraph "Production Account"
        PPVPC["VPC - Prod"] 
        PEC2["EC2 Instances"]
        PS3["S3 Buckets"]
        PPVPC -->|VPC Flow Logs| ODH
        PEC2 -->|CloudTrail| ODH
        PS3 -->|CloudTrail| ODH
    end
    
    subgraph "Development Account"
        DPVPC["VPC - Dev"]
        DEC2["EC2 Dev"]
        DPVPC -->|VPC Flow Logs| ODH
        DEC2 -->|CloudTrail| ODH
    end
    
    subgraph "Security Hub Aggregation"
        SHCONSOLE["Security Hub Console<br/>Findings Aggregated"]
        OSH -->|Findings| SHCONSOLE
    end
    
    ODH -->|Exports| S3EXPORT["S3 Export Bucket<br/>findings.jsonl"]
    ODH -->|SNS Alerts| SNS["SNS Topic<br/>Critical Findings"]
    SNS -->|Email/Slack| SOCEMAIL["SOC Team Notification"]
    
    S3EXPORT -->|Athena Query| ATHENA["🔍 Athena Analysis<br/>Custom Queries"]
    ATHENA -->|Grafana Dashboard| GRAFANA["📈 Grafana<br/>Visualization"]
    
    SHCONSOLE -->|Remediation Rules| REMEDIATE["⚙️ Lambda Remediation<br/>Auto-Fix Logic"]
    REMEDIATE -->|Update| PPVPC
    
    style ODH fill:#ff9999
    style OSH fill:#99ccff
    style SHCONSOLE fill:#99ff99
    style REMEDIATE fill:#ffcc99

この構成のポイントをまとめると:

  • **中央アカウント(Delegated Admin)**にGuardDutyとSecurity Hubの管理を一元化することで、複数アカウントの統一的な運用が実現
  • マルチアカウント配下の全EC2/S3から自動的にCloudTrail・VPCフローログを集約するので、見落としがない
  • Finding exportをS3に流して、Athenaで長期分析できるから、トレンド把握が容易に
  • 自動remediation LambdaでIAM権限エラーや不適切なセキュリティグループ設定を自動修正する仕組みを用意

アラート5000件の地獄から脱出した3つの工夫

1. 重大度別のしきい値調整

GuardDutyのFinding Type Filteringを活用して、本当に必要なものだけを検知対象にします。

import boto3

client = boto3.client('guardduty', region_name='ap-northeast-1')

# 重大度 HIGH 以上のみ抑止ルールから除外
finding_criteria = {
    'Criterion': {
        'severity': {
            'Gte': 7  # 7以上 = HIGH/CRITICAL
        },
        'type': {
            'Eq': ['UnauthorizedAccess:EC2/RDPBruteForce',
                   'CryptoCurrency:EC2/BitcoinTool',
                   'Trojan:EC2/PhishingDomain']
        },
        'region': {
            'Eq': ['ap-northeast-1', 'us-east-1']
        }
    }
}

# Suppression Rule作成
response = client.create_filter(
    DetectorId='detector-xxx',
    Name='Critical-Findings-Only',
    Description='Suppress non-critical findings',
    Action='ARCHIVE',
    FindingCriteria=finding_criteria
)

実装して2週間で、対応が必要なアラートは1日50件程度に落ち着きました。それまでは毎日3000件だったんで、圧倒的な改善ですね。

2. Security HubとGuardDutyの統合分析

Security Hubは複数のセキュリティサービスの結果を集約するんですが、GuardDutyとの相乗効果が地味に大きいんですよ。

うちが設定した統合フローはこんな感じです:

GuardDuty Findings

 Security Hub (Standards Compliance Check)

 Automation (EventBridge + Lambda)

 Auto-Remediation / Manual Review Queue

Security Hubの「Controls」機能で、CIS AWS Foundations Benchmarkのコンプライアンスを自動チェック。GuardDutyで脅威検知、Security Hubで「今のセキュリティ設定が適切か」を並行確認する感じです。

# Security Hub Findings を Athena で分析
import boto3

athena = boto3.client('athena')

query = """
SELECT 
    created_at,
    finding_type,
    severity,
    resource_id,
    COUNT(*) as incident_count
FROM security_hub_findings
WHERE created_at > date_format(current_date - interval '7' day, '%Y-%m-%d')
    AND severity IN ('HIGH', 'CRITICAL')
GROUP BY created_at, finding_type, severity, resource_id
ORDER BY incident_count DESC
"""

response = athena.start_query_execution(
    QueryString=query,
    QueryExecutionContext={'Database': 'security_logs'},
    ResultConfiguration={'OutputLocation': 's3://my-athena-results/'}
)

3ヶ月運用してわかったこと:GuardDuty単体では検知、Security Hubは可視化・コンプライアンス確認と役割を分けるのが正解です。

3. Slackへのインテリジェント通知設計

最初、全findingをSlackに流してました。結果、通知が多すぎてスルーされるようになった。まさに狼少年状態ですね。

そこで実装したのが、重大度・リソースタイプ・時間帯ごとに通知方法を変える仕組みです:

import json
import boto3
from datetime import datetime

slack_client = boto3.client('secretsmanager')
sns = boto3.client('sns')

def lambda_handler(event, context):
    finding = json.loads(event['Records'][0]['Sns']['Message'])
    
    severity = finding['detail']['severity']
    finding_type = finding['detail']['type']
    created_time = finding['detail']['updatedAt']
    
    # 重大度に応じた通知戦略
    if severity >= 8:  # CRITICAL
        # Slack + Email + PagerDuty
        notify_to_slack(finding, channel='#security-critical', ping='@security-team')
        notify_to_email('security-critical@company.com')
        trigger_pagerduty_incident(finding)
        
    elif severity >= 6:  # HIGH
        # Slack only (business hours)
        if is_business_hours(created_time):
            notify_to_slack(finding, channel='#security-alerts')
        else:
            # After hours: Queue for next business day review
            queue_for_morning_review(finding)
            
    else:  # MEDIUM/LOW
        # Weekly digest email
        queue_for_weekly_digest(finding)
    
    return {'statusCode': 200}

def is_business_hours(timestamp):
    hour = datetime.fromisoformat(timestamp).hour
    return 9 <= hour <= 18  # JST 9:00-18:00

def notify_to_slack(finding, channel, ping=''):
    slack_token = slack_client.get_secret_value(
        SecretId='slack-webhook-url'
    )['SecretString']
    
    message = f"""
{ping} **GuardDuty Alert - {finding['detail']['severity']}**

Type: {finding['detail']['type']}
Resource: {finding['detail']['resource']['instanceDetails']['instanceId']}
Region: {finding['detail']['region']}
Time: {finding['detail']['updatedAt']}

Description: {finding['detail']['description']}
    """
    # Slack通知実装...

これで、本当に対応が必要なアラートはすぐに目に入り、バックグラウンドノイズは削減されました。朝1時間で確認できるレベルになってます。

1年運用で気づいた、実装の本当のコツ

Suppression Rule は「永遠」じゃない

3ヶ月ごとに見直しが必須です。開発環境のセキュリティグループが変わったり、新しいツールを入れたら、過去のSuppression Ruleが通用しなくなるんですよ。

うちは Confluence に「Suppression Rule 台帳」を作って、なぜそれを抑止してるのかをドキュメント化しました。理由が「もう不要」になったら削除。

Rule NameReasonCreatedLast ReviewedDelete?
Suppress-Lambda-IAMDenyLambda logs permission errors as expected behavior2026-022026-05NO
Suppress-Dev-RDPScanQualys vulnerability scanning in dev env2026-022026-05YES - Moved Qualys to prod
Suppress-Batch-DynamoDBBatch job occasional throttling logs2026-012026-05REVIEW - Batch optimized

False Positive との付き合い方は「完全排除」ではなく「優先順位」

100%のfalse positiveを排除するのは不可能です。でも「本物の脅威を見落とさない」なら可能。

そのために有効なのが、custom findings export + Athena分析 です。

-- 過去3ヶ月のFinding分析
SELECT 
    finding_type,
    COUNT(*) as count,
    COUNT(DISTINCT resource_id) as unique_resources,
    MAX(severity) as max_severity
FROM guardduty_findings
WHERE created_at >= date_format(current_date - interval '90' day, '%Y-%m-%d')
GROUP BY finding_type
HAVING COUNT(*) > 10
ORDER BY count DESC;

このクエリで「毎日来るけど対応不要」なFinding Typeが見える。そういうのはSuppression Ruleの候補になります。

Security Hub Standards の活用

GuardDutyは「脅威検知」ですが、Security Hubの出番は「セキュリティベースラインの維持」です。

有効化すべきStandardsは以下の3つ。

  1. CIS AWS Foundations Benchmark v1.4.0 — IAM、S3、CloudTrailの設定がベストプラクティスに従ってるかチェック
  2. PCI DSS — 決済情報を扱ってなくても、セキュリティベストプラクティスの参考になる
  3. AWS Foundational Security Best Practices — AWS推奨設定の確認に必須

これら3つを運用すると、GuardDutyの脅威検知 + Security Hubのコンプライアンス確認 で、脅威と基盤のセキュリティが両立します。

実運用で見えた、やらなくて良いこと

1. 全Finding自動修復

「セキュリティだからすべて自動修復しよう」って思いました。でも危険です。

Lambda Remediationで自動修復を試みた結果、こんなことが起きました:

  • セキュリティグループが自動削除されて本番が落ちた
  • IAMロールの権限が自動削除されてデプロイが失敗
  • CloudTrail ログが自動無効化された

セキュリティと可用性のバランスが大事なんです。

うちの現在の方針はこれです:

重大度対応方法理由
CRITICAL自動修復(ロールバック可能)即座の対応が必須、失敗時の復旧手段あり
HIGH管理者承認後に修復本番への影響が大きい可能性
MEDIUM以下手動レビュー誤検知の可能性が高い

2. リアルタイム通知の過度な期待

GuardDutyのFindingが検知されるまで、平均5〜10分のラグがあります。完全リアルタイムではないんですよ。

だから「Slackに即座に来たから即対応」という運用は不適切。むしろ日中1回、朝夕で確認するぐらいが現実的です。

3. GuardDuty + WAF + Network Firewallの3つ全部有効化

シグネチャ検知ツールをいっぱい有効化すると、組織全体でアラートが数倍になります。地味に厳しい。

うちの実装はこう役割分けしてます:

  • Network Firewall → NW層の脅威検知(Intrusion Prevention)
  • GuardDuty → CloudTrail・VPC Flow Logs分析(行動分析)
  • WAF → L7アプリケーション層(SQLインジェクション等)

この3つをレイヤー分けすることで、各層の役割が明確になり、誤検知が減ります。

まとめ

1. GuardDutyはアラート数が全てではない

有効化直後は数千件のアラートが来ますが、大半はfalse positive。Suppression Rules と Trusted IP List を先に構築して、運用可能な量に絞ることが最優先です。

2. False Positive との付き合い方は「排除」じゃなく「優先順位」

100%のfalse positiveを排除するのは不可能。代わりに、本当の脅威を見落とさない設定と、重大度別の対応方針を決めることが大事。

3. Security Hubと併用することで、脅威検知 + コンプライアンス確認が可能に

GuardDuty単体では脅威検知だけですが、Security HubのStandards(CIS、PCI DSS等)と組み合わせることで、セキュリティベースラインも同時に維持できます。

4. 自動修復は「段階的」に

CRITICAL以外は手動レビューを挟むことで、セキュリティと可用性のバランスが取れます。

5. ツール選択はレイヤー分け

Network Firewall(NW層)、GuardDuty(行動分析)、WAF(L7層)を役割分けすることで、各々の検知精度が高まり、運用負荷も最適化できます。

正直、3ヶ月目時点ではまだ試行錯誤の途中です。でも「アラート数の多さ=セキュリティレベルの高さ」じゃなく、「適切な検知と対応の継続性こそが本当のセキュリティ」だってことに気づけたのは大きい。

皆さんが同じ地獄にハマらないよう、現実的な実装方法を共有できたら幸いです。

U

Untanbaby

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

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

関連記事