CSPM・CWPP導入3ヶ月、アラート週500件の地獄から学んだこと|AWSマルチアカウント運用記

「またアラートか…」ってなった経験ありませんか?Wiz・Prisma Cloud・Security Hubを実際に入れて沈みかけたFalse Positive地獄と、そこから這い上がった話を正直に書きます。

先日、社内の四半期セキュリティレビューで「CSPMのアラートが週500件超えてます」ってSlackに流れてきたとき、正直「またか」ってなりました。導入から3ヶ月、うちのチームが経験したのは「クラウドセキュリティが可視化された喜び」と同時に「アラート地獄に沈んでいく恐怖」でした。

CSPM(Cloud Security Posture Management)とCWPP(Cloud Workload Protection Platform)、言葉は知ってるけど実際どう使うの?という人も多いと思う。今回は教科書的な話は抜きにして、うちがやってみて失敗したこと・うまくいったことをそのまま書いていきます。

CSPMとCWPPを改めて整理する(実務で混乱したポイント)

最初に正直に言っておくと、導入前にCSPMとCWPPの違いをちゃんと理解できていなかった。ベンダーの営業資料を見ると「両方カバーしてます!」みたいな感じで書いてあって、違いが曖昧になってしまうんですよね。

実際に運用して体感した違いはこんな感じです。

項目CSPMCWPP
守る対象クラウド設定・構成(S3公開設定、SG穴など)ワークロード自体(コンテナ、VM、Lambda)
検知タイミング設定変更・リソース作成時ランタイム・起動時・パケットレベル
主な検知内容IAMの過剰権限、暗号化漏れ、ネットワーク設定ミスマルウェア、異常プロセス、コンテナエスケープ
エージェント不要(API経由)必要(eBPFベースが主流)
代表ツールWiz、Prisma Cloud、AWS Security HubFalco、Aqua Security、Sysdig

CSPMは「設定の問題」を見つけるもので、CWPPは「動いているものの問題」を見つけるものと思えば大体合ってる。2026年時点では、WizやPrisma Cloudがこの両方をカバーする統合プラットフォームとして提供しているので、予算があれば統合製品を使うのが現実的かなと思っています。ただ正直まだ検証中の部分もあって、「統合が便利か、専門ツール組み合わせが精度高いか」は環境によりそう。

うちの環境と導入したツール構成

うちのAWS環境は、Organizationsで管理している12アカウント構成です。本番・ステージング・各ドメインごとにアカウントを分けているやつですね。このマルチアカウント環境に対して導入したのが以下の構成です。

graph TB
    subgraph AWS_Organizations[AWS Organizations]
        subgraph Management_Account[管理アカウント]
            SecurityHub[AWS Security Hub<br/>統合ダッシュボード]
            Macie[Amazon Macie<br/>S3データ分類]
            GuardDuty_Master[GuardDuty<br/>マスター検出器]
            Inspector[Amazon Inspector v2<br/>脆弱性スキャン]
        end

        subgraph Security_Account[セキュリティ専用アカウント]
            Wiz[Wiz CNAPP<br/>CSPM + CWPP]
            SIEM[Amazon Security Lake<br/>+ OpenSearch]
            EventBridge_Sec[EventBridge<br/>アラートルーティング]
            SNS_Sec[SNS<br/>Slack通知]
        end

        subgraph Prod_Account[本番アカウント]
            subgraph VPC_Prod[VPC: 10.0.0.0/16]
                subgraph AZ_A[AZ: ap-northeast-1a]
                    EKS_Node[EKS Worker Node<br/>+ Falco Agent]
                    Lambda_Prod[Lambda Functions]
                end
                subgraph AZ_C[AZ: ap-northeast-1c]
                    RDS[RDS Aurora<br/>暗号化必須]
                    S3_Prod[S3 Buckets<br/>Macie監視対象]
                end
                GuardDuty_Member[GuardDuty<br/>メンバー検出器]
                Inspector_Member[Inspector<br/>メンバー]
            end
        end

        subgraph Dev_Account[開発アカウント]
            subgraph VPC_Dev[VPC: 10.1.0.0/16]
                EKS_Dev[EKS Dev Cluster<br/>+ Falco Agent]
                Lambda_Dev[Lambda Functions]
            end
            GuardDuty_Dev[GuardDuty<br/>メンバー検出器]
        end
    end

    GuardDuty_Master -->|集約| SecurityHub
    Inspector -->|集約| SecurityHub
    Macie -->|集約| SecurityHub
    GuardDuty_Member -->|委任| GuardDuty_Master
    Inspector_Member -->|委任| Inspector
    SecurityHub -->|イベント転送| EventBridge_Sec
    Wiz -->|API連携| SIEM
    EventBridge_Sec -->|通知| SNS_Sec
    SNS_Sec -->|Slack| DevTeam[開発チーム]
    Falco_Logs[Falcoログ] -->|fluentd| SIEM
    EKS_Node --> Falco_Logs
    EKS_Dev --> Falco_Logs

基本的にはAWSネイティブのSecurity Hub・GuardDuty・Inspector v2をベースに使って、サードパーティのWizをCSPM・CWPPの統合として被せる構成です。AWSネイティブのツールだけでいいんじゃないかという話もあるんですが、Wizのグラフベースのリスク可視化(セキュリティグラフ)は正直便利で、「このS3バケットは外部公開設定があって、かつ機密データが入っていて、アクセス可能なIAMロールがEC2に付いてて……」みたいな複合的なリスクを一目で見られるのはAWSネイティブにはない強みでした。

コンテナのランタイム保護はFalcoをEKSのDaemonSetとして動かしています。2025年末にFalco 1.0がリリースされてeBPFベースのドライバーが安定したので、カーネルモジュール不要で動かせるようになったのはありがたい。

GuardDuty導入3ヶ月の地獄と脱出戦略でも書きましたが、AWSネイティブのセキュリティサービスはとにかく最初のFalse Positiveとの戦いが大変です。CSPMも同じで、「可視化された!」と喜ぶのも束の間、すぐにアラートの波に飲まれる。

アラート地獄からの脱出:重要度分類とルール設計

導入1週間で気づいたのですが、デフォルト設定のままにすると文字通りアラートが洪水になります。うちの環境では初週に3000件超のFindingが出ました。

xychart-beta
    title "CSPM Finding件数推移(週次)"
    x-axis ["導入1週", "2週", "3週", "4週", "6週", "8週", "10週", "12週"]
    y-axis "Finding件数" 0 --> 3500
    bar [3120, 2850, 2100, 1560, 980, 640, 420, 280]
    line [3120, 2850, 2100, 1560, 980, 640, 420, 280]

件数が下がってきているのは「問題を解決した」というよりも「ノイズを適切に除外できるようになった」という面が大きいです。解決済みと除外済みの比率でいうと、正直2:8くらいで除外の方が多かった。そのために実施したのが以下のフローです。

flowchart TD
    A[新規Finding発生] --> B{重要度判定}
    B -->|Critical| C[即時Slack通知<br/>+ PagerDuty]
    B -->|High| D[24時間以内対応チケット]
    B -->|Medium| E[スプリントバックログ追加]
    B -->|Low/Info| F{除外判定}
    
    C --> G[インシデント対応フロー]
    D --> H[担当者アサイン]
    E --> I[週次レビューで優先度決定]
    
    F -->|既知の許容リスク| J[Suppression Rule登録]
    F -->|環境固有の理由| K[Exception登録<br/>+ 理由をコメント記録]
    F -->|確認要| L[セキュリティチームレビュー]
    
    J --> M[四半期ごとに見直し]
    K --> M

特に効いたのが「Suppression RuleとExceptionの使い分けを明確にしたこと」です。Suppression Ruleは「このルールはうちの環境では適用しない」という判断で、Exceptionは「このリソースは特定の理由でこのルールの対象外にする」という判断です。最初はごっちゃにして管理が崩壊しかけました。

実際に設定したSecurity Hubのカスタムアクションの例を載せておきます。

# Lambda関数でSecurity Hubのfindingを処理するサンプル
import boto3
import json
from datetime import datetime

def lambda_handler(event, context):
    securityhub = boto3.client('securityhub')
    
    for finding in event['detail']['findings']:
        severity = finding['Severity']['Label']
        resource_id = finding['Resources'][0]['Id']
        finding_id = finding['Id']
        
        # Critical・HighのみPagerDutyに転送
        if severity in ['CRITICAL', 'HIGH']:
            route_to_pagerduty(finding)
        
        # タグベースで除外判定
        resource_tags = finding['Resources'][0].get('Tags', {})
        if resource_tags.get('security-exception') == 'approved':
            # 承認済みExceptionは自動クローズ
            securityhub.batch_update_findings(
                FindingIdentifiers=[{
                    'Id': finding_id,
                    'ProductArn': finding['ProductArn']
                }],
                Workflow={'Status': 'SUPPRESSED'},
                Note={
                    'Text': f'Auto-suppressed: security-exception tag approved. Reviewed: {resource_tags.get("exception-reviewed-date", "unknown")}',
                    'UpdatedBy': 'lambda-finding-router'
                }
            )
            
def route_to_pagerduty(finding):
    # PagerDuty Events API v2に転送
    import urllib3
    http = urllib3.PoolManager()
    
    payload = {
        "routing_key": "YOUR_PAGERDUTY_ROUTING_KEY",
        "event_action": "trigger",
        "payload": {
            "summary": f"[{finding['Severity']['Label']}] {finding['Title']}",
            "source": finding['Resources'][0]['Id'],
            "severity": finding['Severity']['Label'].lower(),
            "custom_details": {
                "description": finding['Description'],
                "remediation": finding.get('Remediation', {}).get('Recommendation', {}).get('Text', ''),
                "aws_account": finding['AwsAccountId']
            }
        }
    }
    
    response = http.request(
        'POST',
        'https://events.pagerduty.com/v2/enqueue',
        body=json.dumps(payload).encode('utf-8'),
        headers={'Content-Type': 'application/json'}
    )
    return response

タグベースのException管理は地味に便利で、security-exception: approvedexception-reviewed-date: 2026-04-01みたいなタグをリソースに付けておくと、Lambdaが自動でSuppressしてくれる。ただしこれは四半期レビューで棚卸しをサボると「永遠に放置された例外」が積み上がるので、そこだけは怖い。個人的には棚卸しのリマインダーをEventBridgeで自動化しておくのを強くお勧めします。

CWPPのFalco運用で実際に設定したルール

EKS上でFalcoを動かしていて、これも最初はデフォルトルールのアラートが多すぎて参りました。Kubernetesクラスターでは「コンテナ内でshellを起動する」だけでアラートになるんですが、デバッグ目的でkubectl execを使うことって意外と多いんですよね。開発者からすると「ちょっとログ確認しただけなのに」ってなる。

うちがカスタマイズしたFalcoのルールの一部です。

# custom_rules.yaml

# デフォルトのTerminal shell in containerをオーバーライド
- rule: Terminal Shell in Container
  desc: A shell was used as the entrypoint/exec point into a container
  condition: >
    spawned_process
    and container
    and shell_procs
    and proc.tty != 0
    and container_entrypoint
    # 承認済みイメージは除外(CI/CDツールなど)
    and not container.image.repository in (approved_debug_images)
    # 特定のNamespaceは除外(kube-system, monitoring)
    and not k8s.ns.name in (excluded_namespaces)
  output: >
    A shell was spawned in a container with an attached terminal
    (user=%user.name user_loginuid=%user.loginuid %container.info
    shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline
    terminal=%proc.tty container_id=%container.id image=%container.image.repository)
  priority: WARNING
  tags: [container, shell, mitre_execution]

# 承認済みデバッグイメージのリスト
- list: approved_debug_images
  items:
    - "public.ecr.aws/our-company/debug-tools"
    - "busybox"
    - "alpine"

# 除外Namespace
- list: excluded_namespaces
  items:
    - "kube-system"
    - "monitoring"
    - "logging"

# 機密情報へのアクセス検知(これは絶対に除外しない)
- rule: Read Sensitive File in Container
  desc: Detect an attempt to read sensitive files within a container
  condition: >
    open_read
    and container
    and sensitive_files
    and not proc.name in (known_sensitive_file_readers)
  output: >
    Sensitive file read in container
    (user=%user.name file=%fd.name container_id=%container.id
    image=%container.image.repository k8s_ns=%k8s.ns.name
    k8s_pod=%k8s.pod.name)
  priority: CRITICAL
  tags: [container, filesystem, mitre_credential_access]

