Neptune DBクラスターで保管中の暗号化が有効化されていない

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

この記事ではNeptune DB クラスターは、保管中に暗号化について解説します。

ポリシーの説明

[Neptune.1] Neptune DB クラスターは、保管中に暗号化する必要があります

Neptune の Security Hub コントロール – AWS Security Hub

このコントロールは、Neptune DB クラスターが保管中に暗号化されているかどうかをチェックします。Neptune DB クラスターが保管中に暗号化されていない場合、コントロールは失敗します。

Amazon Neptuneは、高速で信頼性の高い、フルマネージドのグラフデータベースサービスです。保管時の暗号化を有効にしない場合、Neptune DBクラスターのストレージに保存されたデータが不正にアクセスされるリスクがあります。特に機密性の高いグラフデータを扱う場合は、保管時の暗号化を有効にすることがセキュリティ上の重要な対策となります。

修復方法

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

既存のNeptune DBクラスターで保管時の暗号化を後から有効にすることはできません。以下の手順で新しいDBクラスターを作成し、データを移行する必要があります。

  1. Neptune > データベースに移動し、対象のデータベースを選択します。
  2. 右上のアクション>バックアップから「スナップショットの取得」をクリック
  1. 作成したスナップショットを選択し、アクションメニューから「スナップショットを復元」をクリックします。

そのまま復元を行うことで暗号化されますが、暗号化設定をカスタマイズする場合はチェックを入れて、AWS KMSを独自のキーに書き換えます。

  1. 設定後、復元をクリックし問題なく復元されたことと、暗号化ありになっていることを確認します。

Terraformでの修復手順

NeptuneクラスターのセキュアなTerraformコードと重要な修正ポイントを説明します。

# KMS key for Neptune encryption
resource "aws_kms_key" "neptune" {
  description             = "KMS key for Neptune encryption"
  deletion_window_in_days = 7
  enable_key_rotation     = true

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "Enable IAM User Permissions"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
        }
        Action   = "kms:*"
        Resource = "*"
      },
      {
        Sid    = "Allow Neptune to use the key"
        Effect = "Allow"
        Principal = {
          Service = "neptune.amazonaws.com"
        }
        Action = [
          "kms:Decrypt",
          "kms:GenerateDataKey",
          "kms:CreateGrant",
          "kms:ReEncrypt*",
          "kms:DescribeKey"
        ]
        Resource = "*"
      }
    ]
  })

  tags = var.tags
}

# KMS alias
resource "aws_kms_alias" "neptune" {
  name          = "alias/neptune-${var.environment}"
  target_key_id = aws_kms_key.neptune.key_id
}

# Subnet group for Neptune
resource "aws_neptune_subnet_group" "main" {
  name        = "neptune-${var.environment}"
  subnet_ids  = var.private_subnet_ids
  description = "Neptune subnet group for ${var.environment}"

  tags = var.tags
}

# Parameter group for Neptune
resource "aws_neptune_parameter_group" "main" {
  family      = "neptune1.2"
  name        = "neptune-params-${var.environment}"
  description = "Neptune parameter group for ${var.environment}"

  tags = var.tags
}

