Amazon DocumentDB クラスターの監査ログの設定について

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

この記事では、Amazon DocumentDB クラスターの監査ログが CloudWatch Logs に発行されていない問題について、リスクと対策を解説します。

ポリシーの説明

すべてのAmazon DocumentDBクラスターで監査ログをCloudWatch Logsに発行するよう設定してください。これにより、データベース操作の詳細な監査証跡を確保し、セキュリティインシデントの調査や規制遵守を支援します。監査ログには、接続の試行、認証の成功と失敗、DDL(Data Definition Language)イベント、ユーザー管理イベント、権限の変更などの重要な情報が記録されます。ログデータを定期的に分析し、異常なアクティビティを検出するプロセスを確立してください。また、ログの保持期間を組織のコンプライアンス要件に合わせて適切に設定し、必要に応じてログデータをS3にアーカイブしてください。

修復方法

コンソールでの修復手順

AWSマネジメントコンソールを使用して、DocumentDBクラスターの監査ログをCloudWatch Logsに発行する設定を行います。

  1. AWSマネジメントコンソールにログインします。
  2. 「Services」から「Amazon DocumentDB」を選択します。
  3. 画面左側のメニューから「Clusters」を選択します。
  4. 監査ログを有効にするクラスターを選択します。
  5. 「Configuration」タブで現在の設定を確認します。
  6. 「Actions」ドロップダウンメニューから「Modify」を選択します。
  7. 「Log exports」セクションまでスクロールし、「監査ログ」のチェックボックスをオンにします。 重要: 「プロファイラーのログ」も同時に有効化することで、パフォーマンス分析が可能になります。
  1. 「Apply immediately」を選択して即座に変更を適用するか、次のメンテナンスウィンドウで適用するかを選択します。
  2. 画面下部の「Continue」をクリックし、変更内容を確認します。
  3. 「Modify cluster」ボタンをクリックして変更を適用します。

注意: 変更の適用には数分かかる場合があります。クラスターのステータスが「Available」になるまで待ってください。

Terraformでの修復手順

DocumentDBクラスターの監査ログをCloudWatch Logsに発行する包括的なTerraformコードです。

# DocumentDBクラスターパラメータグループ
resource "aws_docdb_cluster_parameter_group" "audit_enabled" {
  family      = var.docdb_family  # DocumentDBバージョンに応じて動的に設定
  name        = "${var.cluster_name}-audit-params"
  description = "DocumentDB cluster parameter group with comprehensive audit and profiling"

  parameter {
    name  = "audit_logs"
    value = "enabled"
  }

  parameter {
    name  = "profiler"
    value = "enabled"  # パフォーマンス監視も有効化
  }

  parameter {
    name  = "profiler_threshold_ms"
    value = var.profiler_threshold_ms  # 環境に応じて調整可能
  }

  # TTL設定の有効化(DocumentDB 4.0以降)
  parameter {
    name  = "ttl_monitor"
    value = "enabled"
  }

  tags = var.common_tags
}

# CloudWatch Logsグループの作成
resource "aws_cloudwatch_log_group" "docdb_audit" {
  name              = "/aws/docdb/${var.cluster_name}/audit"
  retention_in_days = var.log_retention_days  # コンプライアンス要件に応じて設定
  kms_key_id        = var.kms_key_id         # ログの暗号化(オプション)

  tags = merge(
    var.common_tags,
    {
      Name        = "${var.cluster_name}-audit-logs"
      Purpose     = "DocumentDB Audit Logs"
      Compliance  = "Required"
    }
  )
}

# DocumentDBクラスター
resource "aws_docdb_cluster" "main" {
  cluster_identifier              = var.cluster_name
  engine                         = "docdb"
  engine_version                 = var.engine_version
  master_username                = var.master_username
  master_password                = random_password.master.result
  db_cluster_parameter_group_name = aws_docdb_cluster_parameter_group.audit_enabled.name

  # 監査ログをCloudWatch Logsに発行
  enabled_cloudwatch_logs_exports = ["audit", "profiler"]

  # セキュリティ設定
  storage_encrypted              = true
  kms_key_id                    = var.kms_key_id
  backup_retention_period       = var.backup_retention_period
  preferred_backup_window       = var.backup_window
  preferred_maintenance_window  = var.maintenance_window

  # 削除保護
  deletion_protection = var.deletion_protection
  skip_final_snapshot = false
  final_snapshot_identifier = "${var.cluster_name}-final-snapshot-${formatdate("YYYY-MM-DD-hhmm", timestamp())}"

  # ネットワーク設定
  db_subnet_group_name   = aws_docdb_subnet_group.main.name
  vpc_security_group_ids = [aws_security_group.docdb.id]

  tags = var.common_tags

  depends_on = [
    aws_cloudwatch_log_group.docdb_audit
  ]
}

# パスワード生成(セキュアな管理)
resource "random_password" "master" {
  length  = 32
  special = true
}

# Secrets Managerでパスワードを管理
resource "aws_secretsmanager_secret" "docdb_master" {
  name                    = "${var.cluster_name}-master-password"
  recovery_window_in_days = 7
}

resource "aws_secretsmanager_secret_version" "docdb_master" {
  secret_id     = aws_secretsmanager_secret.docdb_master.id
  secret_string = jsonencode({
    username = var.master_username
    password = random_password.master.result
    engine   = "docdb"
    host     = aws_docdb_cluster.main.endpoint
    port     = aws_docdb_cluster.main.port
  })
}

# CloudWatch アラーム(監査ログの監視)
resource "aws_cloudwatch_log_metric_filter" "auth_failures" {
  name           = "${var.cluster_name}-auth-failures"
  log_group_name = aws_cloudwatch_log_group.docdb_audit.name
  pattern        = "[time, request_id, connection_id, session_id, type=\"AUTHENTICATION_FAILURE\", ...]"

  metric_transformation {
    name      = "AuthenticationFailures"
    namespace = "DocumentDB/${var.cluster_name}"
    value     = "1"
    default_value = "0"
  }
}

# DDL操作の監視(スキーマ変更の追跡)
resource "aws_cloudwatch_log_metric_filter" "ddl_operations" {
  name           = "${var.cluster_name}-ddl-operations"
  log_group_name = aws_cloudwatch_log_group.docdb_audit.name
  pattern        = "[time, request_id, connection_id, session_id, type=\"DDL\", ...]"

  metric_transformation {
    name      = "DDLOperations"
    namespace = "DocumentDB/${var.cluster_name}"
    value     = "1"
    default_value = "0"
  }
}

# 権限変更の監視
resource "aws_cloudwatch_log_metric_filter" "privilege_changes" {
  name           = "${var.cluster_name}-privilege-changes"
  log_group_name = aws_cloudwatch_log_group.docdb_audit.name
  pattern        = "[time, request_id, connection_id, session_id, type=\"PRIVILEGE_CHANGE\", ...]"

  metric_transformation {
    name      = "PrivilegeChanges"
    namespace = "DocumentDB/${var.cluster_name}"
    value     = "1"
    default_value = "0"
  }
}

resource "aws_cloudwatch_metric_alarm" "auth_failures" {
  alarm_name          = "${var.cluster_name}-excessive-auth-failures"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 1
  metric_name        = "AuthenticationFailures"
  namespace          = "DocumentDB/${var.cluster_name}"
  period             = 300
  statistic          = "Sum"
  threshold          = 5
  alarm_description  = "Alert when authentication failures exceed threshold"
  alarm_actions      = [var.sns_topic_arn]
}

# 変数定義
variable "cluster_name" {
  type        = string
  description = "Name of the DocumentDB cluster"
  validation {
    condition     = can(regex("^[a-z][a-z0-9-]*$", var.cluster_name))
    error_message = "Cluster name must start with lowercase letter and contain only lowercase letters, numbers, and hyphens."
  }
}

variable "docdb_family" {
  type        = string
  description = "DocumentDB parameter group family"
  default     = "docdb5.0"  # 最新バージョンをデフォルトに
  validation {
    condition     = contains(["docdb3.6", "docdb4.0", "docdb5.0"], var.docdb_family)
    error_message = "DocumentDB family must be one of: docdb3.6, docdb4.0, docdb5.0."
  }
}

variable "profiler_threshold_ms" {
  type        = number
  description = "Profiler threshold in milliseconds for slow query logging"
  default     = 100
  validation {
    condition     = var.profiler_threshold_ms >= 0 && var.profiler_threshold_ms <= 2147483647
    error_message = "Profiler threshold must be between 0 and 2147483647 milliseconds."
  }
}

variable "log_retention_days" {
  type        = number
  description = "CloudWatch Logs retention period in days"
  default     = 90
  validation {
    condition     = contains([1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653], var.log_retention_days)
    error_message = "Log retention days must be a valid CloudWatch Logs retention period."
  }
}

variable "kms_key_id" {
  type        = string
  description = "KMS key ID for encryption"
  default     = null
}

variable "common_tags" {
  type        = map(string)
  description = "Common tags to apply to all resources"
  default     = {}
}

variable "sns_topic_arn" {
  type        = string
  description = "SNS topic ARN for alarm notifications"
}

variable "engine_version" {
  type        = string
  description = "DocumentDB engine version"
  default     = "5.0.0"
}

variable "master_username" {
  type        = string
  description = "Master username for DocumentDB cluster"
  default     = "docdbadmin"
  sensitive   = true
}

variable "backup_retention_period" {
  type        = number
  description = "Backup retention period in days"
  default     = 7
  validation {
    condition     = var.backup_retention_period >= 1 && var.backup_retention_period <= 35
    error_message = "Backup retention period must be between 1 and 35 days."
  }
}

variable "backup_window" {
  type        = string
  description = "Preferred backup window"
  default     = "03:00-04:00"
}

variable "maintenance_window" {
  type        = string
  description = "Preferred maintenance window"
  default     = "sun:04:00-sun:05:00"
}

variable "deletion_protection" {
  type        = bool
  description = "Enable deletion protection"
  default     = true
}

 

主要な修正ポイント

  1. 監査ログの有効化: enabled_cloudwatch_logs_exports = ["audit", "profiler"]で監査ログとプロファイラーログの両方を有効化
  2. パラメータグループ: 監査ログを有効にするため、カスタムパラメータグループを作成しaudit_logsenabledに設定
  3. セキュリティ強化:
    • パスワードをSecrets Managerで安全に管理
    • ログとストレージの暗号化
    • 削除保護の有効化
  4. 監視の実装: CloudWatch Metricsフィルターとアラームで認証失敗を監視
  5. コンプライアンス対応: ログ保持期間を変数化し、要件に応じて調整可能

最後に

この記事では、Amazon DocumentDB クラスターの監査ログが CloudWatch Logs に発行されていない問題について、リスクと対策を解説しました。

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

参考資料

この記事をシェアする

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

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

料金プランを詳しく見る