SSM.4
概要
SSM.4 は、アカウントが所有する SSM ドキュメントがパブリックでないことをチェックする Security Hub CSPM コントロールである。対応する Config ルールは ssm-document-not-public。対象リソースタイプは AWS::SSM::Document。
SSM ドキュメントとは: AWS Systems Manager(SSM)で、EC2 インスタンスや他のマネージドノードに対して実行する操作を定義した JSON または YAML のドキュメント。代表的な用途:
- Command ドキュメント:
aws ssm send-commandで実行するシェルスクリプト・PowerShell スクリプト(例:AWS-RunShellScript) - Automation ドキュメント: EC2 起動/停止、AMI 作成、パッチ適用などの自動化ランブック(例:
AWS-StartEC2Instance) - Session ドキュメント: Session Manager のセッション設定(例:
SSM-SessionManagerRunShell)
ドキュメントは 3 種類の所有者カテゴリに分類される:
- Amazon 所有(
Owner: Amazon): AWS が提供する組み込みドキュメント(AWS-*プレフィックス、すべて公開) - 自アカウント所有(
Owner: Self): 自分で作成したカスタムドキュメント(SSM.4 の評価対象) - 他アカウント所有(
Owner: ThirdParty/Public): 他者が作成して自分に共有したドキュメント
SSM ドキュメントには、オートメーション用の機密情報(パラメータ、コマンドロジック、IAM ロール参照など)が含まれることがあり、パブリック共有するとアカウント構成や内部運用プロセスが漏洩する恐れがある。
SSM ドキュメントはパブリック化すると、インターネット上の任意の AWS アカウントから参照・実行可能になる。アカウント ID や内部プロセスの情報が漏洩する恐れがある。
検出範囲
SSM.4 は「自アカウント所有(Owner: Self)の SSM ドキュメントがパブリック共有されているか」をチェックする。具体的には ssm modify-document-permission --account-ids-to-add 'all' でパブリック化されたドキュメントを検出する。
| ドキュメント設定 | SSM.4 |
|---|---|
| デフォルト(共有設定なし) | PASSED |
| 特定アカウント ID で共有(クロスアカウント) | PASSED |
all で共有(パブリック) | FAILED |
SSM.4 はクロスアカウント共有(特定の外部アカウント ID への共有)を検出しない。これは IAM Access Analyzer の領分だが、SSM ドキュメントは IAM Access Analyzer のサポート対象リソースタイプに含まれない。そのため、クロスアカウント共有は 実質的にどの AWS 機能でも検出されない。
modify-document-permission の変更は設定変更イベントとして Config に直接通知されるわけではないため、反映までに時間がかかる場合がある。手動トリガー(start-config-rules-evaluation)で即座に評価を促すことができる。ResourceId 形式の違い: 本検証で判明した実装の差異として、Config(AWS::SSM::Document リソース)の ResourceId はドキュメント名そのまま(例: ssm-4-test-doc)、Security Hub finding の ResourceId は ARN 形式(例: arn:aws:ssm:ap-northeast-1:<アカウント ID>:document/ssm-4-test-doc)。get-compliance-details-by-config-rule の --query と securityhub get-findings の --filters でフィルタを書く際は、両者の違いに注意が必要。外部アクセス制御レイヤー
SSM ドキュメントの外部アクセスに関わるコントロールは以下の通り。SSM.4 と SSM.7 はどちらも Security Hub CSPM の検出コントロールだが、評価単位と対象が異なる。
| レイヤー | コントロール | 役割 |
|---|---|---|
| デフォルト保護 | ドキュメント作成時のデフォルトはプライベート(共有設定なし) | 明示的に modify-document-permission しない限りパブリックにはならない |
| 予防(AWS サービス機能) | SSM の Block Public Sharing(update-service-setting /ssm/documents/console/public-sharing-permission Disable) | アカウント全体で SSM ドキュメントのパブリック共有を物理的にブロックする |
| 検出(CSPM、ドキュメント単位) | SSM.4(本記事) | 個別の SSM ドキュメントがパブリック共有されているかチェック |
| 検出(CSPM、アカウント単位) | SSM.7(検証予定) | アカウントの Block Public Sharing 設定が有効かチェック |
SSM.4 と SSM.7 の違い
SSM.4 と SSM.7 はどちらも Security Hub CSPM の検出コントロールだが、評価対象・タイミング・関係性が異なる。両者は独立して動作し、一方が FAILED でも他方の評価に直接影響しない。
| 観点 | SSM.4 | SSM.7 |
|---|---|---|
| 評価単位 | 個別 SSM ドキュメント | アカウント(Region 単位) |
| 対象リソース | AWS::SSM::Document | AWS::::Account |
| 評価内容 | ドキュメントがパブリック共有されているか | アカウントの Block Public Sharing 設定が有効か |
| Config ルール | ssm-document-not-public | ssm-automation-block-public-sharing |
| FAILED になる条件 | 自アカウント所有の SSM ドキュメントが all で共有されている | Block Public Sharing 設定が Enable(=パブリック共有が許可されている) |
SSM.7 が PASSED(Block Public Sharing が Disable=BPA 有効)な状態だと、ユーザーは新規に modify-document-permission --account-ids-to-add 'all' を実行してもエラーで拒否される。つまり SSM.7 の有効化は、SSM.4 違反を将来的に発生させない予防的効果がある。ただし SSM.7 を有効化する前から既にパブリック化されているドキュメントには影響しない(SSM.4 は FAILED のまま)。
Block Public Sharing 設定値の解釈に関する注意: /ssm/documents/console/public-sharing-permission の値は以下の意味を持つ。設定名と値の方向が直感に反するので、読み違えに注意する。
SettingValue: Disable= パブリック共有を Disable(ブロック) = Block Public Sharing 有効 = SSM.7 は PASSEDSettingValue: Enable= パブリック共有を Enable(許可) = Block Public Sharing 無効 = SSM.7 は FAILED
デフォルト値について: AWS 公式ブログ(2021 年 7 月) には「By default, this setting is disabled」と記載されており、Block Public Sharing はデフォルトで 無効(パブリック共有を許可)である。本検証の 3 アカウント(組織管理アカウント、組織配下の Workload アカウント、組織外アカウント)すべてで、全リージョンで実測値は SettingValue: Enable、Status: Default、LastModifiedUser: System であり、公式ブログの記述通り。つまり 新規アカウントでも SSM.7 は初期状態で FAILED になる。Block Public Sharing を有効化するには、各アカウント・各 Region で明示的に update-service-setting する必要がある。詳細は SSM.7(検証予定)を参照。
本記事で確認すること
| # | 検証観点 | 状態 |
|---|---|---|
| 1 | デフォルト(共有設定なし)の SSM ドキュメントで SSM.4 が PASSED | 本記事で検証(3. パブリック化前の PASSED 確認) |
| 2 | modify-document-permission --account-ids-to-add 'all' でパブリック化した SSM ドキュメントで SSM.4 が FAILED | 本記事で検証(5. パブリック化後の FAILED 確認) |
| 3 | パブリック化を解除(--account-ids-to-remove 'all')した後、SSM.4 が PASSED に戻る | 本記事で検証(7. パブリック解除後の PASSED 確認) |
結果
- デフォルト: SSM ドキュメントは
Owner: Selfで共有設定なしの状態で作成され、SSM.4 は PASSED - パブリック化(
--account-ids-to-add 'all'): SSM.4 は FAILED - パブリック解除(
--account-ids-to-remove 'all'): SSM.4 は PASSED に戻る
検証環境
本記事のコマンドは、--profile 指定がない場合は Workload アカウントで実行する。事前に export AWS_PROFILE=Workload でデフォルトを設定しておくと便利。
共通の前提:アカウントの Block Public Sharing が無効であること
本記事の検証では、SSM ドキュメントをパブリック化する操作が必要である。アカウントの Block Public Sharing(SSM.7 の評価対象でもある設定)が有効(SettingValue: Disable)だと、modify-document-permission --account-ids-to-add 'all' がブロックされてしまうため、検証前に状態を確認する。
aws ssm get-service-setting \
--setting-id /ssm/documents/console/public-sharing-permission \
--query 'ServiceSetting.{SettingValue:SettingValue,Status:Status}' \
--region ap-northeast-1{
"SettingValue": "Enable",
"Status": "Default"
}SettingValue が Enable(パブリック共有が許可されている、Block Public Sharing 無効)であれば本検証をそのまま進められる。
SettingValue: Disable の場合の対応: Block Public Sharing が有効で、ステップ 4 のパブリック化操作がブロックされる状態。検証を進めるには一時的に解除する必要がある。
aws ssm update-service-setting \
--setting-id /ssm/documents/console/public-sharing-permission \
--setting-value Enable \
--region ap-northeast-1検証完了後(ステップ 8 のクリーンアップ時)に元の値に戻す:
aws ssm update-service-setting \
--setting-id /ssm/documents/console/public-sharing-permission \
--setting-value Disable \
--region ap-northeast-1注意: この一時解除中は SSM.7 が FAILED になる。検証は計画的に実施すること。
検証の流れ
flowchart LR
A[1. SSM ドキュメント<br>作成] --> B[2. デフォルト状態<br>確認]
B --> C[3. パブリック化前の<br>PASSED 確認]
C --> D[4. パブリック化<br>する]
D --> E[5. パブリック化後の<br>FAILED 確認]
E --> F[6. パブリック解除<br>する]
F --> G[7. パブリック解除後の<br>PASSED 確認]
G --> H[8. クリーンアップ]
1. SSM ドキュメントの作成
検証用のシンプルな SSM ドキュメントを作成する。内容は何でもよいが、最小限の schemaVersion: 2.2 のシェルスクリプト形式を使う。
まずドキュメント定義ファイルを用意する。
cat > /tmp/ssm-4-test-doc.json <<'EOF'
{
"schemaVersion": "2.2",
"description": "SSM.4 verification test document",
"mainSteps": [
{
"action": "aws:runShellScript",
"name": "sampleStep",
"inputs": {
"runCommand": ["echo hello"]
}
}
]
}
EOFドキュメントを作成する。
aws ssm create-document \
--name ssm-4-test-doc \
--document-type Command \
--document-format JSON \
--content file:///tmp/ssm-4-test-doc.json \
--query 'DocumentDescription.{Name:Name,Status:Status,Owner:Owner,CreatedDate:CreatedDate}' \
--region ap-northeast-1{
"Name": "ssm-4-test-doc",
"Status": "Creating",
"Owner": "<アカウント ID>",
"CreatedDate": "<作成時刻>"
}2. デフォルト状態の確認
作成直後のドキュメントは共有設定なし(プライベート)であることを確認する。
aws ssm describe-document-permission \
--name ssm-4-test-doc \
--permission-type Share \
--region ap-northeast-1{
"AccountIds": [],
"AccountSharingInfoList": []
}AccountIds が空であれば、どこにも共有されていないデフォルト状態。
3. パブリック化前の PASSED 確認
Config ルールを手動トリガーして即座に評価させる。
aws configservice list-discovered-resources \
--resource-type AWS::SSM::Document \
--query 'resourceIdentifiers[?resourceName==`ssm-4-test-doc`]' \
--region ap-northeast-1[
{
"resourceType": "AWS::SSM::Document",
"resourceId": "ssm-4-test-doc",
"resourceName": "ssm-4-test-doc"
}
]Config の resourceId はドキュメント名そのまま(ARN や UUID ではない)。Config に発見されるまで 1〜2 分のラグがある。発見されない場合は数分待って再実行する。
aws configservice start-config-rules-evaluation \
--config-rule-names securityhub-ssm-document-not-public-<サフィックス> \
--region ap-northeast-1(出力なし)1〜2 分待ってから評価結果を確認する。
sleep 90
aws configservice get-compliance-details-by-config-rule \
--config-rule-name securityhub-ssm-document-not-public-<サフィックス> \
--query 'EvaluationResults[?EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId==`ssm-4-test-doc`].{ResourceId:EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId,ComplianceType:ComplianceType,ResultRecordedTime:ResultRecordedTime}' \
--region ap-northeast-1[
{
"ResourceId": "ssm-4-test-doc",
"ComplianceType": "COMPLIANT",
"ResultRecordedTime": "<評価時刻>"
}
]ResultRecordedTime がステップ 1 の create-document 実行時刻より後であることを確認する。これにより、ドキュメント作成後に Config の評価が実行されたことを示す。
start-config-rules-evaluation でトリガーしても、Config のリソース発見ラグにより get-compliance-details-by-config-rule の結果が空(まだ評価対象に含まれていない)の場合がある。その場合は数分待ってから再度 start-config-rules-evaluation で再トリガーする。Security Hub への反映を待ってから、finding を確認する。
sleep 120
aws securityhub get-findings \
--filters '{
"ComplianceSecurityControlId": [{"Comparison": "EQUALS", "Value": "SSM.4"}],
"AwsAccountId": [{"Comparison": "EQUALS", "Value": "<アカウント ID>"}],
"ResourceId": [{"Comparison": "EQUALS", "Value": "arn:aws:ssm:ap-northeast-1:<アカウント ID>:document/ssm-4-test-doc"}],
"RecordState": [{"Comparison": "EQUALS", "Value": "ACTIVE"}]
}' \
--query 'Findings[].{Status:Compliance.Status,ResourceId:Resources[0].Id,UpdatedAt:UpdatedAt}' \
--region ap-northeast-1[
{
"Status": "PASSED",
"ResourceId": "arn:aws:ssm:ap-northeast-1:<アカウント ID>:document/ssm-4-test-doc",
"UpdatedAt": "<更新時刻>"
}
]4. パブリック化する
modify-document-permission で all を指定してパブリック化する。
aws ssm modify-document-permission \
--name ssm-4-test-doc \
--permission-type Share \
--account-ids-to-add all \
--region ap-northeast-1(出力なし)パブリック化されたことを確認する。
aws ssm describe-document-permission \
--name ssm-4-test-doc \
--permission-type Share \
--region ap-northeast-1{
"AccountIds": ["all"],
"AccountSharingInfoList": [
{
"AccountId": "all",
"SharedDocumentVersion": "$DEFAULT"
}
]
}AccountIds に "all" が含まれていればパブリック化されている。
5. パブリック化後の FAILED 確認
Config ルールを再度トリガーする。
aws configservice start-config-rules-evaluation \
--config-rule-names securityhub-ssm-document-not-public-<サフィックス> \
--region ap-northeast-1(出力なし)評価結果を確認する。
sleep 90
aws configservice get-compliance-details-by-config-rule \
--config-rule-name securityhub-ssm-document-not-public-<サフィックス> \
--query 'EvaluationResults[?EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId==`ssm-4-test-doc`].{ResourceId:EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId,ComplianceType:ComplianceType,ResultRecordedTime:ResultRecordedTime}' \
--region ap-northeast-1[
{
"ResourceId": "ssm-4-test-doc",
"ComplianceType": "NON_COMPLIANT",
"ResultRecordedTime": "<評価時刻>"
}
]ResultRecordedTime がステップ 4 の modify-document-permission 実行時刻より後であることを確認する。これにより、パブリック化後に Config の再評価が実行されたことを示す。
COMPLIANT のままの結果が返る場合がある(設定変更の反映ラグにより、直前の評価結果がそのまま返ることがある)。その場合は数分待ってから再度 start-config-rules-evaluation で再トリガーする。Security Hub への反映を待ってから、finding を確認する。
sleep 120
aws securityhub get-findings \
--filters '{
"ComplianceSecurityControlId": [{"Comparison": "EQUALS", "Value": "SSM.4"}],
"AwsAccountId": [{"Comparison": "EQUALS", "Value": "<アカウント ID>"}],
"ResourceId": [{"Comparison": "EQUALS", "Value": "arn:aws:ssm:ap-northeast-1:<アカウント ID>:document/ssm-4-test-doc"}],
"RecordState": [{"Comparison": "EQUALS", "Value": "ACTIVE"}]
}' \
--query 'Findings[].{Status:Compliance.Status,ResourceId:Resources[0].Id,UpdatedAt:UpdatedAt}' \
--region ap-northeast-1[
{
"Status": "FAILED",
"ResourceId": "arn:aws:ssm:ap-northeast-1:<アカウント ID>:document/ssm-4-test-doc",
"UpdatedAt": "<更新時刻>"
}
]6. パブリック解除する
--account-ids-to-remove 'all' で解除する。
aws ssm modify-document-permission \
--name ssm-4-test-doc \
--permission-type Share \
--account-ids-to-remove all \
--region ap-northeast-1(出力なし)aws ssm describe-document-permission \
--name ssm-4-test-doc \
--permission-type Share \
--region ap-northeast-1{
"AccountIds": [],
"AccountSharingInfoList": []
}7. パブリック解除後の PASSED 確認
Config ルールを再度トリガーする。
aws configservice start-config-rules-evaluation \
--config-rule-names securityhub-ssm-document-not-public-<サフィックス> \
--region ap-northeast-1(出力なし)評価結果を確認する。
sleep 90
aws configservice get-compliance-details-by-config-rule \
--config-rule-name securityhub-ssm-document-not-public-<サフィックス> \
--query 'EvaluationResults[?EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId==`ssm-4-test-doc`].{ResourceId:EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId,ComplianceType:ComplianceType,ResultRecordedTime:ResultRecordedTime}' \
--region ap-northeast-1[
{
"ResourceId": "ssm-4-test-doc",
"ComplianceType": "COMPLIANT",
"ResultRecordedTime": "<評価時刻>"
}
]ResultRecordedTime がステップ 6 の modify-document-permission --account-ids-to-remove all 実行時刻より後であることを確認する。これにより、パブリック解除後に Config の再評価が実行されたことを示す。
NON_COMPLIANT のままの結果が返る場合がある(設定変更の反映ラグにより、直前の評価結果がそのまま返ることがある)。その場合は数分待ってから再度 start-config-rules-evaluation で再トリガーする。Security Hub での PASSED 確認も実施する。
sleep 120
aws securityhub get-findings \
--filters '{
"ComplianceSecurityControlId": [{"Comparison": "EQUALS", "Value": "SSM.4"}],
"AwsAccountId": [{"Comparison": "EQUALS", "Value": "<アカウント ID>"}],
"ResourceId": [{"Comparison": "EQUALS", "Value": "arn:aws:ssm:ap-northeast-1:<アカウント ID>:document/ssm-4-test-doc"}],
"RecordState": [{"Comparison": "EQUALS", "Value": "ACTIVE"}]
}' \
--query 'Findings[].{Status:Compliance.Status,ResourceId:Resources[0].Id,UpdatedAt:UpdatedAt}' \
--region ap-northeast-1[
{
"Status": "PASSED",
"ResourceId": "arn:aws:ssm:ap-northeast-1:<アカウント ID>:document/ssm-4-test-doc",
"UpdatedAt": "<更新時刻>"
}
]8. クリーンアップ
検証用ドキュメントを削除する。
aws ssm delete-document \
--name ssm-4-test-doc \
--region ap-northeast-1(出力なし)定義ファイルも削除する。
rm /tmp/ssm-4-test-doc.json