暗号化されていないSSMパラメータの暗号化設定手順

このブログシリーズ 「クラウドセキュリティ 実践集」 では、一般的なセキュリティ課題を取り上げ、「なぜ危険なのか?」 というリスクの解説から、「どうやって直すのか?」 という具体的な修復手順(コンソール、AWS CLI、Terraformなど)まで、分かりやすく解説します。
この記事では、SSMパラメータストアに登録した文字列が暗号化されていないことによるリスクとその修正方法について解説します。

想定されるリスクについて
リスク | 詳細 |
---|---|
不正アクセスによる情報漏えい | IAM 権限の設定ミスやアカウント侵害により、本来アクセスできないユーザー/サービスが平文で機密情報を取得できる。 |
意図しない公開 | CLI・CI/CD のログ出力、シェル履歴、アプリケーションの例外スタックなどに平文が残る可能性。 |
コンプライアンス違反 | 多くの規制で「機密データ at-rest 暗号化」が必須。String 型は at-rest でも暗号化されないため違反リスク。 |
ローテーション困難 | SecureString へ移行しておかないと後からタイプを変更できず、大規模な置き換え作業が必要になる。 |
注: CloudTrail は API 呼び出しのメタデータのみを記録し、パラメータの 値そのもの は残しません。漏えい経路はあくまで IAM 誤設定やログへの平文出力です。
2. 移行方針
- String → SecureString へ直接変更はできない ➜ 新規 SecureString を作成
- 値を書き換えるアプリ側も環境変数や設定を更新
- 旧 String は削除するか “Deprecated” タグを付けて早期廃止
修復方法
パラメータを作成した後に暗号化のタイプを変更することはできないため、新規で作成します。
AWS コンソール
- Systems Manager > パラメータストア を開く
- パラメータを作成 → 必須項目を入力
- タイプ で 安全な文字列 (SecureString) を選択
- KMS キー をカスタムキーまたは
aws/ssm
から選択 - 階層構造 で
/env/app/parameter
形式にし、パラメータを作成

Terraformでの修復手順
SSMパラメータストアのセキュアな設定のためのTerraformコードと、重要な修正ポイントを説明します。
########################################
# KMS (カスタムキーはローテーション推奨)
########################################
resource "aws_kms_key" "ssm" {
description = "KMS key for SSM parameters encryption"
enable_key_rotation = true
deletion_window_in_days = 7
policy = jsonencode({
Version = "2012-10-17",
Statement = [
# root に全権
{
Sid = "EnableRoot",
Effect = "Allow",
Principal = { AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" },
Action = "kms:*",
Resource = "*"
},
# SSM サービスに最小権限
{
Sid = "AllowSSM",
Effect = "Allow",
Principal = { Service = "ssm.amazonaws.com" },
Action = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
Resource = "*"
}
]
})
}
resource "aws_kms_alias" "ssm" {
name = "alias/ssm-${var.environment}"
target_key_id = aws_kms_key.ssm.key_id
}
########################################
# SecureString パラメータ
########################################
resource "aws_ssm_parameter" "secure_parameter" {
for_each = var.secure_parameters
name = "/${var.environment}/${each.key}" # 階層構造推奨
type = "SecureString"
value = each.value
key_id = aws_kms_key.ssm.arn # カスタム KMS
tier = var.parameter_tier
overwrite = false # 誤更新防止
tags = merge(var.tags, { Name = each.key })
}
########################################
# IAM (最小権限)
########################################
resource "aws_iam_role" "app" { … }
resource "aws_iam_role_policy" "app_ssm" {
role = aws_iam_role.app.id
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Action = ["ssm:GetParametersByPath"],
Resource = "arn:aws:ssm:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:parameter/${var.environment}/*"
},
{
Effect = "Allow",
Action = ["kms:Decrypt"],
Resource = [aws_kms_key.ssm.arn]
}
]
})
}
########################################
# 変更監査 – EventBridge + SNS
########################################
resource "aws_cloudwatch_event_rule" "ssm_change" {
name = "ssm-parameter-change-${var.environment}"
event_pattern = jsonencode({
source = ["aws.ssm"],
"detail-type"= ["Parameter Store Change"],
detail = { name = [{ "prefix": "/${var.environment}/" }] }
})
}
resource "aws_cloudwatch_event_target" "notify" {
rule = aws_cloudwatch_event_rule.ssm_change.name
arn = var.alarm_sns_topic_arn
}
ベストプラクティス
項目 | 推奨 |
---|---|
命名規則 | /env/app/component/secret 形式。GetParametersByPath で環境ごとに一括取得。 |
パラメータポリシー | Expiration (有効期限)、NoChangeNotification を活用し、放置や誤変更を検知。 |
ローテーション要件 | DB パスワードなど自動ローテーション必須のシークレットは Secrets Manager を検討。 |
監査・通知 | EventBridge で変更を SNS / ChatOps に通知。 |
アクセス権 | IAM ポリシーはパスプレフィックスで絞り、kms:Decrypt は必要最小限のキー ARN に限定。 |
最後に
今回は、SSMパラメータストアに登録した文字列が暗号化されていないことによるリスクとその修正方法についてご紹介しました。 パスワードや外部APIのシークレットキーなどの機密データは、パラメータストアの「安全な文字列」として保存しておくことで、安全に管理することができるため実施を推奨します。
この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。
運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。
最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。