Skip to content

fix(authz): check a point-in-time restore's target before its source - #827

Merged
LeeroyHannigan merged 4 commits into
mainfrom
fix/446-pitr-authz-order
Nov 9, 2026
Merged

LeeroyHannigan merged 4 commits into
mainfrom
fix/446-pitr-authz-order

Conversation

@LeeroyHannigan

@LeeroyHannigan LeeroyHannigan commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

What

RestoreTableToPointInTime now authorizes the item actions on the target table before dynamodb:RestoreTableToPointInTime on the source table. For a caller with no policy, the denial now names dynamodb:Scan on the target table, as on Amazon DynamoDB. On main, it names the restore action on the source table.

authz_targets in crates/server/src/authz_resource.rs returns the target's item actions first and the source's restore action last. authorize_request checks the pairs in that order, and the first denied pair is the one the denial names. The set of required actions and resources does not change, so a request that a policy allows on main is still allowed.

The admin guide's resource table and its restore note, and the v0.1.15 upgrade note, describe the new order.

This pull request does not implement point-in-time restore, which stays unsupported as on main since #335. An authorized restore still answers PointInTimeRecoveryUnavailableException, and an index SourceTableArn still answers ValidationException: Invalid Request: Table ARN is invalid. A new test pins that second answer.

Why

#446 measured both answers on the service on 22 October, for a caller with no policy and for an admin, with an index SourceTableArn. The denial on main named a different action and resource. A policy written against the service's denial therefore sees a different action and resource on ExtendDB.

Part of #446

Testing done

  • restore_order_tests.rs in crates/server/src/authz_resource/ checks the order of the authorization targets and the denial for a caller with no policy. other_arn_fields_keep_the_supplied_spelling now reads the source from the last target. With main's order, all three tests fail.
  • Two tests in tests/test_authz_resource_arn.py send a RestoreTableToPointInTime request with an index SourceTableArn. The first expects the denial for a caller with no policy to name dynamodb:Scan on the target. The second expects Invalid Request: Table ARN is invalid. for a caller allowed dynamodb:*. I ran the four restore tests of the file against a SQLite server built from this branch: 4 passed. With main's order restored in authz_targets, the dynamodb:Scan test fails and the other three pass. The Table ARN is invalid answer is already on main, so that test passes there too.
  • cargo +1.97.0 fmt --all -- --check: clean.
  • cargo +1.97.0 clippy --locked -p extenddb-server --all-targets -- -D warnings: clean.
  • cargo +1.88.0 test --locked -p extenddb-server: 295 passed.

Checklist

  • I have read CONTRIBUTING.md
  • All tests pass (cargo test --workspace)
  • Code is formatted (cargo fmt --check)
  • Clippy is clean (cargo clippy -- -W clippy::pedantic)
  • I have added or updated tests for new functionality
  • I have updated documentation if behavior changed
  • Breaking changes are noted below (if any)
  • If this changes the wire protocol, Storage trait, auth model, on-disk
    format, or public CLI surface, an RFC has been accepted or is linked
    below. Otherwise, an ADR captures the decision (link below).

ADR / RFC: n/a


By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache License 2.0 and I agree to the Developer Certificate of
Origin (DCO). See CONTRIBUTING.md for details.

…446)

RestoreTableToPointInTime now authorizes the item actions on the target
table before dynamodb:RestoreTableToPointInTime on the source table. The
service checks them in that order: a caller with no policy is denied on
dynamodb:Scan on the target table (measured 2026-10-22 with an index
SourceTableArn). ExtendDB denied the same caller on the restore action on
the source table.

The set of required actions and resources is unchanged; only the order,
and so the action and resource a denial names, changes.
The admin guide's resource table and restore compatibility note, and the
v0.1.15 point-in-time recovery upgrade note, state that the target's item
actions are checked before the restore action, so a caller with no policy
is denied naming dynamodb:Scan on the target table.
…e answer (#446)

A caller with no policy and an index SourceTableArn is denied naming
dynamodb:Scan on the target table, and a caller allowed dynamodb:* gets
ValidationException "Invalid Request: Table ARN is invalid." for the same
request. Both answers are the service's, measured on 2026-10-22.

@eliseong eliseong left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

RestoreTableToPointInTime now authorizes the target table's item actions before the restore action on the source. I measured the live service and ran a local instance from this branch.

  • On the live service, a restore request denies on an item action on the target table, not on the restore action on the source. The denial names the target table as the resource.
  • On an instance built from this branch: a caller with no policy is denied on dynamodb:Scan on the target; a caller allowed dynamodb:* with an index SourceTableArn gets Invalid Request: Table ARN is invalid.; and a well-formed authorized restore answers PointInTimeRecoveryUnavailableException, since the feature stays unimplemented.
  • A caller allowed only the restore action, and not the item actions, is now denied on the target. A caller allowed the item actions but not the restore action is denied on the restore action on the source. Item-action grants scoped to a different table name do not satisfy the check.
  • A target ARN that names another account or region, or that carries an index suffix, resolves to the caller's own account and region on the base table, so it does not change which resource is checked.
  • Restoring the source-first order fails the two order tests.

This is a partial fix for its issue, which stays open for the restore implementation.

@eliseong
eliseong added this pull request to the merge queue Nov 9, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Nov 9, 2026
@eliseong
eliseong added this pull request to the merge queue Nov 9, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Nov 9, 2026
@LeeroyHannigan
LeeroyHannigan added this pull request to the merge queue Nov 9, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Nov 9, 2026
@eliseong
eliseong added this pull request to the merge queue Nov 9, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Nov 9, 2026
@LeeroyHannigan
LeeroyHannigan added this pull request to the merge queue Nov 9, 2026
Merged via the queue into main with commit e24ff1a Nov 9, 2026
39 checks passed
@LeeroyHannigan
LeeroyHannigan deleted the fix/446-pitr-authz-order branch November 9, 2026 20:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-blocker Must ship for its milestone's release v1 Needed for the 1.0 release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants