CloudTrail 証跡のCloudWatchとの連携設定手順について

このブログシリーズ 「クラウドセキュリティ 実践集」 では、一般的なセキュリティ課題を取り上げ、「なぜ危険なのか?」 というリスクの解説から、「どうやって直すのか?」 という具体的な修復手順(コンソール、AWS CLI、Terraformなど)まで、分かりやすく解説します。

この記事では、CloudTrail証跡と連携されているCloudWatch Log Groupが存在しない状態について、リスクと対策を解説します。

ポリシーの説明

Security Hub コントロール AWS CloudTrail – AWS Security Hub

このコントロールは、CloudWatch Logs にログを送信するように CloudTrail 追跡が設定されているかどうかをチェックします。追跡の CloudWatchLogsLogGroupArn プロパティが空の場合、コントロールは失敗します

リスク

AWS CloudTrailは、AWSアカウント内でのすべてのAPI呼び出しとリソース変更を記録する監査サービスです。このCloudTrailのログがAmazon CloudWatch Logsに連携されていない場合、アカウントの監視体制に大きなギャップが生じ、以下のようなリスクが発生します。

  • 異常アクティビティの検知遅延: CloudTrailログは、不正アクセス、特権昇格、設定変更などの異常なアクティビティを特定するための主要な情報源です。CloudWatch Logsとの連携がなければ、これらのログをリアルタイムで監視し、異常を自動的に検知してアラートを送信することが困難になります。
  • セキュリティインシデントへの対応遅延: インシデント発生時、ログの分析は原因究明、攻撃経路の特定、影響範囲の把握に不可欠です。CloudWatch Logsにログが集約されていない場合、ログの収集と分析に時間がかかり、迅速な対応が阻害されます。
  • コンプライアンス違反: 多くのセキュリティフレームワークや規制(例: PCI DSS, HIPAA, GDPR)では、監査ログの集中管理、監視、長期保存が求められます。CloudWatch Logsとの連携がない場合、これらのコンプライアンス要件を満たせない可能性があります。
  • 運用上の非効率性: ログがCloudWatch Logsに集約されていないと、トラブルシューティングや運用上の問題を特定する際に、各AWSサービスやリソースのログを個別に確認する必要があり、運用作業が非効率になります。
  • データの可視性不足: CloudWatch Logsは、ログデータに対するメトリクスフィルター、アラーム、ダッシュボードといった強力な分析機能を提供します。連携がない場合、これらの機能を活用できず、アカウントのセキュリティ状態に関する深い洞察が得られません。

対策

CloudTrailのログをCloudWatch Logsに連携することは、AWSアカウントのセキュリティ監視と監査能力を大幅に向上させるための基本的なかつ重要な対策です。

  • CloudTrailのCloudWatch Logs連携を有効化: CloudTrail証跡の設定で、ログをCloudWatch Logsグループに送信するように設定します。これにより、すべてのCloudTrailイベントが指定されたロググループに集約されます。
  • 適切なIAMロールの設定: CloudTrailがCloudWatch Logsにログを送信するために必要なIAMロール(通常は自動生成されます)が、適切な権限を持っていることを確認します。
  • CloudWatchメトリクスフィルターとアラームの活用: CloudWatch Logsに転送されたCloudTrailログに対して、特定のセキュリティイベント(例: ルートユーザーのログイン、IAMユーザーの作成/削除、セキュリティグループの変更、S3バケットのパブリック化など)を検知するメトリクスフィルターを作成し、それに基づいてSNSトピックへ通知するCloudWatchアラームを設定します。
  • ログの保持期間の設定: CloudWatch Logsのロググループで、監査要件やコンプライアンスポリシーに合わせた適切なログ保持期間を設定します。長期保存が必要な場合は、S3へのエクスポートも検討します。
  • ログ分析ツールの連携: CloudWatch Logsのログデータを、Amazon Athena、Amazon QuickSight、または他のログ分析ツールと連携させることで、より高度な分析やセキュリティイベントの可視化を実現します。

修復方法

AWSコンソールでの修復手順

AWSコンソールを使用して、CloudTrailのログをCloudWatch Logsに連携させます。

  1. CloudTrailサービスへ移動:
    • AWSコンソールにログインし、CloudTrailサービスを開きます。
  2. 既存の証跡の選択または新規作成:
    • 左側のナビゲーションペインで「証跡」を選択します。
    • 既存の証跡を編集する場合は、その証跡名をクリックします。新しい証跡を作成する場合は、「証跡を作成」をクリックします。
  3. CloudWatch Logsの設定:
    • 証跡の設定ページで、「CloudWatch Logs」セクションまでスクロールします。 image.png
    • 「有効」にチェックを入れます。
    • *「ロググループ」で、既存のロググループを選択するか、新しいロググループ名を入力して「新しいロググループを作成」を選択します。
    • *「IAM ロール」で、新しいロールを作成するか、既存のロールを選択します。通常は「新規または既存の IAM ロールを作成」を選択し、デフォルトで作成されるロール(例: CloudTrail-CloudWatchLogs-Role-xxxx)を使用します。このロールには、CloudTrailがログをCloudWatch Logsに書き込むための適切な権限(logs:CreateLogStreamlogs:PutLogEventsなど)が付与されます。
  4. 変更の保存:
    • 既存の証跡の場合は「変更を保存」をクリックします。新しい証跡の場合は、残りの設定(イベント履歴、ストレージロケーションなど)を完了し、「証跡を作成」をクリックします。
    • 設定後、CloudTrailのログが数分以内に指定したCloudWatch Logsグループに表示され始めます。

Terraformでの修復手順

TerraformでCloudTrail証跡とCloudWatch Logsグループを連携させるには、aws_cloudtrail リソースの cloud_watch_logs_group_arncloud_watch_logs_role_arn パラメータを設定します。これには、CloudTrailがCloudWatch Logsにログを書き込むためのIAMロールも必要です。

# Terraformのバージョン要件とAWSプロバイダの指定
terraform {
  required_version = ">= 1.0.0" # v1.12.1を含む1.x系のバージョンを許容
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.67.0" # ご提示いただいたプロバイダバージョンを指定
    }
  }
}

# CloudTrailの名前をlocal変数で定義し、循環依存を解消
locals {
  cloudtrail_name      = "my-main-cloudtrail" # あなたのCloudTrail名に置き換えてください
  cloudtrail_log_group = "/aws/cloudtrail/${local.cloudtrail_name}"
}

# CloudTrailログを書き込むCloudWatch Logsグループを定義
resource "aws_cloudwatch_log_group" "cloudtrail_log_group" {
  # CloudTrailリソースに依存しない固定名(またはlocal変数からの参照)に変更
  name              = local.cloudtrail_log_group 
  retention_in_days = 90 # ログの保持期間 (必要に応じて変更)
}

# CloudTrailがCloudWatch Logsにログを書き込むためのIAMロールを定義
resource "aws_iam_role" "cloudtrail_cloudwatch_logs_role" {
  name = "cloudtrail-cloudwatch-logs-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "cloudtrail.amazonaws.com"
        }
      },
    ]
  })
}

# IAMロールにCloudWatch Logsへの書き込み権限を付与するポリシーを定義
resource "aws_iam_role_policy" "cloudtrail_cloudwatch_logs_policy" {
  name = "cloudtrail-cloudwatch-logs-policy"
  role = aws_iam_role.cloudtrail_cloudwatch_logs_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "logs:CreateLogStream",
          "logs:PutLogEvents",
        ]
        Effect = "Allow"
        Resource = "${aws_cloudwatch_log_group.cloudtrail_log_group.arn}:*" # 特定のロググループに制限
      },
    ]
  })
}

# CloudTrail 証跡の定義
resource "aws_cloudtrail" "main_trail" {
  name                          = local.cloudtrail_name # local変数からCloudTrail名を参照
  is_organization_trail         = false # 組織レベルのCloudTrailの場合は 'true' に設定
  include_global_service_events = true
  is_multi_region_trail         = true
  enable_log_file_validation    = true

  # S3バケットへのログ保存 (必須)
  s3_bucket_name = aws_s3_bucket.cloudtrail_logs_bucket.id
  s3_key_prefix  = "cloudtrail"

  # CloudWatch Logsとの連携設定
  cloud_watch_logs_group_arn = aws_cloudwatch_log_group.cloudtrail_log_group.arn
  cloud_watch_logs_role_arn  = aws_iam_role.cloudtrail_cloudwatch_logs_role.arn

  # オプション: SNS通知設定 (ログファイル配信のエラー通知など)
  # sns_topic_name = aws_sns_topic.cloudtrail_sns_topic.name
}

# CloudTrailログの保存先S3バケットを定義
resource "aws_s3_bucket" "cloudtrail_logs_bucket" {
  bucket = "your-cloudtrail-logs-bucket-name-${data.aws_caller_identity.current.account_id}" # 一意の名前を指定
  # S3バケットポリシーでCloudTrailからの書き込みを許可する設定も必要
}

# CloudTrailログバケットポリシー (例)
resource "aws_s3_bucket_policy" "cloudtrail_bucket_policy" {
  bucket = aws_s3_bucket.cloudtrail_logs_bucket.id
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid       = "AWSCloudTrailAclCheck"
        Effect    = "Allow"
        Principal = { Service = "cloudtrail.amazonaws.com" }
        Action    = "s3:GetBucketAcl"
        Resource  = aws_s3_bucket.cloudtrail_logs_bucket.arn
      },
      {
        Sid       = "AWSCloudTrailWrite"
        Effect    = "Allow"
        Principal = { Service = "cloudtrail.amazonaws.com" }
        Action = [
          "s3:PutObject",
          "s3:PutObjectAcl",
        ]
        Resource = "${aws_s3_bucket.cloudtrail_logs_bucket.arn}/cloudtrail/*" # S3 key prefixに合わせる
        Condition = {
          StringEquals = {
            "s3:x-amz-acl" = "bucket-owner-full-control"
          }
        }
      },
    ]
  })
}

# 現在のAWSアカウントIDを取得するためのデータソース
data "aws_caller_identity" "current" {}

上記の例では、以下のリソースを定義しています。

  1. aws_cloudwatch_log_group.cloudtrail_log_group: CloudTrailログが送信されるCloudWatch Logsグループ。
  2. aws_iam_role.cloudtrail_cloudwatch_logs_role および aws_iam_role_policy.cloudtrail_cloudwatch_logs_policy: CloudTrailがCloudWatch Logsにログを書き込むために必要なIAMロールとポリシー。
  3. aws_cloudtrail.main_trail: CloudTrail証跡自体。ここでcloud_watch_logs_group_arncloud_watch_logs_role_arnに、それぞれ上で定義したリソースのARNを指定して連携を確立します。
  4. aws_s3_bucket.cloudtrail_logs_bucket および aws_s3_bucket_policy.cloudtrail_bucket_policy: CloudTrailログのプライマリ保存先となるS3バケットとそのポリシー。CloudTrail証跡にはS3バケットへのログ保存が必須です。

your-cloudtrail-nameyour-cloudtrail-logs-bucket-name などのプレースホルダーは、実際の環境に合わせて修正してください。特にS3バケット名はグローバルに一意である必要があります。

最後に

この記事では、CloudTrail証跡と連携されているCloudWatch Log Groupが存在しない状態について、リスクと対策を解説しました。CloudTrailログをCloudWatch Logsに連携することは、AWS環境におけるセキュリティと運用の両面で極めて重要です。この連携により、異常なアクティビティの早期検知、迅速なインシデント対応、コンプライアンス要件の達成が可能になります。

この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。

運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。

最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです

この記事をシェアする

クラウドセキュリティ対策実践集一覧へ戻る

貴社の利用状況に合わせた見積もりを作成します。

料金プランを詳しく見る