SSMドキュメントをパブリック公開からプライベート共有化させるための設定手順

このブログシリーズ 「クラウドセキュリティ 実践集」 では、一般的なセキュリティ課題を取り上げ、「なぜ危険なのか?」 というリスクの解説から、「どうやって直すのか?」 という具体的な修復手順(コンソール、AWS CLI、Terraformなど)まで、分かりやすく解説します。
この記事では、AWS Systems ManagerのSecurity Hubコントロール「SSM-4: Systems Managerドキュメントがパブリックに共有されていないこと」について解説します。

ポリシーの説明
[SSM.4] SSM ドキュメントはパブリックにしないでください
Systems Manager の Security Hub コントロール – AWS Security Hub
このコントロールは、アカウントが所有する AWS Systems Manager ドキュメントがパブリックかどうかをチェックします。所有者
Self
の Systems Manager ドキュメントがパブリックの場合、このコントロールは失敗します。
Systems Managerドキュメントは、AWSリソースの構成や自動化を行うためのスクリプトです。パブリックに共有されたドキュメントは、意図しないアクセスや情報漏洩のリスクを高めるためプライベート化しましょうという内容ですね。
修復方法
AWSコンソールでの修正手順
- AWSマネジメントコンソールにログインし、Systems Managerのコンソールを開きます。
- 「ドキュメント」>「自己所有」へ移動しパブリックアクセスを削除したいドキュメントを選択します。
- 「詳細」タブを開き、「アクセス許可」のセクションで「プライベート」をクリックします。
- 自身のAWSアカウントIDを入力します。

- 「保存」をクリックします。
- ドキュメント > 「詳細設定」を選択後、「編集」をクリックし「パブリック共有をブロック」にチェック。
- 「保存」をクリックします。

Terraformでの修復手順
SSMドキュメントを安全に設定するためのTerraformコードと、重要な修正ポイントを説明します。
# SSM Document
resource "aws_ssm_document" "example" {
name = "secure-ssm-document-${var.environment}"
document_type = "Command"
document_format = "YAML"
# ★重要: content はYAML形式で安全なコマンドのみを含める
content = yamlencode({
schemaVersion = "2.2"
description = "Safe command execution example"
parameters = {
commands = {
type = "StringList"
description = "Commands to execute"
default = []
}
}
mainSteps = [
{
action = "aws:runShellScript"
name = "example"
inputs = {
runCommand = ["{{ commands }}"]
}
}
]
})
# ★重要: タグ付けによる管理
tags = merge(var.tags, {
Name = "secure-ssm-document-${var.environment}"
Environment = var.environment
Secure = "true"
})
}
# ★重要: ドキュメントの共有設定
# 特定のアカウントとのみ共有し、パブリック共有を避ける
resource "aws_ssm_document_permission" "example_share" {
count = length(var.shared_account_ids)
name = aws_ssm_document.example.name
account_ids = [var.shared_account_ids[count.index]]
permission_type = "Share"
}
# SSM Document Version Policy
resource "aws_ssm_document_version" "example" {
name = aws_ssm_document.example.name
document_version = "$LATEST"
}
# IAM Role for SSM
resource "aws_iam_role" "ssm_role" {
name = "ssm-secure-role-${var.environment}"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ssm.amazonaws.com"
}
}
]
})
# ★重要: 最小権限の原則に基づいたポリシー
inline_policy {
name = "ssm-secure-policy"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"ssm:GetParameter",
"ssm:GetParameters",
"ssm:GetParametersByPath"
]
Resource = [
"arn:aws:ssm:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:parameter/${var.environment}/*"
]
}
]
})
}
tags = var.tags
}
# CloudWatch Log Group for SSM
resource "aws_cloudwatch_log_group" "ssm_logs" {
name = "/aws/ssm/${var.environment}/documents"
retention_in_days = var.log_retention_days
tags = var.tags
}
# Variables
variable "environment" {
description = "Environment name"
type = string
}
variable "shared_account_ids" {
description = "List of AWS account IDs to share the document with"
type = list(string)
default = []
# ★重要: アカウントIDの検証
validation {
condition = can([for id in var.shared_account_ids : regex("^\\\\\\\\d{12}$", id)])
error_message = "All account IDs must be 12 digits."
}
}
variable "log_retention_days" {
description = "Number of days to retain CloudWatch logs"
type = number
default = 30
}
variable "tags" {
description = "Tags for resources"
type = map(string)
default = {}
}
# Data sources
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}
# Outputs
output "document_name" {
description = "The name of the SSM document"
value = aws_ssm_document.example.name
}
output "document_arn" {
description = "The ARN of the SSM document"
value = aws_ssm_document.example.arn
}
主要な修正ポイントは以下の通りです:
- ドキュメントの共有設定(最重要):
resource "aws_ssm_document_permission" "example_share" {
# 特定のアカウントのみと共有
account_ids = [var.shared_account_ids[count.index]]
permission_type = "Share"
# パブリック共有を避ける("all" は使用しない)
}
安全なドキュメント内容:
resource "aws_ssm_document" "example" {
content = yamlencode({
# 安全なコマンドのみを含める
# パラメータのバリデーションを含める
})
}
アクセス制御とログ記録:
# IAM Role with minimum permissions
resource "aws_iam_role" "ssm_role" {
# 最小権限の原則に基づいたポリシー
}
# CloudWatch Logs for auditing
resource "aws_cloudwatch_log_group" "ssm_logs" {
# ログの保持と監査
}
使用方法:
- 変数の設定:
# terraform.tfvars
environment = "production"
shared_account_ids = ["123456789012", "210987654321"] # 特定のアカウントIDのみ
log_retention_days = 30
既存のドキュメントを修正する場合の手順:
パブリック共有の削除:
# 古い共有設定を削除
terraform destroy -target=aws_ssm_document_permission.old_permission
b. 新しい共有設定の適用:
# 特定アカウントとの共有を設定
terraform apply
重要な注意点:
- 共有設定のベストプラクティス:
- パブリック共有(”all”)を絶対に使用しない
- 必要な特定のアカウントとのみ共有
- 定期的に共有設定を見直す
- セキュリティ強化のポイント:
# バージョン管理の有効化
resource "aws_ssm_document" "example" {
version_name = "1.0.0"
}
# タグによる管理
tags = {
Confidentiality = "high"
Owner = "team-name"
}
監査とモニタリング:
# CloudWatch Alarmsの追加
resource "aws_cloudwatch_metric_alarm" "ssm_document_usage" {
# ドキュメントの使用状況を監視
}
これらの修正を適用することで、SSMドキュメントのセキュリティが強化されます。特に:
- パブリックアクセスの防止
- 適切なアクセス制御
- 監査とログ記録の確保
- 最小権限の原則の遵守
が重要なポイントとなります。
最後に
今回は、パブリックに共有されたSystems Managerドキュメントの対処方法についてご紹介しました。 パブリックに共有されたSystems Managerドキュメントを放置すると、意図しないアクセスや情報漏洩のリスクが高まります。定期的なチェックと適切な設定を行い、セキュリティを強化しましょう。
この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。
運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。
最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。