feat(s3,sqs,sns): wire Phase 1 IAM enforcement#399
Merged
vieiralucas merged 2 commits intomainfrom Apr 15, 2026
Merged
Conversation
Extends the IAM enforcement surface (started in PR #395 with IAM+STS) to cover the three most-used queue/storage services. Along with IAM+STS, this matches the same enforcement surface LocalStack Pro ships for its paid IAM feature. SQS: - All 20 supported SQS actions map to sqs:<Action>. - Queue ARN is built from QueueName (CreateQueue, GetQueueUrl) or from the trailing segment of QueueUrl (all other queue-targeted actions). Account-level actions (ListQueues) target '*'. - Account id is sourced from principal.account_id (#381 note). SNS: - All 34 supported SNS actions map to sns:<Action>. - Topic-targeted actions read TopicArn; subscription-targeted actions read SubscriptionArn; platform app / endpoint / tagging actions read their respective *Arn params. CreateTopic builds the to-be-created topic ARN from the principal's account + Name. - Account-scoped actions (ListTopics, SetSMSAttributes, ...) resolve to '*'. S3: - All 74 supported S3 actions are classified by s3_resource_for into bucket or object ARNs (arn:aws:s3:::bucket[/key]); ARNs intentionally omit account+region because bucket names are globally unique in AWS. - New s3_detect_action() helper derives the IAM action name from method + bucket + key + query params, since S3 dispatches internally on method+path and doesn't set request.action. Handles the common object/bucket operations plus ?acl / ?tagging / ?versioning / ?policy / ?cors / ?website / ?lifecycle / ?encryption / ?logging / ?notification / ?replication / ?ownershipControls / ?publicAccessBlock / ?accelerate / ?inventory / ?object-lock / ?uploads / ?uploadId sub-resources. Tests: 5 new e2e tests in iam_enforcement.rs: - SQS SendMessage denied without policy - SQS resource-scoped Allow: jobs queue allowed, secrets queue denied under the same action/principal - SNS Publish denied without policy - SNS Publish allowed on a specific topic ARN - S3 ReadDocs policy: GetObject allowed on private-docs/readme.md, PutObject on the same bucket denied (different action) All 13 iam_enforcement tests pass end-to-end via real aws-sdk-rust signed requests.
There was a problem hiding this comment.
4 issues found across 4 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="crates/fakecloud-s3/src/service/mod.rs">
<violation number="1" location="crates/fakecloud-s3/src/service/mod.rs:800">
P2: Missing method guard on `?attributes` sub-resource — any HTTP method with `?attributes` maps to `GetObjectAttributes`. Should match GET only, consistent with all other sub-resource handlers.</violation>
<violation number="2" location="crates/fakecloud-s3/src/service/mod.rs:803">
P2: Missing method guard on `?restore` sub-resource — any HTTP method (including GET) with `?restore` in the query string maps to `RestoreObject` instead of falling through to the correct plain-method dispatch. Since RestoreObject is a POST-only operation, this should only match POST. A GET with `?restore` present would be IAM-checked against `s3:RestoreObject` instead of `s3:GetObject`.</violation>
</file>
<file name="crates/fakecloud-sns/src/service.rs">
<violation number="1" location="crates/fakecloud-sns/src/service.rs:155">
P2: `CreateTopic` IAM resource account derivation is inconsistent with actual topic ARN creation (`state.account_id`), which can cause policy evaluation against the wrong ARN.</violation>
<violation number="2" location="crates/fakecloud-sns/src/service.rs:180">
P2: `ConfirmSubscription` is mapped to `SubscriptionArn`, but the request uses `TopicArn`; this makes IAM evaluate the wrong resource (`*` fallback in most calls).</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Identified by cubic on PR #399: S3: - ?attributes sub-resource now requires GET — previously any method with ?attributes mapped to GetObjectAttributes, which was inconsistent with the other sub-resource handlers that all method-gate. - ?restore sub-resource now requires POST — previously a GET with ?restore would be classified as RestoreObject (POST-only in AWS) and IAM-evaluated against s3:RestoreObject instead of s3:GetObject. SNS: - CreateTopic IAM resource now sources its account id from state.account_id via self.state.read(), matching how the handler actually builds the topic ARN (via Arn::new(..., &state.account_id, ...)). Previously it used principal.account_id, which is the same value today but would diverge under multi-account isolation (#381) and cause policy evaluation to target a different ARN than the one the handler creates. Keeping them consistent means #381 will update both sites in the same change. - ConfirmSubscription is now keyed by TopicArn, not SubscriptionArn — the ConfirmSubscription API takes a Token against a topic, and the subscription ARN only exists after confirmation. Previously the resource fell back to '*' in most calls.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extends the IAM enforcement surface (started in PR #395 with IAM+STS) to cover S3 + SQS + SNS — the three most-used queue/storage services. Combined with the IAM+STS coverage from #395, this matches the same enforcement surface LocalStack Pro ships for its paid IAM feature.
SQS
sqs:<Action>.QueueName(CreateQueue,GetQueueUrl) or from the trailing segment ofQueueUrlfor queue-targeted calls.ListQueues→*.principal.account_id(Feature proposal: multi-account isolation within a single fakecloud instance #381 note).SNS
sns:<Action>.TopicArn; subscription-targeted actions readSubscriptionArn; platform-app/endpoint/tagging actions read their respective*Arnparams.CreateTopicbuilds the to-be-created topic ARN from the principal's account +Name.ListTopics,SetSMSAttributes, ...) →*.S3
s3_resource_forinto bucket or object ARNs (arn:aws:s3:::bucket[/key]); S3 ARNs intentionally omit account+region because bucket names are globally unique in AWS.s3_detect_action()helper re-derives the IAM action name from method + bucket + key + query params, since S3 dispatches internally on method+path and doesn't setrequest.action. Handles:GetObject,PutObject,DeleteObject,HeadObject,CopyObjectListBuckets,CreateBucket,DeleteBucket,HeadBucket,GetBucketLocation,ListObjectsV2,ListObjects,ListObjectVersions,DeleteObjects?acl/?tagging/?versioning/?policy/?cors/?website/?lifecycle/?encryption/?logging/?notification/?replication/?ownershipControls/?publicAccessBlock/?accelerate/?inventory/?object-lockCreateMultipartUpload,UploadPart,CompleteMultipartUpload,AbortMultipartUpload,ListParts,ListMultipartUploadsTest plan
5 new E2E tests in
iam_enforcement.rs(on top of the 8 from PR #395), all signed with realaws-sdk-rustclients:SendMessagedenied without policy →AccessDeniedExceptionAllowonjobsqueue lets throughjobsmessages but deniessecretsmessages (same action, different resource)Publishdenied without policyPublishallowed on specific topic ARN via dynamically-composed inline policyReadDocspolicy:GetObjectonprivate-docs/readme.mdallowed,PutObjecton same bucket denied (different action)Plus:
cargo test -p fakecloud-e2e --test iam_enforcement— 13 tests all green (8 from feat(iam,sts): wire Phase 1 enforcement for IAM + STS services #395 + 5 new)cargo test -p fakecloud-e2e --test iam --test s3 --test sqs --test sns --test sigv4_verification— 183 tests total, zero regressionscargo clippy --workspace --all-targets -- -D warningscleancargo fmt --checkcleanSummary by cubic
Adds Phase 1 IAM enforcement for S3, SQS, and SNS, with precise action-to-resource mapping and new E2E coverage. Also fixes S3 sub-resource method guards and SNS ARN/resource detection for consistency.
New Features
sqs:<Action>; queue ARN fromQueueName(CreateQueue,GetQueueUrl) or last segment ofQueueUrl;ListQueues→*; account id fromprincipal.account_id.sns:<Action>; resources fromTopicArn/SubscriptionArn/PlatformApplicationArn/EndpointArn;CreateTopicbuilds ARN from service state account +Name; account-scoped actions →*.s3_detect_action()derives the IAM action from method + bucket + key + query; 74 actions mapped to bucket/object ARNsarn:aws:s3:::bucket[/key](ListBuckets→*).SendMessagedeny and resource-scoped allow/deny, SNSPublishdeny/allow, and S3GetObjectallowed vsPutObjectdenied.Bug Fixes
?attributesand POST for?restoreto avoid misclassifying IAM actions.CreateTopicIAM resource uses the service state account id to match the created ARN;ConfirmSubscriptionis keyed byTopicArninstead ofSubscriptionArn.Written for commit 28bcfc6. Summary will update on new commits.