Skip to content

Data Perimeter

A data perimeter is the set of guardrails that keep your data reachable only by trusted identities, from expected networks, to trusted resources (AWS data perimeter whitepaper). cloud-audit's data perimeter checks read your resource-based policies and flag the boundary failures you can detect from a single account, read-only, without AWS Organizations access.

cloud-audit scan --categories security        # data perimeter runs as part of a normal scan
cloud-audit list-checks                        # see all aws-dp-* checks

Why this matters

Most scanners evaluate a resource policy as raw API output and never look at the condition keys that AWS recommends for the data perimeter. That produces two problems: blind spots (a wildcard grant that should be flagged isn't analyzed in context) and false positives (a grant that is scoped by aws:PrincipalOrgID gets flagged anyway). The dominant open-source scanner tracks this as an open feature request - Prowler issue #7114, "Integrating SCP/RCP Policy Awareness", open since March 2025.

cloud-audit reads the condition keys directly and reports the absence of a guardrail without guessing about organization-level policy.

What it detects

Dimension Trigger Severity
Confused deputy An Allow statement grants an AWS service principal without aws:SourceAccount / aws:SourceArn / aws:SourceOrgID / aws:SourceOwner MEDIUM
Cross-org exposure (wildcard) An Allow statement grants Principal: "*" (any AWS account) without an organization-boundary condition HIGH
Cross-org exposure (external account) An Allow statement grants a named external account without an organization-boundary condition LOW

The confused deputy problem is when a service acting on behalf of another account is coerced into operating on your resource. AWS recommends aws:SourceArn, aws:SourceAccount, aws:SourceOrgID, or aws:SourceOrgPaths "wherever an AWS service principal is granted permission to access one of your resources."

A grant is treated as scoped (no finding) when it carries any organization or account binding: aws:PrincipalOrgID, aws:PrincipalOrgPaths, aws:ResourceOrgID, aws:SourceOrgID, aws:SourceOrgPaths, aws:SourceAccount, aws:SourceOwner, aws:PrincipalAccount, or aws:SourceArn. Condition key names are matched case-insensitively, and the default SNS/SQS policies that rely on aws:SourceOwner are correctly recognized as account-scoped.

Checks

Check Service Resource policy
aws-dp-001 S3 bucket policy
aws-dp-002 SNS topic policy
aws-dp-003 SQS queue policy
aws-dp-004 Secrets Manager secret resource policy (cross-org escalated: CRITICAL wildcard / MEDIUM external)
aws-dp-005 Lambda function resource policy

aws-dp-001 complements aws-s3-001 (public access block): PAB governs anonymous public access, while aws-dp-001 governs the organization boundary and confused-deputy posture of the bucket policy itself.

Every finding ships copy-paste CLI + Terraform remediation and a breach-cost estimate.

Remediation example

A bucket policy that lets CloudTrail write logs without scoping the source is a confused deputy:

{
  "Effect": "Allow",
  "Principal": { "Service": "cloudtrail.amazonaws.com" },
  "Action": "s3:PutObject",
  "Resource": "arn:aws:s3:::my-logs/*"
}

Add a source condition so the service can only act for your account:

"Condition": { "StringEquals": { "aws:SourceAccount": "111122223333" } }

Scope and limitations

  • In scope: resource-based policies readable by any account-local principal (S3, SNS, SQS, Secrets Manager, Lambda).
  • Out of scope: SCP/RCP enforcement, which lives at the AWS Organizations level and requires management-account access. These checks report the absence of a resource-level guardrail; they do not assume an org-wide RCP closes the gap.
  • Condition values are evaluated, not just key presence: a guardrail (aws:SourceAccount / aws:SourceOwner / aws:PrincipalAccount / aws:SourceArn) scoped to a foreign account is still flagged. Organization keys (aws:PrincipalOrgID, ...) are treated as a guardrail when present, since the org id is not locally verifiable without AWS Organizations access (documented trade-off favoring zero false positives).
  • Federated provider ARNs in a foreign account are flagged as external grants. Federated URL IdPs (e.g. accounts.google.com) and CanonicalUser principals are not account-parseable and are out of scope.
  • NotPrincipal statements are not analyzed (uncommon; treated as a known limitation rather than guessed at).
  • Scoping is heuristic, not a full IAM policy evaluation (operator semantics and per-request key presence are not simulated) - a deliberate choice to avoid the maintenance trap that killed PMapper.
  • A condition key under an ...IfExists operator is counted as present. This favors fewer false positives; verify intent on highly sensitive resources.

The detection taxonomy follows the AWS data perimeter whitepaper and AWS cross-service confused deputy prevention guidance.