OpenSearchでのCMKでの暗号化について

このブログシリーズ 「クラウドセキュリティ 実践集」 では、一般的なセキュリティ課題を取り上げ、「なぜ危険なのか?」 というリスクの解説から、「どうやって直すのか?」 という具体的な修復手順(コンソール、AWS CLI、Terraformなど)まで、分かりやすく解説します。
今回は、Amazon OpenSearch Service(旧Amazon Elasticsearch Service)のドメインがカスタマー管理キー (CMK) 以上のレベルで暗号化されていない状態について、そのリスクと対策を解説します。

リスク
Amazon OpenSearch Serviceは、ElasticsearchやOpenSearchクラスターをデプロイ、運用、スケールできるフルマネージドサービスです。ログ分析、全文検索、アプリケーション監視など、多様なユースケースで利用されます。OpenSearchドメインは、保管時の暗号化オプションを提供していますが、デフォルトでは無効になっています。求められるコンプライアンスの基準に応じてKMSカスタマー管理キー(CMK)の暗号化を行うようにしましょう。
修復方法
Amazon OpenSearch Serviceドメインの暗号化をKMSカスタマー管理キー(CMK)で有効にする方法は、AWSコンソールまたはTerraformで行えます。CloudHSMキーを使用する場合は、先にAWS CloudHSMクラスターとそれに統合されたKMSキーを作成する必要があります。
AWSコンソールでの修復手順
AWSコンソールを使用して、Amazon OpenSearch Serviceドメインの作成時にKMS CMKで暗号化を有効にします。
前提:
- OpenSearchドメインを暗号化するためのAWS KMS カスタマー管理キー (CMK) が既に存在すること。
- CMKのキーポリシーには、OpenSearchサービス (
es.amazonaws.com
) がキーを使用するための適切な権限(kms:Encrypt
,kms:Decrypt
など)が付与されている必要があります。
- CMKのキーポリシーには、OpenSearchサービス (
- Amazon OpenSearch Serviceへ移動: AWSコンソールにログインし、Amazon OpenSearch Service サービスを開きます。
- ドメインの作成: 左側のナビゲーションペインで「ドメイン」を選択し、「ドメインを作成」をクリックします。
- デプロイメントタイプとドメイン設定の選択:
- デプロイメントタイプ: 「本番稼働用」または「開発/テスト」を選択します。
- ドメイン名: ドメインの識別子を入力します。
- OpenSearchバージョン: 使用するOpenSearchのバージョンを選択します。
- ストレージ設定:
- 「ストレージ設定」セクションまでスクロールします。
- 「データノードのストレージ」セクションの「暗号化」で、「保管時の暗号化を有効にする」にチェックを入れます。
- 「AWS Key Management Service (KMS) マスターキー」のドロップダウンメニューから、使用したい既存のKMS CMKを選択します。
- もし適切なCMKがリストに表示されない場合は、正しいIAM権限があるか、またはCMKが作成されているか確認してください。

- その他の設定(インスタンスタイプ、ネットワーク設定、アクセスポリシーなど)を構成します。
- 作成: 設定内容を確認し、「作成」をクリックしてドメインをプロビジョニングします。
これで、Amazon OpenSearch Serviceドメインに保存されるデータは、指定したKMS CMKを使用して保管時に暗号化されるようになります。既存のドメインの暗号化キーを変更することはできないため、既存のドメインをCMKで暗号化したい場合は、新しいドメインにデータを移行する必要があります。
Terraformでの修復手順
TerraformでAmazon OpenSearch Serviceドメインの暗号化をKMSカスタマー管理キー(CMK)で有効にするには、aws_opensearch_domain
リソースの node_to_node_encryption
, encrypt_at_rest
, kms_key_id
パラメータを設定します。
# (例) OpenSearchドメイン暗号化用のKMSカスタマー管理キー (CMK)
resource "aws_kms_key" "opensearch_cmk" {
description = "KMS key for OpenSearch domain 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 OpenSearch Service to use the key"
Effect = "Allow",
Principal = {
Service = "es.amazonaws.com" # OpenSearch Service プリンシパル
},
Action = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
Resource = "*"
}
]
})
tags = {
Name = "OpenSearch_CMK"
}
}
# (前提) VPC, サブネット, セキュリティグループ
# OpenSearchドメインをデプロイする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_security_group" "opensearch_sg" {
name = "opensearch-security-group"
description = "Security group for OpenSearch domain"
vpc_id = aws_vpc.main.id
# OpenSearchへのインバウンド接続を許可 (例: 443 HTTPS)
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["10.0.0.0/16"] # VPC内部からのアクセスを許可
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# Amazon OpenSearch Service ドメイン
resource "aws_opensearch_domain" "my_encrypted_opensearch_domain" {
domain_name = "my-secure-opensearch-domain"
engine_version = "OpenSearch_2.11" # 使用するOpenSearchバージョンを指定
cluster_config {
instance_type = "r6g.large.elasticsearch" # OpenSearchインスタンスタイプ
instance_count = 2
zone_awareness_enabled = true
zone_awareness_config {
availability_zone_count = 2
}
}
# データノード間の通信を暗号化
node_to_node_encryption {
enabled = true
}
# 保管時の暗号化を有効にし、KMS CMKを指定
encrypt_at_rest {
enabled = true
kms_key_id = aws_kms_key.opensearch_cmk.arn
}
# VPC設定
vpc_options {
subnet_ids = [aws_subnet.subnet_a.id, aws_subnet.subnet_b.id]
security_group_ids = [aws_security_group.opensearch_sg.id]
}
# ドメインへのアクセスポリシー (最小特権の原則に基づく)
access_policies = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Principal = {
AWS = data.aws_caller_identity.current.account_id
},
Action = "es:*",
Resource = "arn:aws:es:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:domain/${aws_opensearch_domain.my_encrypted_opensearch_domain.domain_name}/*"
}
]
})
tags = {
Name = "MySecureOpenSearchDomain"
Environment = "Production"
}
}
# 現在のAWSアカウント情報とリージョンを取得
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}
上記のTerraformコードでは、aws_opensearch_domain
リソース内で encrypt_at_rest
ブロックを設定することで、OpenSearchドメインのデータをKMS CMKで暗号化しています。
node_to_node_encryption { enabled = true }
: クラスター内のノード間の通信を暗号化します。これは、保管時の暗号化とは別に設定できます。encrypt_at_rest { enabled = true }
: 保管時の暗号化を有効にします。encrypt_at_rest { kms_key_id = aws_kms_key.opensearch_cmk.arn }
: 暗号化に使用するKMSカスタマー管理キーのARNを指定します。このキーは事前にaws_kms_key
リソースで定義しておく必要があります。- KMSキーポリシーでは、OpenSearchサービスプリンシパル (
es.amazonaws.com
) がキーを使用してデータを暗号化・復号化するために必要な権限を付与することが重要です。
my-secure-opensearch-domain
や 10.0.0.0/16
などのプレースホルダーは、実際の環境に合わせて修正してください。
最後に
この記事では、Amazon OpenSearch ServiceドメインのデータをKMSカスタマー管理キー(CMK)以上で暗号化することの重要性について解説しました。この設定は、ログデータ、検索インデックス、その他の機密情報を保護し、厳格なセキュリティおよびコンプライアンス要件を満たすために不可欠です。CMKやCloudHSMキーを使用することで、鍵管理の制御を強化し、機密データの露出リスクを大幅に軽減できます。 貴社のOpenSearchドメインは、カスタマー管理キー以上のレベルで暗号化されていますか?この機会にぜひ設定を確認・強化してみてください。 こちらの内容の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。運用が非常にラクに出来る製品になっていますのでぜひ興味がある方はお問い合わせお待ちしております。
最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。