RDSインスタンスにおけるCMKでの暗号化について

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

今回は、Amazon RDS (Relational Database Service) のデータベースインスタンスがAWS管理キーで暗号化されており、カスタマー管理キー (CMK) 以上のレベルで暗号化されていない状態について、そのリスクと対策を解説します。

リスク

Amazon RDSは、リレーショナルデータベースをAWSクラウドで簡単にセットアップ、運用、スケールできるフルマネージドサービスです。MySQL、PostgreSQL、SQL Server、Oracle、MariaDB、Amazon Auroraなど多様なデータベースエンジンをサポートしています。RDSは保管時の暗号化機能を提供していますが、デフォルトではAWS管理キー(AWS managed key)が使用されるか、暗号化自体が無効になっている場合があります。この設定のまま運用している場合、以下のような重大なセキュリティおよびコンプライアンス上のリスクが発生します。

  • 機密データの露出リスク: RDSデータベースには、顧客情報、トランザクションデータ、個人識別情報(PII)、認証情報など、企業にとって最も機密性の高い情報が保存されていることがほとんどです。保管時に暗号化されていない場合、またはAWS管理キーのみで暗号化されている場合、データベースファイルが不正にアクセスされたり、バックアップが漏洩したりした場合に、平文でデータが露出するリスクが高まります。
  • 鍵管理の制御不足: AWS管理キーはAWSによって管理され、ユーザーは鍵のライフサイクル(作成、ローテーション、無効化、削除)やアクセス制御を詳細に制御できません。より高いセキュリティ要件を持つ組織では、鍵の生成、保管、利用、ローテーションなどを自身で完全に管理できるカスタマー管理キー (CMK) またはそれ以上のセキュリティレベルのキーの利用が不可欠となります。
  • 鍵の使用状況の可視性不足: AWS管理キーの使用状況はKMSのログに詳細に記録されないため、誰がいつ暗号化/復号化操作を行ったかといった詳細な監査証跡を追跡することが困難です。CMKを使用すると、KMSのAPI呼び出しがCloudTrailに記録され、鍵の使用状況を完全に可視化できます。
  • データベースバックアップの脆弱性: RDSインスタンスの暗号化設定は、自動バックアップ、リードレプリカ、スナップショットにも適用されます。インスタンスが暗号化されていない、またはCMKで暗号化されていない場合、これらのバックアップも同様に保護されず、データ漏洩のリスクを高めます。

対策

Amazon RDSデータベースインスタンスのデータをKMSのカスタマー管理キー (CMK) またはCloudHSMキーで暗号化することは、上記のすべてのリスクを軽減し、セキュリティ体制を大幅に強化するための重要なベストプラクティスです。

  • 保管時の暗号化の有効化: RDSインスタンスまたはDBクラスターを作成する際に、必ず保管時の暗号化を有効にします。これにより、データベースインスタンスのストレージ、自動バックアップ、リードレプリカ、スナップショットが暗号化されます。
  • KMS カスタマー管理キー (CMK) の使用: KMSで作成したカスタマー管理キーを指定します。CMKを使用することで、鍵の生成、ローテーション、無効化、削除、およびアクセス権限(キーポリシー)をユーザー自身が完全に制御できるようになります。これは、最も一般的なセキュリティ強化策です。
  • CloudHSMキーの使用 (最高レベルのセキュリティ): FIPS 140-2 Level 3認証のハードウェアセキュリティモジュール (HSM) に保管されたキーを使用したい場合は、AWS CloudHSMと統合できます。これは、最も厳格なセキュリティおよびコンプライアンス要件を持つ組織に適しており、鍵がAWSのデータセンター内でFIPS検証済みのハードウェアに安全に保管されることを保証します。
  • 最小特権の原則に基づくキーポリシー: CMKのキーポリシーを設定する際には、RDSサービスがデータベースの暗号化および復号化に必要な最小限の権限のみを付与するようにします。具体的には、RDSサービスプリンシパル(rds.amazonaws.com)に kms:Encrypt, kms:Decrypt, kms:ReEncrypt*, kms:GenerateDataKey*, kms:DescribeKey などの権限を許可します。
  • 新規インスタンス/クラスターでの有効化: RDSの暗号化設定は、インスタンスまたはクラスター作成時のみに指定できます。既存の暗号化されていない、またはAWS管理キーで暗号化されたインスタンスをCMKで暗号化するには、スナップショットを取得し、そのスナップショットを新しいCMKで暗号化して復元するプロセスが必要です。
  • AWS CloudTrailとの統合: CMKまたはCloudHSMキーの使用状況はAWS CloudTrailに記録されます。これにより、誰がいつ暗号化/復号化操作を行ったかを監査し、セキュリティイベントを監視できます。

修復方法

