S3バケットのサーバーアクセスログ有効化手順

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

この記事では、S3バケットのサーバーアクセスログ有効化について、リスクと対策を解説します。

ポリシーの説明

S3サーバーアクセスログは、S3バケットに対するすべてのリクエストの詳細な記録を提供する重要なセキュリティ機能です。この機能により、バケットへのアクセス元IP、実行された操作、HTTPステータスコード、エラーコードなど、セキュリティ監査とトラブルシューティングに必要な包括的な情報が記録されます。

デフォルトでは無効になっているため、手動で有効化する必要があります。記録されるログには以下の重要な情報が含まれます:

  • リクエスト時刻とリクエスト元のIPアドレス
  • 実行されたアクション(GET、PUT、DELETE等)とレスポンスステータス
  • バケット所有者、リクエスタ、ユーザーエージェント
  • エラーコード、リファラ、ターンアラウンドタイム
  • 署名バージョン、暗号化方式、ホストヘッダー

CloudTrailとの違い: CloudTrailはAWS APIの呼び出しを記録しますが、S3サーバーアクセスログはオブジェクトレベルのアクセス(GET、HEADリクエスト等)も含む、より詳細なログを提供します。両方を有効化することで、包括的な監査証跡を確保できます。

 

修復方法

コンソールでの修復手順

AWSのコンソールを使用して、S3バケットのサーバーアクセスログを有効化します。

ステップ1: ログ保存先バケットの準備

  1. AWS Management ConsoleにサインインしてS3コンソール(https://console.aws.amazon.com/s3/)にアクセス
  2. ログ保存用のバケットを作成(既存のバケットを使用する場合はスキップ)

ステップ2: サーバーアクセスログの有効化

  1. ログを有効化したいソースバケットを選択
  2. 「プロパティ」タブをクリック
  3. 「サーバーアクセスログ」セクションまでスクロールし、「編集」をクリック
  4. 「サーバーアクセスログのリクエスト」で「有効化」を選択
  5. ターゲットバケットの設定:
    • 「ターゲットバケット」フィールドで、ステップ1で作成したログバケットを選択
    • 「ターゲットプレフィックス」にプレフィックスを入力(例:access-logs/)
    • これにより、ログファイルが整理された階層で保存されます
  6. 「変更を保存」をクリック

重要な注意事項:

  • ログ保存先バケット自体にサーバーアクセスログを有効化しないでください(無限ループを防ぐため)
  • ログバケットとソースバケットは同じAWSアカウントとリージョンである必要があります
  • ログファイルの配信には最大1時間の遅延が発生する可能性があります
  • ログバケットへのアクセスは最小権限の原則に基づいて制限してください
  • 本番環境では必ずログバケットの暗号化とバージョニングを有効化してください

Terraformでの修復手順

S3バケットのサーバーアクセスログを有効にするTerraformコードと、主要な修正ポイントを説明します。

完全な実装例:

# データソース
data "aws_caller_identity" "current" {}

# ログ保存用バケット
resource "aws_s3_bucket" "log_bucket" {
  bucket = "my-company-s3-access-logs"

  tags = {
    Name        = "S3 Access Logs"
    Environment = "Production"
    Purpose     = "Security Audit"
  }
}

# ログバケットのバージョニング
resource "aws_s3_bucket_versioning" "log_bucket_versioning" {
  bucket = aws_s3_bucket.log_bucket.id

  versioning_configuration {
    status = "Enabled"
  }
}

# ログバケットの暗号化
resource "aws_s3_bucket_server_side_encryption_configuration" "log_bucket_encryption" {
  bucket = aws_s3_bucket.log_bucket.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

# ログバケットのパブリックアクセスブロック
resource "aws_s3_bucket_public_access_block" "log_bucket_pab" {
  bucket = aws_s3_bucket.log_bucket.id

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

# ログバケット用のバケットポリシー
resource "aws_s3_bucket_policy" "log_bucket_policy" {
  bucket = aws_s3_bucket.log_bucket.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "S3ServerAccessLogsPolicy"
        Effect = "Allow"
        Principal = {
          Service = "logging.s3.amazonaws.com"
        }
        Action = "s3:PutObject"
        Resource = "${aws_s3_bucket.log_bucket.arn}/*"
        Condition = {
          ArnLike = {
            "aws:SourceArn" = aws_s3_bucket.source_bucket.arn
          }
          StringEquals = {
            "aws:SourceAccount" = data.aws_caller_identity.current.account_id
          }
        }
      }
    ]
  })
}

# ソースバケット
resource "aws_s3_bucket" "source_bucket" {
  bucket = "my-application-data-bucket"

  tags = {
    Name        = "Application Data"
    Environment = "Production"
  }
}

# サーバーアクセスログの設定
resource "aws_s3_bucket_logging" "source_bucket_logging" {
  bucket = aws_s3_bucket.source_bucket.id

  target_bucket = aws_s3_bucket.log_bucket.id
  target_prefix = "access-logs/${aws_s3_bucket.source_bucket.id}/"
}

# ライフサイクルポリシー(ログの長期保存とコスト最適化)
resource "aws_s3_bucket_lifecycle_configuration" "log_bucket_lifecycle" {
  bucket = aws_s3_bucket.log_bucket.id

  rule {
    id     = "log_retention_policy"
    status = "Enabled"

    transition {
      days          = 30
      storage_class = "STANDARD_IA"
    }

    transition {
      days          = 90
      storage_class = "GLACIER"
    }

    transition {
      days          = 365
      storage_class = "DEEP_ARCHIVE"
    }

    expiration {
      days = 2555  # 7年間保持(コンプライアンス要件に応じて調整)
    }

    noncurrent_version_expiration {
      noncurrent_days = 90  # 非現行バージョンは90日後に削除
    }
  }
}

 

既存バケットへの適用例:

# 既存バケットをデータソースとして参照
data "aws_s3_bucket" "existing_bucket" {
  bucket = "existing-bucket-name"
}

# 既存バケットにログ設定を追加
resource "aws_s3_bucket_logging" "existing_bucket_logging" {
  bucket = data.aws_s3_bucket.existing_bucket.id

  target_bucket = aws_s3_bucket.log_bucket.id
  target_prefix = "access-logs/${data.aws_s3_bucket.existing_bucket.id}/"
}

 

主要な修正ポイント:

  1. 専用ログバケットの作成: ログ専用のバケットを作成し、ソースバケットと分離
  2. 適切な権限設定: logging.s3.amazonaws.comサービスプリンシパルへの書き込み権限付与
  3. 暗号化の実装: ログデータのセキュリティ確保のためAES-256暗号化を適用
  4. ライフサイクル管理: コスト最適化のため、古いログを自動的に低コストストレージクラスへ移行
  5. 整理されたプレフィックス: バケット名を含むプレフィックスで、複数バケットのログを効率的に管理

最後に

この記事では、S3バケットのサーバーアクセスログ有効化について、リスクと対策を解説しました。

サーバーアクセスログは、セキュリティ監査、インシデント対応、コンプライアンス要件を満たすために不可欠な機能です。CloudTrailと併用することで、包括的な監視体制を構築できます。特に機密データを扱うバケットでは、必ずこの機能を有効化し、定期的にログを分析することを強く推奨します。

この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。 運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。 最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。

参考資料

この記事をシェアする

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

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

料金プランを詳しく見る