Back to Checks
SSM document is not public and shared only with trusted AWS accounts
ssm_documents_set_as_public
Service: ssmSeverity: high
OfficialBuilt-inVerified
Categories:identity-accessinternet-exposed
Resource Type:AwsSsmPatchCompliance
SSM documents are evaluated for public sharing (all) and for shares with AWS accounts outside a defined trusted list. Documents that remain private or are shared only with trusted accounts indicate restricted distribution.
Risk
Public or non-trusted sharing exposes document content, eroding confidentiality of scripts, parameters, and embedded secrets. Adversaries can study runbooks to craft targeted attacks and reuse logic, causing credential leakage and downstream integrity and availability impacts.
Run this check with Prowler
Run in Prowler CloudRun
prowler aws --checks ssm_documents_set_as_publicRecommendation
Apply least privilege to document distribution:
- Keep documents private; share only with specific trusted account IDs
- Enable account-level block public sharing for documents
- Remove secrets from content; use secure parameters
- Limit who can share or run documents; require reviews and version control
Remediation
CLI
aws ssm modify-document-permission --name <DOCUMENT_NAME> --permission-type Share --account-ids-to-remove allTerraform
resource "aws_ssm_document" "<example_resource_name>" {
name = "<example_resource_name>"
document_type = "Command"
content = jsonencode({
schemaVersion = "2.2"
mainSteps = []
})
# Critical: no permissions block -> document remains private (not public/shared)
}Other
1Open AWS Systems Manager > Documents
2Select the document > Permissions tab > Edit
3Select Private (remove Public/'all')
4Remove any non-trusted AWS account IDs
5Save
Check Code
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.ssm.ssm_client import ssm_client
class ssm_documents_set_as_public(Check):
def execute(self):
findings = []
for document in ssm_client.documents.values():
report = Check_Report_AWS(metadata=self.metadata(), resource=document)
trusted_account_ids = ssm_client.audit_config.get("trusted_account_ids", [])
if ssm_client.audited_account not in trusted_account_ids:
trusted_account_ids.append(ssm_client.audited_account)
if not document.account_owners or document.account_owners == [
ssm_client.audited_account
]:
report.status = "PASS"
report.status_extended = f"SSM Document {document.name} is not public."
elif document.account_owners == ["all"]:
report.status = "FAIL"
report.status_extended = f"SSM Document {document.name} is public."
elif all(owner in trusted_account_ids for owner in document.account_owners):
report.status = "PASS"
report.status_extended = f"SSM Document {document.name} is shared to trusted AWS accounts: {', '.join(document.account_owners)}."
elif not all(
owner in trusted_account_ids for owner in document.account_owners
):
report.status = "FAIL"
report.status_extended = f"SSM Document {document.name} is shared to non-trusted AWS accounts: {', '.join(document.account_owners)}."
findings.append(report)
return findings