Amazon RDSデータベースインスタンスの暗号化をKMSカスタマー管理キー(CMK)で有効にする方法は、AWSコンソールまたはTerraformで行えます。CloudHSMキーを使用する場合は、先にAWS CloudHSMクラスターとそれに統合されたKMSキーを作成する必要があります。

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

AWSコンソールを使用して、Amazon RDSデータベースインスタンスの作成時にKMS CMKで暗号化を有効にします。

前提:

  • RDSデータベースを暗号化するためのAWS KMS カスタマー管理キー (CMK) が既に存在すること。
    • CMKのキーポリシーには、RDSサービス (rds.amazonaws.com) がキーを使用するための適切な権限(kms:Encrypt, kms:Decrypt など)が付与されている必要があります。
  1. Amazon RDSサービスへ移動: AWSコンソールにログインし、Amazon RDS サービスを開きます。
  2. データベースの作成: 左側のナビゲーションペインで「データベース」を選択し、「データベースの作成」をクリックします。
  3. エンジンの選択と設定:
    • 希望するエンジンタイプ(例: MySQL、PostgreSQL、Amazon Auroraなど)を選択します。
    • テンプレート(例: 本番、開発/テスト)を選択します。
    • DBインスタンス識別子、マスターユーザー名、パスワードなどを設定します。
  4. 接続とセキュリティの設定:
    • 追加設定」または「ストレージ」セクションまでスクロールします。
    • 暗号化」セクションを見つけます。
    • 暗号化を有効にする」にチェックを入れます。
    • AWS Key Management Service キー」または「カスタマー管理キー (CMK)」のドロップダウンメニューから、使用したい既存のKMS CMKを選択します。
      • もし適切なCMKがリストに表示されない場合は、正しいIAM権限があるか、またはCMKが作成されているか確認してください。
  1. その他の設定(VPC、サブネットグループ、セキュリティグループ、バックアップなど)を構成します。
  2. データベースの作成: 設定内容を確認し、「データベースの作成」をクリックしてデータベースインスタンス(またはクラスター)をプロビジョニングします。

これで、Amazon RDSデータベースインスタンス(またはクラスター)に保存されるデータは、指定したKMS CMKを使用して保管時に暗号化されるようになります。既存のインスタンスの暗号化キーを変更することはできないため、既存のインスタンスをCMKで暗号化したい場合は、スナップショットを取得し、CMKで暗号化された新しいインスタンスとして復元する必要があります。

Terraformでの修復手順

TerraformでAmazon RDSデータベースインスタンスの暗号化をKMSカスタマー管理キー(CMK)で有効にするには、aws_db_instance または aws_rds_cluster リソースの kms_key_id パラメータを設定します。

単一インスタンスの場合 (aws_db_instance):

# (例) RDSインスタンス暗号化用のKMSカスタマー管理キー (CMK)
resource "aws_kms_key" "rds_cmk" {
  description             = "KMS key for RDS instance encryption"
  deletion_window_in_days = 10 # キーの削除をスケジュールするまでの日数
  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 RDS Service to use the key"
        Effect = "Allow",
        Principal = {
          Service = "rds.amazonaws.com"
        },
        Action = [
          "kms:Encrypt",
          "kms:Decrypt",
          "kms:ReEncrypt*",
          "kms:GenerateDataKey*",
          "kms:DescribeKey"
        ],
        Resource = "*"
      }
    ]
  })
  tags = {
    Name = "RDS_CMK"
  }
}

# (前提) VPC, サブネットグループ, セキュリティグループ
# RDSインスタンスをデプロイするVPC, サブネットグループ, セキュリティグループを定義します
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "subnet_a" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "${data.aws_region.current.name}a"
}

resource "aws_subnet" "subnet_b" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = "${data.aws_region.current.name}b"
}

resource "aws_db_subnet_group" "rds_subnet_group" {
  name       = "my-rds-subnet-group"
  subnet_ids = [aws_subnet.subnet_a.id, aws_subnet.subnet_b.id]
}