# Security group for Neptune
resource "aws_security_group" "neptune" {
  name        = "neptune-${var.environment}"
  description = "Security group for Neptune cluster"
  vpc_id      = var.vpc_id

  ingress {
    description     = "Neptune port"
    from_port       = 8182
    to_port         = 8182
    protocol        = "tcp"
    security_groups = var.allowed_security_group_ids
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = merge(var.tags, {
    Name = "neptune-${var.environment}"
  })
}

# ★重要: Neptune DB Cluster
resource "aws_neptune_cluster" "main" {
  cluster_identifier = "neptune-${var.environment}"
  engine            = "neptune"
  engine_version    = var.engine_version

  # ★重要: 暗号化設定
  storage_encrypted = true  # 必須: 保管時の暗号化を有効化
  kms_key_arn      = aws_kms_key.neptune.arn

  vpc_security_group_ids = [aws_security_group.neptune.id]
  neptune_subnet_group_name = aws_neptune_subnet_group.main.name
  neptune_parameter_group_name = aws_neptune_parameter_group.main.name

  iam_database_authentication_enabled = true
  backup_retention_period = var.backup_retention_period
  preferred_backup_window = "03:00-04:00"
  skip_final_snapshot    = false
  final_snapshot_identifier = "neptune-${var.environment}-final"

  # IAMロールの関連付け
  iam_roles = [aws_iam_role.neptune_service_role.arn]

  tags = var.tags
}

# Neptune DB Instances
resource "aws_neptune_cluster_instance" "main" {
  count              = var.instance_count
  cluster_identifier = aws_neptune_cluster.main.id
  engine            = "neptune"
  instance_class    = var.instance_class

  neptune_parameter_group_name = aws_neptune_parameter_group.main.name

  # Auto Minor Version Upgrade
  auto_minor_version_upgrade = true

  tags = merge(var.tags, {
    Name = "neptune-${var.environment}-${count.index + 1}"
  })
}

# IAM Role for Neptune
resource "aws_iam_role" "neptune_service_role" {
  name = "neptune-service-role-${var.environment}"

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

  tags = var.tags
}

# CloudWatch Alarm for monitoring
resource "aws_cloudwatch_metric_alarm" "neptune_cpu" {
  alarm_name          = "neptune-cpu-utilization-${var.environment}"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = "2"
  metric_name        = "CPUUtilization"
  namespace          = "AWS/Neptune"
  period             = "300"
  statistic          = "Average"
  threshold          = "80"
  alarm_description  = "Neptune cluster CPU utilization"
  alarm_actions      = var.alarm_sns_topic_arns

  dimensions = {
    DBClusterIdentifier = aws_neptune_cluster.main.id
  }

  tags = var.tags
}

# Variables
variable "environment" {
  description = "Environment name"
  type        = string
}

variable "vpc_id" {
  description = "VPC ID"
  type        = string
}

variable "private_subnet_ids" {
  description = "List of private subnet IDs"
  type        = list(string)
}

variable "allowed_security_group_ids" {
  description = "List of security group IDs allowed to access Neptune"
  type        = list(string)
}

variable "engine_version" {
  description = "Neptune engine version"
  type        = string
  default     = "1.2.1.0"
}

variable "instance_class" {
  description = "Neptune instance class"
  type        = string
  default     = "db.r5.large"
}

variable "instance_count" {
  description = "Number of instances in the cluster"
  type        = number
  default     = 2
}

variable "backup_retention_period" {
  description = "Backup retention period in days"
  type        = number
  default     = 7
}

variable "alarm_sns_topic_arns" {
  description = "List of SNS topic ARNs for CloudWatch alarms"
  type        = list(string)
  default     = []
}

variable "tags" {
  description = "Tags for resources"
  type        = map(string)
  default     = {}
}

# Data sources
data "aws_caller_identity" "current" {}

主要な修正ポイントは以下の通りです:

  1. 保管時の暗号化設定(最重要):
resource "aws_neptune_cluster" "main" {
  storage_encrypted = true  # これが最も重要な設定
  kms_key_arn      = aws_kms_key.neptune.arn
}

この設定により:

  • データの保管時暗号化
  • アクセス制御の強化
  • バックアップと復旧の確保
  • 監視とアラートの設定

が実現されます。

注意: 暗号化はクラスター作成時にのみ設定可能で、後から変更することはできません。既存のクラスターを暗号化する場合は、新しいクラスターを作成してデータを移行する必要があります。

最後に

今回は、Neptune DBクラスターの保管時の暗号化を有効にする方法についてご紹介しました。保管時の暗号化は、保存されたグラフデータを保護するための重要なセキュリティ対策です。

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

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

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

この記事をシェアする

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

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

料金プランを詳しく見る