Skip to content

ImportTable with a table ARN as the new table's name passes authorization; the service denies it to an admin #797

Open

Description

@LeeroyHannigan

What DynamoDB does

Measured 2026-11-03 in us-east-1. Each request is an ImportTable with S3BucketSource naming a bucket that does not exist and InputFormat DYNAMODB_JSON. Its TableCreationParameters has pk (S) as the HASH key and PAY_PER_REQUEST, and its TableName is a table ARN in another account, arn:aws:dynamodb:us-east-1:<other account>:table/<T>. Each caller sent it once with an account that exists and once with one that does not, and got the same answer both times:

Caller Answer
an admin AccessDeniedException "User: is not authorized to perform: dynamodb:ImportTable on resource: arn:aws:dynamodb:us-east-1::table/arn:aws:dynamodb:us-east-1::table/"
no policy the same

The message has no "because ..." clause. A table ARN in the caller's own account was not sent.

What ExtendDB does

The same requests were replayed on 2026-11-03 against a SQLite server built from e3b0f96 (the head of #509), which has no [import] paths. Both accounts gave the same answers:

Caller Answer
a user allowed dynamodb:* on * ValidationException "Import is disabled. Configure [import] paths in extenddb.toml to enable."
no policy AccessDeniedException with the service's message followed by " because no identity-based policy allows the dynamodb:ImportTable action"

The allowed user passes the IAM decision and the engine answers.

Code path

  • At e3b0f96, authz_targets authorizes ImportTable on arn:aws:dynamodb:<region>:<caller account>:table/<value as written> (597c1dc). An Allow on * matches that resource.
  • On main (03baa32) the resource is table_resource_arn of the value, which reduces a table ARN to table/<T> in the caller's account (crates/server/src/authz_resource.rs:551-558 and :370-385), so the no-policy denial on main names that ARN instead (read from the code, not replayed).
  • deny_message adds "because no identity-based policy allows the action" to a denial that no explicit Deny caused (crates/server/src/authorization.rs:287-301 on main).
  • fix(server): name the supplied ARN in a denial #509's cross-account refusal skips ImportTable, because the service reads the table name as a name (find in crates/server/src/authz_resource/cross_account.rs).
  • handle_import_table answers "Import is disabled" when no import paths are configured (crates/engine/src/import_export.rs:43-47). With import paths and a readable FileSource, it passes the value as written to create_table without the CreateTable name checks (:80-85, ImportTable creates a table under a name CreateTable refuses #771).

Expected

An ImportTable whose TableCreationParameters.TableName is a table ARN gets the service's AccessDeniedException, with no reason clause, for both callers and before the engine runs. The answer for these values was not measured: a table ARN in the caller's own account, an index or stream ARN, and a value that starts with arn: but is not an ARN.

Related

#771 asks ImportTable to refuse the names CreateTable refuses, with the service's ValidationExceptions. For a table ARN the service answers this AccessDeniedException instead, to an admin as well as to a caller with no policy, so the ARN case has to be answered before #771's name check.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions