上級 40分 Lesson 16

CloudWatch — ログ監視・メトリクスフィルター・異常検知

CloudWatch Logs/Alarms/Insights のセキュリティ監視設計、メトリクスフィルター、クロスアカウント集約を徹底解説

AWS CloudWatch SCS-C03 ログ監視 Security

CloudWatch は AWS のネイティブな監視・ログ集約サービスだ。セキュリティ監視の要として、ログの収集・分析・アラート化を一元管理する。本講では、SCS-C03 で頻出される CloudWatch の設計パターンと落とし穴を徹底解説する。

CloudWatch セキュリティ監視パイプライン

Loading diagram...

クロスアカウント ログ集約アーキテクチャ

Loading diagram...

1. CloudWatch Logs — ログの構造と設計

ロググループ・ログストリームの階層設計

CloudWatch Logs は ロググループログストリーム の階層構造を持つ。

階層構造:

  • ロググループ(Log Group)
    • ログストリーム(Log Stream) — アプリケーション・インスタンス・Lambda等
      • ログイベント(Log Event) — 時系列のログメッセージ
      • メタデータ — Timestamp, Message, Sequence Token

セキュリティ監視向けの設計例:

  • /aws/cloudtrail/produs-east-12026/04/27/...
  • /aws/vpc/flowlogs/prodeni-xxx-all-traffic / eni-yyy-rejected
  • /aws/lambda/auth-handler2026-04-27T12:34:56.789Z-$LATEST / 2026-04-27T12:35:00.000Z-$LATEST
  • /aws/waf/prodregional-waf-logs

命名規則のベストプラクティス

パターン推奨度理由
/aws/service/account-id/region⭐⭐⭐検索性が高く、複数アカウント集約に最適
/logs/env-service-component⭐⭐⭐環境別・サービス別で自然なツリー構造
時系列パーティショニング⭐⭐クエリ範囲を狭められるが、過度な分割は避ける

ロググループの保持期間設定

# AWS CLI: 30日保持に設定
aws logs put-retention-policy \
  --log-group-name /aws/cloudtrail/prod \
  --retention-in-days 30

# 無期限保持の設定(コスト注意)
aws logs put-retention-policy \
  --log-group-name /aws/cloudtrail/prod \
  --retention-in-days 0

費用最適化のポイント:

  • 保持期間の短縮: セキュリティ規制を確認した上で、不要な長期保持は避ける
  • ログフィルターでの絞り込み: エージェント側でノイズログを排除
  • S3 への自動エクスポート: 長期保存が必要な場合は Kinesis Firehose で S3 にアーカイブ

2. メトリクスフィルター — セキュリティ脅威の自動検知

メトリクスフィルターは CloudWatch Logs をスキャンしてメトリクスに変換する。リアルタイムに異常を検知する仕組みの要だ。

2.1 不正な API コール検知

CloudTrail ログを監視して、認可されていない API 呼び出しを自動検知。

// CloudTrail ログの例(UnauthorizedOperation)
{
  "eventVersion": "1.08",
  "eventID": "abc123",
  "eventSource": "ec2.amazonaws.com",
  "eventName": "AuthorizeSecurityGroupIngress",
  "awsRegion": "us-east-1",
  "sourceIPAddress": "203.0.113.0",
  "userAgent": "aws-cli/2.0.0",
  "requestParameters": null,
  "responseElements": null,
  "errorCode": "UnauthorizedOperation",
  "errorMessage": "User: arn:aws:iam::123456789012:user/attacker is not authorized..."
}

メトリクスフィルター設定

# CloudTrail ログから UnauthorizedOperation をメトリクス化
aws logs put-metric-filter \
  --log-group-name /aws/cloudtrail/prod \
  --filter-name unauthorized-api-calls \
  --filter-pattern '[... , errorCode = "UnauthorizedOperation" || errorCode = "AccessDenied" , ...]' \
  --metric-transformations \
    metricName=UnauthorizedAPICallsMetric,\
    metricNamespace=CloudTrailMetrics,\
    metricValue=1

フィルターパターンの文法

// 単一フィールド マッチ
[... , errorCode = "UnauthorizedOperation" , ...]

// 複数条件の AND
[... , eventSource = "iam.amazonaws.com" , eventName = "DeleteUser" , ...]

// OR 条件(複数フィルターを組み合わせ)
フィルター 1: errorCode = "UnauthorizedOperation"
フィルター 2: errorCode = "AccessDenied"
→ アラームは OR で結合

// キーワード マッチ(完全一致)
[... , eventName = "ConsoleLogin" , errorCode = "Failed*" , ...]

2.2 ルートアカウント使用の検知

ルートアカウントの操作は実務では極力避けるべき。検知して即座にアラート。

// CloudTrail ログ(ルートアカウント)
{
  "userIdentity": {
    "type": "Root",
    "principalId": "123456789012",
    "arn": "arn:aws:iam::123456789012:root",
    "accountId": "123456789012",
    "invokedBy": "signin.amazonaws.com"
  },
  "eventName": "ConsoleLogin",
  "sourceIPAddress": "203.0.113.0"
}

メトリクスフィルター設定

aws logs put-metric-filter \
  --log-group-name /aws/cloudtrail/prod \
  --filter-name root-account-usage \
  --filter-pattern '[... , userIdentity.type = "Root" , ...]' \
  --metric-transformations \
    metricName=RootAccountUsageMetric,\
    metricNamespace=CloudTrailMetrics,\
    metricValue=1

2.3 IAM 変更の検知

IAM ポリシー・ロール・ユーザーの作成・削除・変更は監視対象の最重要項目。

# IAM 変更を検知
aws logs put-metric-filter \
  --log-group-name /aws/cloudtrail/prod \
  --filter-name iam-policy-changes \
  --filter-pattern '[eventSource = iam.amazonaws.com && (eventName = PutUserPolicy || eventName = PutRolePolicy || eventName = PutGroupPolicy || eventName = DeleteUserPolicy || eventName = DeleteRolePolicy || eventName = DeleteGroupPolicy || eventName = AttachUserPolicy || eventName = AttachRolePolicy || eventName = DetachUserPolicy || eventName = DetachRolePolicy)]' \
  --metric-transformations \
    metricName=IAMPolicyChangesMetric,\
    metricNamespace=CloudTrailMetrics,\
    metricValue=1

試験で狙われるポイント

  • ✅ メトリクスフィルターは ログ受信後にのみ適用される(過去ログには遡及しない)
  • ✅ フィルターパターンは JSON フィールド マッチング が基本
  • ✅ 複数フィルターを組み合わせる場合は複合アラームを使用
  • ✅ メトリクスフィルター自体はフィルターパターン作成時点から有効化

3. CloudWatch Logs Insights — セキュリティ調査クエリ

Logs Insights は SQL ライクなクエリで大規模ログを高速検索する。セキュリティインシデント調査で強力。

3.1 セキュリティ調査用クエリ例

特定 IP からの失敗ログイン検索

fields @timestamp, userIdentity.principalId, sourceIPAddress, errorMessage
| filter eventName = "ConsoleLogin" and errorCode = "Failed*"
| stats count() as failed_attempts by sourceIPAddress
| filter failed_attempts > 5

特定期間の IAM 権限昇格の検知

fields @timestamp, userIdentity.principalId, eventName, requestParameters
| filter eventSource = "iam.amazonaws.com"
| filter eventName in ["PutUserPolicy", "AttachUserPolicy", "CreateAccessKey"]
| stats count() as permission_escalation_attempts by userIdentity.principalId, eventName

管理者権限の過度な使用検知

fields @timestamp, userIdentity.principalId, eventName, sourceIPAddress
| filter userIdentity.sessionContext.sessionIssuer.principalId = "*-admin*"
| filter eventSource in ["s3.amazonaws.com", "ec2.amazonaws.com", "iam.amazonaws.com"]
| stats count() as admin_actions by userIdentity.principalId, eventName
| filter admin_actions > 100

VPC Flow Logs から拒否されたトラフィック検索

fields @timestamp, srcaddr, dstaddr, dstport, action
| filter action = "REJECT"
| stats count() as rejected_packets by srcaddr, dstaddr, dstport
| filter rejected_packets > 1000

クロスアカウント API 呼び出し検索

fields @timestamp, userIdentity.arn, eventName, recipientAccountId
| filter userIdentity.accountId != recipientAccountId
| stats count() as cross_account_calls by userIdentity.arn, eventName

3.2 Logs Insights のクォータと制限

制限項目備考
クエリ実行時間最大 15分タイムアウトを避けるため時間範囲を制限
スキャン対象ログサイズ無制限高速化のため絞り込み条件を活用
並列実行アカウント全体で最大 20同時実行クエリを計画的に
クエリ結果行数最大 10,000 行統計処理で集約することで対応

4. サブスクリプションフィルター — リアルタイムログ処理

メトリクスフィルターは集計のみだが、サブスクリプションフィルターは詳細なログ処理を可能にする。

4.1 Lambda へのストリーミング

CloudWatch Logs から Lambda へログをリアルタイムに送信して、カスタムロジックで処理。

# Lambda 関数をターゲットとするサブスクリプションフィルター作成
aws logs put-subscription-filter \
  --log-group-name /aws/cloudtrail/prod \
  --filter-name stream-to-lambda-security-analysis \
  --filter-pattern "[eventSource, eventName, errorCode, ...]" \
  --destination-arn arn:aws:lambda:us-east-1:123456789012:function:SecurityAnalyzer

Lambda 関数の例(Python)

import json
import base64
import boto3
import urllib.parse
from datetime import datetime

sns_client = boto3.client('sns')

def lambda_handler(event, context):
    # CloudWatch Logs からの圧縮データをデコード
    compressed_data = base64.b64decode(event['awslogs']['data'])
    
    # gzip で解凍
    import gzip
    log_data = gzip.decompress(compressed_data).decode('utf-8')
    log_events = json.loads(log_data)['logEvents']
    
    security_alerts = []
    
    for log_event in log_events:
        message = json.loads(log_event['message'])
        
        # セキュリティ脅威の判定
        if should_alert(message):
            security_alerts.append({
                'timestamp': datetime.fromtimestamp(log_event['timestamp'] / 1000).isoformat(),
                'principal': message.get('userIdentity', {}).get('principalId'),
                'event': message.get('eventName'),
                'source_ip': message.get('sourceIPAddress'),
                'error': message.get('errorCode')
            })
    
    # アラート送信
    if security_alerts:
        send_alert(security_alerts)
    
    return {'statusCode': 200}

def should_alert(message):
    # ルートアカウント検知
    if message.get('userIdentity', {}).get('type') == 'Root':
        return True
    # 認可エラー検知
    if message.get('errorCode') in ['UnauthorizedOperation', 'AccessDenied']:
        return True
    # IAM 変更検知
    if message.get('eventSource') == 'iam.amazonaws.com':
        return True
    return False

def send_alert(alerts):
    message = json.dumps(alerts, indent=2, ensure_ascii=False)
    sns_client.publish(
        TopicArn='arn:aws:sns:us-east-1:123456789012:security-alerts',
        Subject='[Security Alert] CloudTrail 異常検知',
        Message=message
    )

4.2 Kinesis Firehose への送信

高スループットのログを Firehose で S3 にアーカイブ。リアルタイム分析と長期保存を両立。

# Kinesis Firehose をターゲットに設定
aws logs put-subscription-filter \
  --log-group-name /aws/vpc/flowlogs/prod \
  --filter-name stream-to-firehose \
  --filter-pattern "[version, account, interface_id, srcaddr, dstaddr, srcport, dstport, protocol, packets, bytes, windowstart, windowend, action, tcpflags, type, pkt_srcaddr, pkt_dstaddr, flow_direction, traffic_type, ...]" \
  --destination-arn arn:aws:kinesis:us-east-1:123456789012:firehose/vpc-flowlogs-archive

Firehose の変換ラムダ関数(メタデータ付与)

import json
import base64

def lambda_handler(event, context):
    output = []
    
    for record in event['records']:
        # Base64 デコード
        payload = json.loads(base64.b64decode(record['data']).decode('utf-8'))
        
        # VPC Flow Logs フィールド定義
        fields = payload.split(' ')
        enhanced_log = {
            'version': fields[0],
            'account_id': fields[1],
            'interface_id': fields[2],
            'srcaddr': fields[3],
            'dstaddr': fields[4],
            'srcport': int(fields[5]),
            'dstport': int(fields[6]),
            'protocol': fields[7],
            'packets': int(fields[8]),
            'bytes': int(fields[9]),
            'action': fields[12],
            'threat_detected': is_suspicious(fields[3], fields[4], fields[12])
        }
        
        # 出力レコード
        output_record = {
            'recordId': record['recordId'],
            'result': 'Ok',
            'data': base64.b64encode(
                (json.dumps(enhanced_log) + '\n').encode('utf-8')
            ).decode('utf-8')
        }
        output.append(output_record)
    
    return {'records': output}

def is_suspicious(src, dst, action):
    # ブロックリスト確認
    blocklist = ['192.0.2.0/24', '198.51.100.0/24']
    return action == 'REJECT' and any(ip_in_range(src, block) for block in blocklist)

def ip_in_range(ip, cidr):
    # CIDR 判定ロジック(簡略版)
    return True

5. クロスアカウント集約 — マルチアカウント環境での監視

複数の AWS アカウントからログを中央集約する。セキュリティ運用の要。

5.1 送信側アカウント(ログ送信元)

# CloudWatch Logs グループを作成
aws logs create-log-group \
  --log-group-name /aws/cloudtrail/prod

# 送信側の IAM ロール作成(クロスアカウント)
cat > trust-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::CENTRAL-ACCOUNT:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "unique-external-id-12345"
        }
      }
    }
  ]
}
EOF

aws iam create-role \
  --role-name CloudTrailLogsToDestination \
  --assume-role-policy-document file://trust-policy.json

# ロールにポリシー追加
cat > policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "logs:PutLogEvents",
      "Resource": "arn:aws:logs:*:CENTRAL-ACCOUNT:log-group:/aws/cloudtrail/central:*"
    }
  ]
}
EOF

aws iam put-role-policy \
  --role-name CloudTrailLogsToDestination \
  --policy-name AllowCloudTrailLogs \
  --policy-document file://policy.json

5.2 受信側アカウント(ログ送信先)

# リソースベースのポリシーで送信元を許可
cat > resource-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::SOURCE-ACCOUNT-1:role/CloudTrailLogsToDestination",
        "AWS": "arn:aws:iam::SOURCE-ACCOUNT-2:role/CloudTrailLogsToDestination"
      },
      "Action": [
        "logs:PutLogEvents",
        "logs:CreateLogStream"
      ],
      "Resource": "arn:aws:logs:us-east-1:CENTRAL-ACCOUNT:log-group:/aws/cloudtrail/central:*",
      "Condition": {
        "StringEquals": {
          "aws:SourceAccount": ["SOURCE-ACCOUNT-1", "SOURCE-ACCOUNT-2"]
        }
      }
    }
  ]
}
EOF

aws logs put-resource-policy \
  --policy-name AllowMultiAccountCloudTrail \
  --policy-text file://resource-policy.json

5.3 送信側での設定(CloudTrail → 中央ロググループ)

# CloudTrail を更新して中央ロググループに送信
aws cloudtrail update-trail \
  --name security-trail-prod \
  --cloud-watch-logs-group-arn arn:aws:logs:us-east-1:CENTRAL-ACCOUNT:log-group:/aws/cloudtrail/central:* \
  --cloud-watch-logs-role-arn arn:aws:iam::SOURCE-ACCOUNT:role/CloudTrailRole

クロスアカウント集約のベストプラクティス

項目推奨
外部 ID必ず使用(セキュリティ向上)
リソースベースのポリシー中央で一元管理
ロググループ命名/aws/central/account-id/region で アカウント特定可能に
メトリクスフィルター中央側で設定(単一管理)
タグ付与SourceAccount, SourceService を付与

6. 暗号化 — KMS 連携

CloudWatch Logs を KMS で暗号化。コンプライアンス要件や機密ログ保護が必須。

# KMS キー作成
aws kms create-key \
  --description "CloudWatch Logs Encryption Key" \
  --key-usage ENCRYPT_DECRYPT

KEY_ID=$(aws kms describe-key --key-id alias/cloudwatch-logs --query 'KeyMetadata.KeyId' --output text)

# KMS キー別名設定
aws kms create-alias \
  --alias-name alias/cloudwatch-logs \
  --target-key-id $KEY_ID

# CloudWatch Logs グループを KMS で暗号化
aws logs associate-kms-key \
  --log-group-name /aws/cloudtrail/prod \
  --kms-key-id arn:aws:kms:us-east-1:123456789012:key/$KEY_ID

KMS ポリシー(CloudWatch Logs サービスに権限を付与)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Allow CloudWatch Logs",
      "Effect": "Allow",
      "Principal": {
        "Service": "logs.amazonaws.com"
      },
      "Action": [
        "kms:Encrypt",
        "kms:Decrypt",
        "kms:ReEncrypt*",
        "kms:GenerateDataKey*",
        "kms:CreateGrant",
        "kms:DescribeKey"
      ],
      "Resource": "*",
      "Condition": {
        "ArnLike": {
          "kms:ViaService": "logs.us-east-1.amazonaws.com"
        }
      }
    }
  ]
}

暗号化時の注意点

  • ✅ KMS キーとロググループが 同じリージョン に存在する必要あり
  • ✅ CloudWatch Logs がキーに対して Decrypt 権限を持つ必要がある
  • ✅ 暗号化はログ取り込み時に自動的に適用される(遡及しない)
  • ✅ クロスアカウント集約時は中央側の KMS キー使用

7. CloudWatch Alarms — セキュリティアラート設定

7.1 標準アラーム

メトリクスフィルターで生成されたメトリクスに基づくアラーム。

# UnauthorizedOperation メトリクスのアラーム
aws cloudwatch put-metric-alarm \
  --alarm-name unauthorized-api-calls-alarm \
  --alarm-description "Alert on unauthorized API calls" \
  --metric-name UnauthorizedAPICallsMetric \
  --namespace CloudTrailMetrics \
  --statistic Sum \
  --period 300 \
  --threshold 1 \
  --comparison-operator GreaterThanOrEqualToThreshold \
  --evaluation-periods 1 \
  --alarm-actions arn:aws:sns:us-east-1:123456789012:security-alerts

7.2 複合アラーム(Composite Alarms)

複数のアラームを組み合わせて、より複雑な条件でアラート。

# 複合アラーム: IAM 変更 AND UnauthorizedOperation の場合
aws cloudwatch put-composite-alarm \
  --alarm-name security-incident-escalation \
  --alarm-description "Alert when IAM changes are followed by unauthorized calls" \
  --alarm-rule "ALARM(iam-policy-changes-alarm) AND ALARM(unauthorized-api-calls-alarm)" \
  --alarm-actions arn:aws:sns:us-east-1:123456789012:security-critical

7.3 異常検出アラーム(Anomaly Detection)

機械学習で過去のデータから異常パターンを学習・検出。

# 異常検出アラーム: CloudTrail イベント数の異常
aws cloudwatch put-metric-alarm \
  --alarm-name cloudtrail-events-anomaly \
  --alarm-description "Detect anomalies in CloudTrail event count" \
  --comparison-operator LessThanLowerOrGreaterThanUpperThreshold \
  --evaluation-periods 2 \
  --threshold-metric-id e1 \
  --metrics '[
    {
      "id": "m1",
      "return_data": false,
      "metric": {
        "namespace": "AWS/CloudTrail",
        "metric_name": "EventCount",
        "stat": "Sum",
        "period": 300
      }
    },
    {
      "id": "e1",
      "expression": "ANOMALY_DETECTION_BAND(m1, 2)",
      "return_data": true
    }
  ]' \
  --alarm-actions arn:aws:sns:us-east-1:123456789012:security-alerts

異常検出の仕組み

過去 2 週間のデータ → 機械学習モデル → 標準偏差を計算

正常範囲: 平均値 ± (標準偏差 × 係数)
異常判定: データが範囲外

例: API 呼び出し回数
  - 平均: 1000 /日
  - 標準偏差: 100
  - 係数: 2
  → 正常範囲: 800 ~ 1200
  → 実際: 2000 → アラート!

7.4 セキュリティ用アラームパターン集

検知項目メトリクス閾値通知先
ルートアカウント使用RootAccountUsageMetric>= 1 (5分)Critical SNS
IAM ポリシー変更IAMPolicyChangesMetric>= 1 (5分)Critical SNS
認可エラーUnauthorizedAPICallsMetric>= 5 (5分)Warning SNS
コンソールログイン失敗ConsoleLoginFailureMetric>= 3 (5分)Warning SNS
API 呼び出し異常CloudTrailEventCount (異常検出)Info SNS

8. CloudWatch Agent — ログ/メトリクス収集

CloudWatch Agent は EC2 / オンプレミスから詳細ログ・メトリクスを収集。旧 Logs Agent より高機能。

8.1 インストールと初期設定

# EC2 での CloudWatch Agent インストール (Amazon Linux 2)
wget https://s3.amazonaws.com/amazoncloudwatch-agent/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm
sudo rpm -U ./amazon-cloudwatch-agent.rpm

# 設定ウィザード(対話形式)
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard

# または JSON 設定ファイルで直接設定
cat > /opt/aws/amazon-cloudwatch-agent/etc/cloudwatch-config.json << 'EOF'
{
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/var/log/secure",
            "log_group_name": "/aws/ec2/secure-logs",
            "log_stream_name": "{instance_id}",
            "retention_in_days": 30
          },
          {
            "file_path": "/var/log/audit/audit.log",
            "log_group_name": "/aws/ec2/audit-logs",
            "log_stream_name": "{instance_id}",
            "retention_in_days": 90
          }
        ]
      }
    }
  },
  "metrics": {
    "namespace": "CustomMetrics",
    "metrics_collected": {
      "cpu": {
        "measurement": [
          {
            "name": "cpu_usage_idle",
            "rename": "CPU_IDLE",
            "unit": "Percent"
          }
        ],
        "totalcpu": false,
        "metrics_collection_interval": 60
      },
      "disk": {
        "measurement": [
          {
            "name": "used_percent",
            "rename": "DISK_USED",
            "unit": "Percent"
          }
        ],
        "metrics_collection_interval": 60,
        "resources": ["/"]
      }
    }
  }
}
EOF

# Agent 起動
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
  -a fetch-config \
  -m ec2 \
  -s \
  -c file:/opt/aws/amazon-cloudwatch-agent/etc/cloudwatch-config.json

8.2 セキュリティ監視用の設定

{
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/var/log/secure",
            "log_group_name": "/aws/ec2/security",
            "log_stream_name": "{instance_id}-secure",
            "retention_in_days": 90,
            "timezone": "UTC"
          },
          {
            "file_path": "/var/log/audit/audit.log",
            "log_group_name": "/aws/ec2/security",
            "log_stream_name": "{instance_id}-auditd",
            "retention_in_days": 365,
            "timezone": "UTC"
          },
          {
            "file_path": "/var/log/apache2/access.log",
            "log_group_name": "/aws/ec2/web-access",
            "log_stream_name": "{instance_id}",
            "retention_in_days": 30
          },
          {
            "file_path": "/var/log/apache2/error.log",
            "log_group_name": "/aws/ec2/web-errors",
            "log_stream_name": "{instance_id}",
            "retention_in_days": 30
          }
        ]
      }
    }
  },
  "metrics": {
    "metrics_collected": {
      "netstat": {
        "measurement": [
          {"name": "tcp_established", "unit": "Count"}
        ],
        "metrics_collection_interval": 60
      }
    }
  }
}

8.3 CloudWatch Agent vs 旧 Logs Agent

機能CloudWatch AgentLogs Agent
ログ収集
メトリクス収集
マルチプラットフォーム⭕ (Linux/Windows/Mac)⭕ (Linux のみ)
設定管理Systems Manager Parameter Store手動管理
サポート状況アクティブ開発中サポート終了予定

推奨: 新規構築では CloudWatch Agent を使用


9. VPC Flow Logs との連携

VPC Flow Logs は ネットワークトラフィックを CloudWatch Logs に記録。セキュリティ分析の必須ソース。

9.1 VPC Flow Logs の有効化と CloudWatch Logs 送信

# VPC Flow Logs の作成
aws ec2 create-flow-logs \
  --resource-type VPC \
  --resource-ids vpc-12345678 \
  --traffic-type ALL \
  --log-destination-type cloud-watch-logs \
  --log-group-name /aws/vpc/flowlogs/prod \
  --deliver-logs-permission-iamrolesarn arn:aws:iam::123456789012:role/flowlogsRole \
  --log-format '${version} ${account-id} ${interface-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${packets} ${bytes} ${start} ${end} ${action} ${tcp-flags} ${type} ${pkt-srcaddr} ${pkt-dstaddr}'

9.2 VPC Flow Logs の分析クエリ

// 拒否されたトラフィック検索
fields @timestamp, srcaddr, dstaddr, dstport, action
| filter action = "REJECT"
| stats count() as rejected_packets, sum(bytes) as total_bytes by srcaddr, dstaddr, dstport
| sort total_bytes desc
| limit 100

// ポートスキャンの検知
fields @timestamp, srcaddr, dstport, action
| filter action = "REJECT" and protocol = 6
| stats count() as connection_attempts by srcaddr, dstport
| filter connection_attempts > 100
| sort connection_attempts desc

// 異常なデータ転送の検知
fields @timestamp, srcaddr, dstaddr, bytes
| stats sum(bytes) as total_bytes by srcaddr, dstaddr
| filter total_bytes > 1000000000
| sort total_bytes desc

10. 制限事項と落とし穴

10.1 リアルタイム性の限界

ログ生成 → CloudWatch Logs 送信 → メトリクスフィルター適用 → メトリクス生成 → アラーム評価

遅延: 数秒~数分(ネットワーク遅延、バッチ処理の影響)

対策

  • 高速検知が必要な場合は EventBridge ルール + Lambda を併用
  • メトリクスフィルターだけに依存しない

10.2 メトリクスフィルターの制限

制限項目              値
フィルターパターン長   1024 文字
ロググループあたり    最大 10 個
メトリクスネームスペース  250 個

対策: 複数ロググループへの分散

# サービス別にロググループを分割
/aws/security/cloudtrail
/aws/security/config
/aws/security/guardduty
/aws/security/waf

10.3 Logs Insights のクォータ

最大実行時間: 15 分
最大結果行数: 10,000 行
同時実行数: アカウント全体で最大 20

対策

// 期間を絞る
| filter @timestamp > ago(1h) and @timestamp < ago(30m)

// 統計処理で集約
| stats count() as occurrences by field1, field2
| sort occurrences desc
| limit 1000

10.4 クロスリージョン制約

CloudWatch Logs はリージョンサービス。グローバル集約が必要な場合は複雑になる。

東京(ap-northeast-1) → Lambda → Kinesis → 中央リージョン → S3
バージニア(us-east-1)  → Lambda → Kinesis ↓
シドニー(ap-southeast-2) → Lambda → Kinesis

Lambda で複数リージョンのログをまとめて送信

11. 統合アーキテクチャ — エンドツーエンド監視設計

セキュリティ監視のベストプラクティス統合例

┌─────────────────────────────────────────────────────────────────┐
│ Data Sources                                                      │
├─────────────────────────────────────────────────────────────────┤
│ CloudTrail → CloudWatch Logs                                    │
│ VPC Flow Logs → CloudWatch Logs                                 │
│ Config Changes → CloudWatch Logs                                │
│ GuardDuty Findings → CloudWatch Events                          │
│ WAF Logs → CloudWatch Logs                                      │
└──────────────┬──────────────────────────────────────────────────┘

┌──────────────▼──────────────────────────────────────────────────┐
│ Processing Layer                                                 │
├─────────────────────────────────────────────────────────────────┤
│ 1. メトリクスフィルター(集計)                                │
│    - ルートアカウント → RootAccountUsageMetric                 │
│    - IAM 変更 → IAMPolicyChangesMetric                          │
│    - API エラー → UnauthorizedAPICallsMetric                    │
│                                                                  │
│ 2. サブスクリプションフィルター(詳細分析)                    │
│    - CloudWatch Logs → Lambda → 異常検知ロジック               │
│    - CloudWatch Logs → Kinesis Firehose → S3 (長期保存)        │
│                                                                  │
│ 3. Logs Insights(深掘り調査)                                 │
│    - セキュリティ侵害の根因分析                                │
│    - ユーザー行動の異常検知                                    │
└──────────────┬──────────────────────────────────────────────────┘

┌──────────────▼──────────────────────────────────────────────────┐
│ Alerting & Response                                             │
├─────────────────────────────────────────────────────────────────┤
│ メトリクス → CloudWatch Alarm → SNS (Critical)                 │
│           → 複合アラーム → SNS (Escalation)                    │
│           → 異常検出 → Lambda (自動対応)                       │
│                                                                  │
│ SNS トピック:                                                   │
│   - security-critical: セキュリティ侵害対応チーム              │
│   - security-warning: セキュリティ監視チーム                   │
│   - security-info: 定期レポート配信                            │
└──────────────┬──────────────────────────────────────────────────┘

┌──────────────▼──────────────────────────────────────────────────┐
│ Long-term Storage & Audit                                       │
├─────────────────────────────────────────────────────────────────┤
│ CloudWatch Logs (30日保持) → Kinesis Firehose                  │
│                              ↓                                   │
│                          S3 (年単位保持)                        │
│                          ↓                                       │
│                     Athena (クエリ)                             │
│                     Lake Formation (governance)                 │
└─────────────────────────────────────────────────────────────────┘

試験で狙われるポイント

必出パターン 1: メトリクスフィルターの動作範囲

問題: CloudTrail ログが生成される前に作成したメトリクスフィルターは、過去ログに適用されるか?

: ❌ 適用されない。メトリクスフィルターは 設定後のログのみ をスキャンする。

対策: 過去ログの分析は Logs Insights を使用。メトリクスフィルターは継続監視に使う。


必出パターン 2: クロスアカウント集約の認可

問題: 複数アカウント間でログを集約する際、必ず設定すべき 2 つの IAM ポリシーは?

:

  1. 送信側: AssumeRole ポリシーで中央アカウントを許可
  2. 受信側: リソースベースのポリシーで送信側ロールを許可
// 受信側: ロググループのリソースポリシー
{
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::SOURCE:role/CloudTrailRole"
      },
      "Action": ["logs:PutLogEvents", "logs:CreateLogStream"],
      "Resource": "arn:aws:logs:region:CENTRAL:log-group:*"
    }
  ]
}

必出パターン 3: 暗号化時の KMS キーの条件

問題: CloudWatch Logs を KMS で暗号化する際、KMS キーが別リージョンにあるとどうなるか?

: ❌ 失敗。CloudWatch Logs と KMS キーは 同じリージョン に存在する必要がある。


必出パターン 4: 異常検出アラームの学習期間

問題: 異常検出アラームはいつから機械学習を開始するか?

: アラーム作成後 約 2 週間。それまでは十分な学習データがないため機能しない。


必出パターン 5: CloudWatch Agent の権限

問題: CloudWatch Agent が CloudWatch Logs にログを送信するために必要な IAM アクションは?

:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents",
        "logs:DescribeLogGroups",
        "logs:DescribeLogStreams"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "cloudwatch:PutMetricData"
      ],
      "Resource": "*"
    }
  ]
}

まとめ

CloudWatch はセキュリティ監視の統合プラットフォーム。

レイヤー機能用途
ログ集約CloudWatch Logs全セキュリティログの一元管理
メトリクス化メトリクスフィルターリアルタイム異常検知
詳細分析Logs Insightsセキュリティ侵害の根因追跡
リアルタイム処理サブスクリプションフィルターカスタム脅威検知ロジック
アラート・対応CloudWatch Alarmsセキュリティ体制の自動化
長期保存Kinesis Firehose → S3コンプライアンス対応

セキュリティ監視設計の原則

  1. 多層防御: メトリクスフィルター + Logs Insights + Lambda で多角的に監視
  2. スケーラビリティ: クロスアカウント集約で複雑性を管理
  3. 保持期間の最適化: 規制要件と コスト のバランス
  4. 自動対応: Lambda + SNS で人手を最小化
  5. 長期監査証跡: S3 + Athena で過去検証に耐える

CloudWatch はシンプルに見えて、細部に秘密あり。制限を理解し、統合アーキテクチャで補完する——それが実運用の秘訣だ。