Falcoのルール設計で気づいたのは、「何を検知したいか」より「何は検知しなくていいか」を先に決めた方が運用が楽になるということです。これはコンテナセキュリティ完全ガイド2026でも触れていますが、eBPFベースのランタイム保護はカーネルへの介入が必要なので、まずステージング環境でノイズレベルを確認してから本番に入れることを強くお勧めします。うちは本番から入れて後悔しました。

IaC連携:Terraform × CDK Nagでシフトレフト

「検知してから直す」よりも「デプロイ前に防ぐ」方が絶対に楽です。これは3ヶ月運用して確信に変わった話で、工数的には圧倒的にシフトレフトの方がコスパが高い。

うちではTerraformのコードにCheckovを、CDKにcdk-nagを組み込んで、CI/CDの段階でセキュリティ設定ミスを検出するようにしています。

# main.tf の例:S3バケット設定
resource "aws_s3_bucket" "data_bucket" {
  bucket = "${var.project}-${var.env}-data"
  
  # Checkovが必ずチェックするポイント
  force_destroy = false
  
  tags = {
    Environment            = var.env
    DataClassification     = "confidential"
    # セキュリティException管理のためのタグ
    security-exception     = "none"
    security-reviewed-by   = "security-team"
    security-reviewed-date = "2026-04-15"
  }
}

resource "aws_s3_bucket_public_access_block" "data_bucket" {
  bucket = aws_s3_bucket.data_bucket.id
  
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

resource "aws_s3_bucket_server_side_encryption_configuration" "data_bucket" {
  bucket = aws_s3_bucket.data_bucket.id
  
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm     = "aws:kms"
      kms_master_key_id = aws_kms_key.s3_key.arn
    }
    bucket_key_enabled = true
  }
}

CheckovをCIに組み込むのは簡単で、GitHub Actionsなら以下の感じです。

# .github/workflows/security-scan.yml
name: Security Scan

on:
  pull_request:
    branches: [main, develop]

jobs:
  checkov:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Run Checkov
        uses: bridgecrewio/checkov-action@v12
        with:
          directory: ./terraform
          framework: terraform
          # CISベンチマークとAWSセキュリティのベストプラクティスをチェック
          check: CKV_AWS_*,CKV2_AWS_*
          # チームで合意した除外ルール(理由をコメントで記録)
          skip-check: >
            CKV_AWS_144,
            CKV_AWS_145
          # SARIF形式でGitHub Security Alertsに連携
          output_format: sarif
          output_file_path: checkov-results.sarif
          soft-fail: false
          
      - name: Upload SARIF
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: checkov-results.sarif

soft-fail: falseにしてPRをブロックするようにした瞬間、チーム内で「なんで俺のPRがブロックされてるんだ」という摩擦が発生しました。ここは好み分かれるかもしれないけれど、最初はwarnにして1〜2ヶ月慣らしてからブロックに変える方が現実的だったと今は思っています。Terraformで3年分の失敗から学んだ、State管理とAI検証の正解でも触れていますが、セキュリティツールをCIに入れるときは「教育ファースト」でいかないとチームの反感を買います。これは本当に。

あとCDK Nagを使った自動セキュリティ検証についてはCDK Aspects・Nag導入で痛感した、自動セキュリティ検証の現実的な話に詳しく書いたので、そちらも参考にしてください。

コンプライアンス対応への活用:Security HubのCIS・PCI DSS自動チェック

うちはSOC2対応も進めていて、CSPMの自動チェックがコンプライアンス証跡として使えるのは非常に助かっています。Security Hubには「セキュリティ標準」として以下が組み込まれていて、主要なフレームワークはほぼカバーできます。

セキュリティ標準主な対象2026年時点のコントロール数
CIS AWS Foundations Benchmark v3.0AWS基本設定約89項目
AWS Foundational Security Best PracticesAWSサービス全般約500項目
NIST SP 800-53 Rev.5政府・金融系約700項目
PCI DSS v3.2.1カード決済約220項目

SOC2審査では「特定のコントロールが常時チェックされていること」を証明できれば大幅に楽になります。Security Hubのコンプライアンスチェック結果を定期的にS3に保存しておくことで、監査時の証跡として使える。SOC2審査でCloudTrail・Config設計が半年泥沼になった実録にも書きましたが、コンプライアンスのためのログ収集と証跡管理は早めに設計しておくのが吉です。

Security Hubの自動エクスポート設定はこんな感じで組んでいます。

# EventBridgeで定期的にコンプライアンスサマリーをS3に保存
import boto3
import json
from datetime import datetime, timezone

def export_compliance_summary(event, context):
    securityhub = boto3.client('securityhub')
    s3 = boto3.client('s3')
    
    # CIS Benchmark v3.0のコンプライアンス状況を取得
    standards_arn = 'arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/3.0.0'
    
    paginator = securityhub.get_paginator('get_compliance_summary')
    
    summary_data = {
        'export_timestamp': datetime.now(timezone.utc).isoformat(),
        'account_id': boto3.client('sts').get_caller_identity()['Account'],
        'standards': []
    }
    
    # 各標準のコンプライアンス率を集計
    response = securityhub.list_standards_control_associations(
        SecurityControlId='CIS.1.1'  # サンプル
    )
    
    # S3に証跡として保存
    key = f"compliance-reports/{datetime.now().strftime('%Y/%m/%d')}/summary.json"
    s3.put_object(
        Bucket='your-compliance-bucket',
        Key=key,
        Body=json.dumps(summary_data, ensure_ascii=False, indent=2),
        ServerSideEncryption='aws:kms',
        ContentType='application/json'
    )
    
    print(f"Compliance summary exported to s3://your-compliance-bucket/{key}")
    return {'statusCode': 200, 'key': key}

これを毎日実行して、四半期ごとの審査時に「この期間のコンプライアンス状況はここにあります」と言えるようにしています。地味に便利で、スクショ撮って貼り付けるような手作業とは雲泥の差です。皆さんのチームではコンプライアンス証跡の自動化ってどこまでやってますか?手動でスクショ撮ってるチームもまだ多いんじゃないかと思っていて、ここはもう少し業界全体で自動化が進んでほしいなと感じているところです。

まとめ

CSPM・CWPPを3ヶ月本番運用して得られた知見をざっくりまとめます。

1. 最初の1〜2週間はアラート地獄を覚悟する デフォルト設定のまま放置すると週数千件のFindingが出る。重要度分類とSuppressionルールの設計を先に決めてから導入したほうがいい。

2. CSPMとCWPPは別物と理解した上で統合製品を使う WizやPrisma Cloudの統合プラットフォームは設定ミスとランタイム脅威の両方を一元管理できるので、中規模以上のAWS環境なら投資する価値はある。

3. シフトレフト(IaCスキャン)が最もROIが高い CheckovやCDK NagをCI/CDに組み込んで本番デプロイ前に検出するのが、結果的に工数を一番削減できた方法だった。

4. コンプライアンス証跡の自動化はSOC2・ISO27001対応に直接効く Security HubのチェックをS3に定期保存しておくだけで審査の準備工数が大幅に減る。

5. チームへの段階的な導入が現実的 最初はwarnモードで慣らして、ルールへの理解が深まってからブロックに変えないと反感を買う。


まず試すなら、aws securityhub enable-security-hubとCIS Benchmark v3.0を有効化して現状を可視化するところから始めてみるといいと思います。CheckovはCIのwarnモードで試験導入して、どの程度のFindingが出るか把握するのが次のステップ。Falcoはいきなり本番に入れず、ステージング環境で1週間アラートを観察してから判断するのが吉です(うちはここで痛い目を見た)。

セキュリティは「入れたら終わり」ではなくて、チームが日常的に向き合える仕組みを作るのが本質だと思っています。完璧なゼロFindingを目指すより、重要なアラートを見逃さない運用フローを育てることに時間を使う方がいい。それが3ヶ月やってみての正直な結論です。

U

Untanbaby

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

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

関連記事