aws-dynamodb-restore-pitr-read
dynamodb:RestoreTableToPointInTime creates a new table from PITR; reading it requires separate GetItem/Scan/Query permission on the restored table ARN (CONDITIONAL path).
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?table) ==
NoSQLDatabase
?table.provider_type in ['AWS::DynamoDB::Table', 'AWS::DynamoDB::GlobalTable']
?principal has EFFECTIVE dynamodb:RestoreTableToPointInTime on ?table ARN
?table.properties.PointInTimeRecoveryStatus == 'ENABLED'
emit
| source type | Identity |
|---|---|
| target type | NoSQLDatabase |
| source | ?principal |
| target | ?table |
| permissions | dynamodb:RestoreTableToPointInTime |
| conditions | iam_permission scp_or_org_policy service_state |
| state logic | CONDITIONAL(iam_permission) when dynamodb:RestoreTableToPointInTime is confirmed EFFECTIVE on the source table ARN AND PITR is enabled. RestoreTableToPointInTime creates a NEW table but does NOT automatically grant the restoring principal read access to the NEW table's ARN. The principal must have a SEPARATE, confirmed EFFECTIVE permission (dynamodb:GetItem, dynamodb:Query, or dynamodb:Scan) on the newly-restored table's ARN to read items. This typically requires a wildcard permission (e.g., dynamodb:GetItem on arn:aws:dynamodb:*:*:table/* or arn:aws:dynamodb:region:account:table/restored-*) or an explicit grant on the new table. Emit as CONDITIONAL(iam_permission); upgrade to ACTIVE only when an aws-dynamodb-read-data edge is confirmed on the restored table ARN. CONDITIONAL(service_state) when PITR is disabled. BLOCKED by an SCP or permission-boundary deny on RestoreTableToPointInTime. |
Narrative
{principal.name} can restore a point-in-time copy of {table.name} (dynamodb:RestoreTableToPointInTime), creating a new table with full historical item data. Reading the new table requires a separate GetItem/Scan/Query permission on the restored table ARN.
Raw rule rules/derived/aws/dynamodb.yaml
id: aws-dynamodb-restore-pitr-read
emits: CanReadData
description: dynamodb:RestoreTableToPointInTime creates a new table from PITR; reading it requires separate
GetItem/Scan/Query permission on the restored table ARN (CONDITIONAL path).
match:
- - principal: null
- HasPermission
- table: null
where:
- node_type(?table) == NoSQLDatabase
- ?table.provider_type in ['AWS::DynamoDB::Table', 'AWS::DynamoDB::GlobalTable']
- ?principal has EFFECTIVE dynamodb:RestoreTableToPointInTime on ?table ARN
- ?table.properties.PointInTimeRecoveryStatus == 'ENABLED'
emit:
source_type: Identity
target_type: NoSQLDatabase
source: ?principal
target: ?table
permissions:
- dynamodb:RestoreTableToPointInTime
conditions:
- iam_permission
- scp_or_org_policy
- service_state
state_logic: CONDITIONAL(iam_permission) when dynamodb:RestoreTableToPointInTime is confirmed EFFECTIVE
on the source table ARN AND PITR is enabled. RestoreTableToPointInTime creates a NEW table but does
NOT automatically grant the restoring principal read access to the NEW table's ARN. The principal
must have a SEPARATE, confirmed EFFECTIVE permission (dynamodb:GetItem, dynamodb:Query, or dynamodb:Scan)
on the newly-restored table's ARN to read items. This typically requires a wildcard permission (e.g.,
dynamodb:GetItem on arn:aws:dynamodb:*:*:table/* or arn:aws:dynamodb:region:account:table/restored-*)
or an explicit grant on the new table. Emit as CONDITIONAL(iam_permission); upgrade to ACTIVE only
when an aws-dynamodb-read-data edge is confirmed on the restored table ARN. CONDITIONAL(service_state)
when PITR is disabled. BLOCKED by an SCP or permission-boundary deny on RestoreTableToPointInTime.
confidence: min(contributing_confidences) * 0.85
derived_from:
- ?principal HasPermission ?table (dynamodb:RestoreTableToPointInTime effective permission)
- ?table PointInTimeRecoveryStatus == ENABLED
- aws-dynamodb-read-data (separate edge required on restored table ARN)
false_positive_note: "PITR must be enabled on the SOURCE table. RestoreTableToPointInTime is a single\
\ action that creates the target table as part of its operation \u2014 no separate dynamodb:CreateTable\
\ permission is required per AWS Service Authorization Reference. The restored table is created in\
\ the SAME ACCOUNT as the calling principal \u2014 DynamoDB does not support cross-account restore\
\ directly (unlike Redshift). CRITICAL: the principal MUST HAVE a confirmed EFFECTIVE GetItem/Scan/Query\
\ permission on the NEW restored table's ARN to read it; restore access alone does not grant read\
\ capability. This is not a false positive IF the principal has a wildcard dynamodb:GetItem on arn:aws:dynamodb:*:*:table/*\
\ or equivalent, but CONDITIONAL(iam_permission) otherwise. The SSE key of the source table is inherited\
\ by the restored table \u2014 additional CONDITIONAL(key_permission) applies if the source table\
\ uses a CMK the principal cannot decrypt. Subsequent read access on the restored table is captured\
\ separately by aws-dynamodb-read-data; do not treat restore access as implied read access."
narrative: '{principal.name} can restore a point-in-time copy of {table.name} (dynamodb:RestoreTableToPointInTime),
creating a new table with full historical item data. Reading the new table requires a separate GetItem/Scan/Query
permission on the restored table ARN.'