パブリックアクセス可能なDocumentDB 手動クラスタースナップショットの非公開化設定手順

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

この記事では、Amazon DocumentDB クラスタースナップショットのパブリックアクセス設定に関するセキュリティポリシーについて解説します。

ポリシーの説明

[DocumentDB.3] Amazon DocumentDB 手動クラスタースナップショットはパブリックにできません

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

このコントロールは、Amazon DocumentDB の手動クラスタースナップショットがパブリックかどうかをチェックします。手動クラスタースナップショットがパブリックの場合、コントロールは失敗します。

このポリシーは、Amazon DocumentDB の手動クラスタースナップショットがインターネットから誰でもアクセスできないようにすることを求めています。パブリックアクセスを許可すると、スナップショットに含まれる機密データが漏洩したり、不正アクセスが行われたりするリスクが高まります。DocumentDB クラスタースナップショットにはデータベース全体のデータが含まれるため、厳格なアクセス制御が不可欠です。

修復方法

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

  1. AWS マネジメントコンソールにログインし、DocumentDB コンソールを開きます。
  2. 「スナップショット」を選択し、パブリックアクセスが許可されているスナップショットを特定します。
  3. 該当のスナップショットを選択し、「アクション」>「スナップショットを共有」をクリックします。
  4. DB スナップショットの可視性で、「プライベート」をクリックします。

Terraformでの修復手順

Terraformには、既存の手動DocumentDBクラスタースナップショットの共有属性(パブリック/プライベート)を直接管理する専用のリソースが現在(2025年4月時点)ありません。そのため、ここでは回避策として null_resourcelocal-exec プロビジョナーを使用して、AWS CLIコマンドを実行し、特定のスナップショットをプライベートにする方法を示します。

# AWSプロバイダーの設定
provider "aws" {
  region = "ap-northeast-1"  # 東京リージョン
}

# 変数定義
variable "snapshot_identifier" {
  type        = string
  description = "修正するDocumentDBスナップショットの識別子"
}

# nullリソースを使用してスナップショット属性を修正
resource "null_resource" "modify_snapshot_attribute" {
  triggers = {
    snapshot_identifier = var.snapshot_identifier
  }

  provisioner "local-exec" {
    command = <<EOT
      aws docdb modify-db-cluster-snapshot-attribute \\
        --db-cluster-snapshot-identifier ${var.snapshot_identifier} \\
        --attribute-name restore \\
        --values-to-remove all \\
        --region ap-northeast-1
    EOT
  }
}

# スナップショットの属性を取得
data "aws_lambda_invocation" "get_snapshot_attribute" {
  function_name = aws_lambda_function.get_snapshot_attribute.function_name

  input = jsonencode({
    snapshot_identifier = var.snapshot_identifier
  })

  depends_on = [null_resource.modify_snapshot_attribute]
}

# Lambda関数のIAMロール
resource "aws_iam_role" "lambda_role" {
  name = "docdb_snapshot_attribute_role"

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

# Lambda関数のIAMポリシー
resource "aws_iam_role_policy" "lambda_policy" {
  role = aws_iam_role.lambda_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "docdb:DescribeDBClusterSnapshotAttributes"
        ]
        Resource = "*"
      }
    ]
  })
}

# Lambda関数
resource "aws_lambda_function" "get_snapshot_attribute" {
  filename      = "lambda_function.zip"
  function_name = "get_docdb_snapshot_attribute"
  role          = aws_iam_role.lambda_role.arn
  handler       = "lambda_function.lambda_handler"
  runtime       = "python3.8"

  source_code_hash = filebase64sha256("lambda_function.zip")
}

# 出力: スナップショットの公開状態
output "is_public" {
  value = jsondecode(data.aws_lambda_invocation.get_snapshot_attribute.result)["is_public"]
}

注意点:

  • この方法は、Terraformの管理外でリソース属性を変更するため、Terraformの状態ファイル(tfstate)には変更が反映されません。
  • local-exec は、Terraformを実行する環境にAWS CLIがインストールされ、適切な権限が設定されている必要があります。
  • スナップショット識別子 (snapshot_identifier) は変数として渡す必要があります。
# AWSプロバイダーの設定
provider "aws" {
  region = "ap-northeast-1"  # 対象のスナップショットが存在するリージョン
}

# 変数定義
variable "snapshot_identifier" {
  type        = string
  description = "プライベートにするDocumentDB手動スナップショットの識別子"
}

# null_resourceを使用してスナップショット属性を修正 (Workaround)
resource "null_resource" "make_snapshot_private" {
  # snapshot_identifierが変わるたびにトリガーされるように設定
  triggers = {
    snapshot_id = var.snapshot_identifier
    # timestamp   = timestamp() # 必要に応じて毎回実行させる場合
  }

  # local-execプロビジョナーでAWS CLIコマンドを実行
  provisioner "local-exec" {
    command = <<EOT
      aws docdb modify-db-cluster-snapshot-attribute \\\\
        --db-cluster-snapshot-identifier ${self.triggers.snapshot_id} \\\\
        --attribute-name restore \\\\
        --values-to-remove all \\\\
        --region ${provider.aws.region} || exit 0 
        # エラーが発生してもTerraformが停止しないように `|| exit 0` を追加 (冪等性のため)
        # 既にプライベートの場合、コマンドはエラーになる可能性があるため
    EOT
    # interpreter = ["bash", "-c"] # Windows以外の場合、通常は不要
    when = create # 作成時(またはトリガー変更時)に実行
  }

  # 破棄時にもし何か処理が必要なら destroy プロビジョナーを追加
  # provisioner "local-exec" {
  #   when    = destroy
  #   command = "echo 'Cleanup action for ${self.triggers.snapshot_id}'"
  # }
}

# 出力 (実行されたスナップショットID)
output "modified_snapshot_identifier" {
  description = "Attribute modification attempted for this snapshot ID."
  value       = null_resource.make_snapshot_private.triggers.snapshot_id
}

コードのポイント:

  • null_resource: Terraformで直接管理できない外部アクションを実行するためだけに使用されるリソースです。
  • local-exec: Terraformを実行するローカルマシン上でシェルコマンドを実行します。
    • aws docdb modify-db-cluster-snapshot-attribute ... --values-to-remove all: このAWS CLIコマンドが、指定されたスナップショットから全ての共有設定(allを指定)を削除し、結果的にスナップショットをプライベートにする実際の操作です。
    • || exit 0: CLIコマンドが失敗しても(例: スナップショットが既にプライベートだった場合など)、Terraformの実行がエラーで停止しないようにしています。冪等性を担保するための一つの方法です。
  • triggers: このマップ内の値が変更されると、local-exec プロビジョナーが再実行されます。スナップショットIDが変わった場合に再実行されるようにしています。

このTerraformコードを適用するには、snapshot_identifier 変数に対象のスナップショットIDを指定して terraform apply を実行します。

最後に

今回は、DocumentDB クラスタースナップショットのパブリックアクセス設定について解説しました。パブリックアクセスを許可すると、データ漏洩や不正アクセスのリスクが高まります。必ず手動スナップショットの共有設定を確認し、不要なパブリックアクセスを無効にして、厳格なアクセス制御を実施してください。

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

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

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

この記事をシェアする

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

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

料金プランを詳しく見る