Skip to content

feat(auth): resource ARNs for IAM, SQS, SNS and DynamoDB (AUTHZ-X1e) - #1443

Draft
NitinKumar004 wants to merge 1 commit into
developmentfrom
feat/auth-resource-arns
Draft

NitinKumar004 wants to merge 1 commit into
developmentfrom
feat/auth-resource-arns

Conversation

@NitinKumar004

Copy link
Copy Markdown
Collaborator

AUTHZ-X1e from the AUTHZ-X1 plan (§2 Resource ARNs). Before this change, IAM, SNS and SQS were authorized under --enforce-auth against an unknown resource, and DynamoDB had a table ARN only for requests with a top-level TableName. As a result, a policy such as sqs:SendMessage on one queue denied every queue, and Allow dynamodb:* with Deny ... table/prod also blocked a BatchWriteItem that touched only dev. With this change, each request is authorized against the resource it actually acts on.

What changed

IAM (server/aws/iam/authz.go)

  • iamActions now maps every served action to its resource type: user, role, group, policy, instance-profile or mfa.
  • If the entity exists, the check uses its stored ARN, including the path. If it doesn't exist, the ARN is built from Path and the name, the same way the backend builds it on create. The deny message only names what the request sent.
  • PolicyArn, SerialNumber and PolicySourceArn are accepted only in this account, or as an AWS managed policy for policies.
  • List and account operations use *.
  • GetUser without UserName, and CreateServiceLinkedRole, stay unknown.

SQS (server/aws/sqs/authz.go)

  • SQS is now a Resolver, no longer registered through the JSON-RPC table.
  • The queue name comes from QueueUrl (last path segment, which is the only key the backend matches), QueueName, SourceArn, or the source ARN inside a move-task handle. The ARN is arn:aws:sqs:<server region>:<server account>:<name>.
  • The *Batch operations are authorized as the single-message action (sqs:SendMessage, sqs:DeleteMessage, sqs:ChangeMessageVisibility), which is how AWS authorizes them.
  • ListQueues uses *.

SNS (server/aws/sns/authz.go)

  • The topic comes from TopicArn, TargetArn or ResourceArn, using the last field, which is the topic the handler runs on. For a SubscriptionArn it uses the topic field.
  • CreateTopic uses Name.
  • PublishBatch is authorized as sns:Publish.
  • Both publish handlers now share publishTarget, so the gate and dispatch read the same parameter.

DynamoDB (server/aws/dynamodb/authz.go)

  • DynamoDB and DynamoDB Streams are now Resolvers.
  • Every operation is authorized on its table ARN:
    • Query, Scan and the contributor-insights ops use table/x/index/y when IndexName is set.
    • BatchGetItem and BatchWriteItem get one check per table.
    • TransactWriteItems gets PutItem, UpdateItem, DeleteItem or ConditionCheckItem per element, with the element kind picked by the same toTxOp dispatch uses.
    • TransactGetItems gets GetItem per table.
    • Backups use the backup ARN. Restores check both the backup or source and the target. Global tables use the regionless global-table ARN.
    • Tags go through the same tableFromARN the handler uses.
    • GetRecords is authorized on the stream of the table its shard iterator names.

Gate and shared helpers

  • deriveResource and jsonField are removed from the gate. JSON-RPC handlers still on the target table get an unknown resource.
  • Region and account always come from the server Scope, never from the request.
  • If a request doesn't name a well-formed resource, or its body doesn't decode, the resource stays unknown and is evaluated conservatively.
  • awsauthz gains Scope.ARN, Scope.GlobalARN and JSONBody. JSONBody decodes the same way wire.DecodeJSON does and puts the body back.

I checked the action-to-resource mapping against the service authorization reference data for IAM, SQS, SNS and DynamoDB (servicereference.us-east-1.amazonaws.com, the machine-readable form of the "Actions, resources, and condition keys" pages).

Known gaps, left for later:

  • CreateServiceLinkedRole stays unknown, because the role name is derived in the provider.
  • Restore ops don't add the item-level actions AWS also requires on the target table.

Tests

  • Per-op IAMChecks table tests for iam, sqs, sns, dynamodb and streams.
  • Drift test: every DynamoDB table op is actually served.
  • server/aws/authz_resource_arns_test.go adds matrix rows:
    • sqs:SendMessage on q1 passes on q1, including the batch op, and returns 403 on q2.
    • sns:* on t1 lets a publish to t1 through but denies t2, and denies Unsubscribe of a t2 subscription.
    • Allow dynamodb:* with Deny table/prod blocks prod in PutItem, BatchWriteItem and TransactWriteItems, and only there.
    • An index-only Query grant does not cover the base table.
    • iam:* on user/dev/* covers alice (path /dev/) by name but not bob.
  • contrib/server adds a real-SDK subtest under serve --enforce-auth, scoped to q1: q1 send and batch pass, q2 is denied, and so is ReceiveMessage.
  • The new matrix rows and the contrib subtest fail on development and pass here.

Verification

  • go build ./...
  • go vet and go test -race on server/aws, server/aws/{iam,sqs,sns,dynamodb}, server/wire/awsauthz, providers/aws/iam and compat/aws
  • go -C contrib/server test -run Enforce
  • golangci-lint --new-from-rev=origin/development: 0 issues
  • coveragegen: no change

aws CLI against cloudemu serve --enforce-auth on :64966, bootstrapped with the admin token and a seeded iamUsers key. The limited user had SendMessage on q1, Publish on t1, item ops on tdev, and GetUser/TagUser on user/dev/*.

  • Allowed as expected: q1 send and batch, t1 publish, tdev put/get/batch, and get-user/tag-user on alice.
  • Denied as expected: q2 send and batch, receive on q1, a t2 publish by topic or target, tprod put, a tdev+tprod batch and transact, and bob get/tag.
  • Afterwards q2 and tprod were empty and bob had no tags.
  • 25/25 checks passed.

IAM, SQS, SNS and DynamoDB now name the resource each request acts on, so resource-scoped Allow and Deny statements apply under --enforce-auth. SQS and DynamoDB move from the gate's target table to their own IAMChecks; the gate's DynamoDB-only deriveResource is gone.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant