S3バケットのオブジェクトレベルの読み取りログの有効化設定手順

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

この記事では、Amazon S3バケットで オブジェクトレベルの読み取りイベントのログ記録 が有効になっていない状態について、そのリスクと対策を解説します。

ポリシーの説明

Amazon S3 の Security Hub コントロール – AWS Security Hub

このコントロール AWS アカウント は、 に Amazon S3 バケットのすべての読み取りデータイベントを記録する AWS CloudTrail マルチリージョン証跡が少なくとも 1 つあるかどうかをチェックします。 Amazon S3 S3 バケットの読み取りデータイベントをログに記録するマルチリージョン証跡がアカウントにない場合、コントロールは失敗します。

リスク

Amazon S3は、多くの企業にとって重要なデータレイクやストレージ基盤として利用されています。S3バケット内のオブジェクトは、機密情報や重要な業務データを含むことが多く、そのアクセス状況を詳細に把握することは、セキュリティとコンプライアンスの観点から非常に重要です。オブジェクトレベルの読み取りイベントのログ記録が有効になっていない場合、以下のようなリスクが発生します。

  • データアクセス状況の可視性不足: 誰が、いつ、どのS3オブジェクトを読み取ったかという情報が記録されないため、データへのアクセス状況が不明瞭になります。これにより、不審なデータアクセスがあった場合に、その原因究明や影響範囲の特定が困難になります。
  • コンプライアンス違反: 多くの規制やコンプライアンス基準(例: GDPR、HIPAA、PCI DSS、ISO 27001)では、機密データへのアクセスログの保持が義務付けられています。オブジェクトレベルの読み取りログがない場合、これらの要件を満たせず、監査での指摘や法的リスク、罰金につながる可能性があります。
  • セキュリティインシデントの検知遅延: 内部不正や外部からの不正アクセスによりデータが閲覧された場合でも、オブジェクトレベルのログがなければ、その事実を即座に検知することができません。これにより、被害の拡大を防ぐための初期対応が遅れる可能性があります。
  • フォレンジック調査の困難さ: セキュリティインシデント発生時、詳細なオブジェクトアクセスログがないと、攻撃の経緯や影響範囲を正確に特定するためのフォレンジック調査が著しく困難になります。
  • ユーザー行動の分析不足: 特定のS3オブジェクトに対するユーザーやアプリケーションの行動パターンを分析し、最適化や異常検知に役立てることができません。

対策

S3バケットのオブジェクトレベルの読み取りイベントのログ記録を有効にすることは、データへのアクセス状況を詳細に可視化し、セキュリティ、コンプライアンス、および運用の要件を満たすための重要な対策です。

  • CloudTrail データイベントの有効化: S3オブジェクトレベルのログ記録は、AWS CloudTrailデータイベント として記録されます。CloudTrailトレイルで、対象S3バケットの「読み取り」データイベント(GetObjectなど)をログに記録するように設定します。
  • CloudWatch Logsへの連携: CloudTrailのログを CloudWatch Logs に送信するように設定します。これにより、ログデータを一元的に管理し、メトリクスフィルターやアラームを設定できるようになります。
  • 適切なストレージと保持期間: ログの量が多くなる可能性があるため、S3バケットへのログ保存先を適切に計画し、必要な保持期間を設定します。長期的な保持が必要な場合は、S3のライフサイクルルールを活用してGlacierなどの低コストストレージに移行することも検討します。
  • セキュリティ分析ツールとの統合: ログデータをAmazon Athena、Amazon QuickSight、またはサードパーティのSIEM (Security Information and Event Management) ツールと統合することで、高度なセキュリティ分析や視覚化が可能になります。
  • アラームと通知の設定: 特定の機密オブジェクトへのアクセスや、異常な読み取りパターンを検知するためのCloudWatchアラームを設定し、Amazon SNSなどを通じて関係者に通知を送信します。

修復方法

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

AWSコンソールを使用して、S3バケットのオブジェクトレベル読み取りイベントのログ記録を有効にします。

  1. CloudTrailサービスへ移動: AWSコンソールにログインし、CloudTrail サービスを開きます。
  2. トレイルの選択: 左側のナビゲーションペインで「証跡」を選択し、もしがない場合は、まず新しいトレイルを作成します。
  3. データイベントの設定変更: トレイルの詳細ページで、「データイベント」セクションを見つけ、「編集」をクリックします。
  4. S3セクションの設定:S3」セクションまでスクロールします。
    • ログイベント: 「データイベントのログ記録」がチェックされていることを確認します。
    • データイベントセレクター:
      • 「読み取りイベントのみをログ記録」を選択
  5. 変更の保存: 設定を確認し、「変更を保存」をクリックします。

Terraformでの修復手順

TerraformでS3バケットのオブジェクトレベル読み取りイベントのログ記録を有効にするには、aws_cloudtrail リソースの event_selector ブロックを設定します。

前提: 既にCloudTrailトレイルが作成されており、ログがS3バケットに保存され、CloudWatch Logsに送信されていると仮定します。

# 既存のCloudTrailトレイルを参照 (もし既存のものを更新する場合)
# data "aws_cloudtrail" "existing_trail" {
#   name = "my-cloudtrail-trail" # あなたのCloudTrailトレイル名に置き換えてください
# }

# 新しいCloudTrailトレイルを作成する場合 (例)
resource "aws_s3_bucket" "cloudtrail_log_bucket" {
  bucket = "my-cloudtrail-logs-bucket-unique-12345" # グローバルで一意の名前に変更
  force_destroy = true # テスト用。本番環境ではfalseを推奨

  tags = {
    Name = "CloudTrailLogBucket"
  }
}

resource "aws_cloudtrail" "my_cloudtrail_with_s3_data_events" {
  name                          = "my-cloudtrail-with-s3-data-events"
  s3_bucket_name                = aws_s3_bucket.cloudtrail_log_bucket.id
  is_organization_trail         = false # 組織トレイルにする場合はtrue
  include_global_service_events = true
  is_multi_region_trail         = true

  # CloudWatch Logsへのログ送信設定 (アラームのために推奨)
  cloud_watch_logs_group_arn = aws_cloudwatch_log_group.cloudtrail_log_group.arn
  cloud_watch_logs_role_arn  = aws_iam_role.cloudtrail_cw_role.arn

  # S3オブジェクトレベルのデータイベントを設定
  event_selector {
    read_write_type           = "All" # または "ReadOnly" (読み取りイベントのみを対象にする場合)
    include_management_events = true
    # 管理イベントをログに記録するかどうか。通常はtrue。

    # S3バケットのデータイベントを指定
    data_resource {
      type   = "AWS::S3::Object"
      # すべてのS3バケットのオブジェクトイベントをログに記録する場合:
      values = ["arn:aws:s3:::"]
      # 特定のS3バケットのオブジェクトイベントをログに記録する場合:
      # values = ["${aws_s3_bucket.my_data_bucket.arn}/*"] # 特定のS3バケットを参照
    }
  }

  tags = {
    Name = "CloudTrail_S3_DataEvents"
  }
}

# CloudTrailログ用のS3バケットポリシー (CloudTrailがログを書き込めるようにする)
resource "aws_s3_bucket_policy" "cloudtrail_log_bucket_policy" {
  bucket = aws_s3_bucket.cloudtrail_log_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_log_bucket.arn
      },
      {
        Sid       = "AWSCloudTrailWrite"
        Effect    = "Allow"
        Principal = { Service = "cloudtrail.amazonaws.com" }
        Action    = "s3:PutObject"
        Resource  = "${aws_s3_bucket.cloudtrail_log_bucket.arn}/AWSLogs/${data.aws_caller_identity.current.account_id}/*"
        Condition = {
          StringEquals = {
            "s3:x-amz-acl" = "bucket-owner-full-control"
          }
        }
      }
    ]
  })
}

# CloudWatch Logsグループ (CloudTrailログ用)
resource "aws_cloudwatch_log_group" "cloudtrail_log_group" {
  name              = "/aws/cloudtrail/my-cloudtrail-with-s3-data-events" # トレイル名と一致させる
  retention_in_days = 90 # ログ保持期間を適切に設定
}

# CloudTrailがCloudWatch Logsに書き込むためのIAMロール
resource "aws_iam_role" "cloudtrail_cw_role" {
  name = "cloudtrail-to-cloudwatch-logs-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "cloudtrail.amazonaws.com"
        }
      },
    ]
  })
}

resource "aws_iam_role_policy" "cloudtrail_cw_policy" {
  name = "cloudtrail-cw-logs-policy"
  role = aws_iam_role.cloudtrail_cw_role.id
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect   = "Allow"
        Action   = [
          "logs:CreateLogStream",
          "logs:PutLogEvents"
        ]
        Resource = "${aws_cloudwatch_log_group.cloudtrail_log_group.arn}:*"
      }
    ]
  })
}

# 現在のAWSアカウント情報とリージョン情報を取得
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}

# 特定のS3データバケットを監視する場合の例 (event_selectorのvaluesと連携)
# resource "aws_s3_bucket" "my_data_bucket" {
#   bucket = "my-specific-data-bucket-to-monitor-12345"
#   tags = {
#     Name = "MyDataBucket"
#   }
# }

上記のTerraformコードでは、aws_cloudtrail リソース内で event_selector ブロックを設定し、data_resource タイプを "AWS::S3::Object" と指定することで、S3オブジェクトレベルのデータイベントのログ記録を有効にしています。

  • read_write_type = "ReadOnly" を設定することで、読み取りイベントのみを対象とすることができます。全てのイベントを対象にする場合は "All" を使用します。
  • values = ["arn:aws:s3:::"] とすることで、アカウント内のすべてのS3バケットのオブジェクトイベントをログに記録します。
  • 特定のS3バケットのみを対象にする場合は、values = ["${aws_s3_bucket.my_data_bucket.arn}/*"] のように、対象バケットのARNを指定します。(コメントアウトされている部分を参照)

my-cloudtrail-logs-bucket-unique-12345your-security-email@example.com などのプレースホルダーは、実際の環境に合わせて修正してください。

最後に

この記事では、S3バケットのオブジェクトレベル読み取りイベントのログ記録が有効になっていない状態のリスクと、その対策について解説しました。CloudTrailのデータイベントを活用してS3オブジェクトへのアクセスを詳細にログ記録することは、データセキュリティ、コンプライアンス、およびインシデント対応能力を大幅に向上させるために不可欠です。

貴社のS3バケットでは、オブジェクトレベルの読み取りイベントが適切にログ記録されていますか?ぜひ、この機会に設定を確認・強化してみてください。

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

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

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

この記事をシェアする

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

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

料金プランを詳しく見る