resource "aws_security_group" "rds_sg" {
  name        = "rds-security-group"
  description = "Security group for RDS instance"
  vpc_id      = aws_vpc.main.id

  # RDSへのインバウンド接続を許可 (例: MySQLの3306)
  ingress {
    from_port   = 3306
    to_port     = 3306
    protocol    = "tcp"
    cidr_blocks = [aws_vpc.main.cidr_block] # VPC内部からのアクセスを許可
  }

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

# Amazon RDSデータベースインスタンス
resource "aws_db_instance" "my_encrypted_rds_instance" {
  allocated_storage    = 20
  engine               = "mysql"
  engine_version       = "8.0.35" # 利用可能なエンジンバージョンを指定
  instance_class       = "db.t3.micro"
  db_name              = "mydb"
  username             = "admin"
  password             = "Password123!" # セキュアなパスワードに変更
  parameter_group_name = "default.mysql8.0"
  skip_final_snapshot  = true
  
  # 暗号化を有効にし、KMS CMKを指定
  storage_encrypted = true
  kms_key_id        = aws_kms_key.rds_cmk.arn

  db_subnet_group_name = aws_db_subnet_group.rds_subnet_group.name
  vpc_security_group_ids = [aws_security_group.rds_sg.id]
  publicly_accessible  = false # パブリックアクセスを無効化
  apply_immediately    = true

  tags = {
    Name        = "MySecureRDSInstance"
    Environment = "Production"
  }
}

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

Auroraクラスターの場合 (aws_rds_clusteraws_rds_cluster_instance):

# (例) Auroraクラスター暗号化用のKMSカスタマー管理キー (CMK)
resource "aws_kms_key" "aurora_cmk" {
  description             = "KMS key for Aurora cluster encryption"
  deletion_window_in_days = 10
  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 RDS Service to use the key"
        Effect = "Allow",
        Principal = {
          Service = "rds.amazonaws.com"
        },
        Action = [
          "kms:Encrypt",
          "kms:Decrypt",
          "kms:ReEncrypt*",
          "kms:GenerateDataKey*",
          "kms:DescribeKey"
        ],
        Resource = "*"
      }
    ]
  })
  tags = {
    Name = "Aurora_CMK"
  }
}

# (前提) VPC, サブネットグループ, セキュリティグループは上記と同じ定義を使用
# ... (aws_vpc, aws_subnet, aws_db_subnet_group, aws_security_group の定義をここにコピーまたは参照)

# Amazon Aurora DB クラスター
resource "aws_rds_cluster" "my_encrypted_aurora_cluster" {
  cluster_identifier      = "my-secure-aurora-cluster"
  engine                  = "aurora-mysql" # または aurora-postgresql
  engine_version          = "8.0.mysql_aurora.3.06.0" # 利用可能なエンジンバージョンを指定
  database_name           = "mydb"
  master_username         = "admin"
  master_password         = "Password123!" # セキュアなパスワードに変更
  db_subnet_group_name    = aws_db_subnet_group.rds_subnet_group.name
  vpc_security_group_ids  = [aws_security_group.rds_sg.id]
  skip_final_snapshot     = true
  final_snapshot_identifier = "my-secure-aurora-final-snapshot"
  port                    = 3306

  # 暗号化を有効にし、KMS CMKを指定
  storage_encrypted = true
  kms_key_id        = aws_kms_key.aurora_cmk.arn

  tags = {
    Name        = "MySecureAuroraCluster"
    Environment = "Production"
  }
}

# Aurora DB クラスターインスタンス
resource "aws_rds_cluster_instance" "my_aurora_instance" {
  cluster_identifier = aws_rds_cluster.my_encrypted_aurora_cluster.id
  instance_class     = "db.t3.medium"
  engine             = aws_rds_cluster.my_encrypted_aurora_cluster.engine
  engine_version     = aws_rds_cluster.my_encrypted_aurora_cluster.engine_version
  publicly_accessible = false
  apply_immediately  = true

  tags = {
    Name = "MySecureAuroraInstance"
  }
}

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

上記のTerraformコードでは、aws_db_instance または aws_rds_cluster リソース内で storage_encrypted = truekms_key_id パラメータを設定することで、RDSデータベースのストレージをKMS CMKで暗号化しています。

  • aws_kms_key.rds_cmk または aws_kms_key.aurora_cmk: RDS/Auroraの暗号化に使用するKMSカスタマー管理キー (CMK) を作成します。このキーのポリシーには、RDSサービスプリンシパル (rds.amazonaws.com) がキーを使用するための適切な権限が必要です。
  • storage_encrypted = true: ストレージの暗号化を有効にします。
  • kms_key_id: ここに作成したKMS CMKのARNを指定します。

my-secure-rds-instancemy-secure-aurora-clusterPassword123! などのプレースホルダーは、実際の環境に合わせて修正してください。特にパスワードは、Secrets Managerなどのシークレット管理サービスから取得することを強く推奨します。

最後に

この記事では、Amazon RDSデータベースインスタンスのデータをKMSカスタマー管理キー(CMK)以上で暗号化することの重要性について解説しました。この設定は、データベースに保存される機密情報を保護し、厳格なセキュリティおよびコンプライアンス要件を満たすために不可欠です。CMKやCloudHSMキーを使用することで、鍵管理の制御を強化し、機密データの露出リスクを大幅に大幅に軽減できます。 貴社のRDSインスタンスは、カスタマー管理キー以上のレベルで暗号化されていますか?この機会にぜひ設定を確認・強化してみてください。 こちらの内容の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。運用が非常にラクに出来る製品になっていますのでぜひ興味がある方はお問い合わせお待ちしております。

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

この記事をシェアする

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

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

料金プランを詳しく見る