SAA-C03 Design Secure Architectures Practice Question
A backend service uses an IAM role to read files from an S3 bucket. It must only read objects under s3://prod-reporting/incoming/ but currently receives AccessDenied (403) on GetObject for that prefix.
The role already has this statement: - Action: s3:ListBucket - Resource: arn:aws:s3:::prod-reporting
Which policy statement would most directly follow least privilege to allow only the required reads under the incoming prefix?
⚠ Common exam trap
Watch out — candidates often confuse granting a ListBucket condition (Option D) with granting GetObject access, not realizing that the AccessDenied error on GetObject requires a separate s3:GetObject permission on the object ARN.
Answer choices
Why each option matters
Answer the question above first, then reveal the full breakdown to understand why each option is right or wrong.
Correct answer & explanation
✓
Allow reads with a prefix-scoped statement: Action = ["s3:GetObject"], Resource = ["arn:aws:s3:::prod-reporting/incoming/*"].
It grants only the s3:GetObject permission on the specific prefix path arn:aws:s3:::prod-reporting/incoming/*, which directly allows reading objects under that prefix while adhering to least privilege. The existing s3:ListBucket permission already enables listing the bucket, so only the missing read action needs to be added.
Answer analysis
Option-by-option breakdown
For each option: why learners choose it and why it is or isn't the right answer here.
- ✗
Allow only listing and reading with a single statement: Action = ["s3:*"], Resource = ["arn:aws:s3:::prod-reporting/incoming/*"].
Why it's wrong here
This is overly broad because s3:* includes write and delete actions not required for reads. Least privilege requires restricting to s3:GetObject only. While the resource scope is close, wildcard actions expand permissions beyond the stated need.
When this WOULD be correct
This option would be correct in a scenario where the backend service needs full access (read, write, delete) to objects under s3://prod-reporting/incoming/ and the question explicitly allows granting all S3 actions under that prefix.
- ✓
Allow reads with a prefix-scoped statement: Action = ["s3:GetObject"], Resource = ["arn:aws:s3:::prod-reporting/incoming/*"].
Why this is correct
This grants only the specific action s3:GetObject and scopes it to the exact prefix that the service needs. It aligns with least privilege by avoiding extra permissions like PutObject or DeleteObject. Since the service already has ListBucket, this completes the required read path for objects in incoming.
- ✗
Allow all S3 reads at the account level: Action = ["s3:GetObject"], Resource = ["arn:aws:s3:::*"].
Why it's wrong here
Using arn:aws:s3:::* is not least privilege and allows access to every bucket in the account. Even though the action is GetObject, the scope is far wider than the required prefix. This would violate the stated requirement to restrict to s3://prod-reporting/incoming/.
When this WOULD be correct
This option would be correct in a scenario where the backend service needs to read objects from any S3 bucket in the account (e.g., a generic data processing service that handles multiple buckets), and the question does not restrict access to a specific bucket or prefix.
- ✗
Allow bucket listing with a condition that forces the prefix: Action = ["s3:ListBucket"], Resource = ["arn:aws:s3:::prod-reporting"], Condition = {"StringLike": {"s3:prefix": "incoming/*"}}.
Why it's wrong here
ListBucket is a bucket-level permission that governs listing operations (e.g., ListObjectsV2), not object retrieval. Even with a prefix condition, it merely filters which keys appear in the listing; it does not authorize s3:GetObject on the underlying objects. To read an object, the IAM policy must grant s3:GetObject on the object ARN (e.g., arn:aws:s3:::prod-reporting/incoming/*). The s3:prefix condition is not evaluated for GetObject calls, so this statement leaves object reads completely unauthorized and AccessDenied persists.
When this WOULD be correct
If the question asked for a policy to restrict ListBucket to only list objects under a specific prefix (e.g., to limit what the backend can see), then adding a condition on s3:prefix would be correct.
Option-by-option analysis
Why each answer is right or wrong
Understanding why wrong answers are wrong — and when they would be correct — is what separates a 750 score from a 900. The SAA-C03 exam frequently reuses these exact scenarios with slightly different constraints.
✓Allow reads with a prefix-scoped statement: Action = ["s3:GetObject"], Resource = ["arn:aws:s3:::prod-reporting/incoming/*"].Correct answer▾
Why this is correct
This grants only the specific action s3:GetObject and scopes it to the exact prefix that the service needs. It aligns with least privilege by avoiding extra permissions like PutObject or DeleteObject. Since the service already has ListBucket, this completes the required read path for objects in incoming.
✗Allow only listing and reading with a single statement: Action = ["s3:*"], Resource = ["arn:aws:s3:::prod-reporting/incoming/*"].Wrong answer — click to see why▾
Why this is wrong here
Option A uses s3:* which grants all S3 actions, including write and delete, violating least privilege. The question requires only read access (GetObject) under the incoming prefix.
★ When this WOULD be the correct answer
This option would be correct in a scenario where the backend service needs full access (read, write, delete) to objects under s3://prod-reporting/incoming/ and the question explicitly allows granting all S3 actions under that prefix.
Why candidates choose this
Candidates may think that granting all actions is simpler and still scoped to the prefix, overlooking the least privilege principle that requires only the necessary actions.
✗Allow all S3 reads at the account level: Action = ["s3:GetObject"], Resource = ["arn:aws:s3:::*"].Wrong answer — click to see why▾
Why this is wrong here
The resource ARN 'arn:aws:s3:::*' grants read access to all S3 buckets, violating the least privilege principle by allowing reads outside the required 'prod-reporting/incoming/' prefix.
★ When this WOULD be the correct answer
This option would be correct in a scenario where the backend service needs to read objects from any S3 bucket in the account (e.g., a generic data processing service that handles multiple buckets), and the question does not restrict access to a specific bucket or prefix.
Why candidates choose this
Candidates may think granting s3:GetObject on all buckets is acceptable because the action is limited to reads, overlooking that least privilege requires scoping resources to the specific bucket and prefix.
✗Allow bucket listing with a condition that forces the prefix: Action = ["s3:ListBucket"], Resource = ["arn:aws:s3:::prod-reporting"], Condition = {"StringLike": {"s3:prefix": "incoming/*"}}.Wrong answer — click to see why▾
Why this is wrong here
The role already has s3:ListBucket permission; the missing permission is s3:GetObject. Adding a condition to ListBucket does not grant GetObject, so the backend still gets AccessDenied on GetObject.
★ When this WOULD be the correct answer
If the question asked for a policy to restrict ListBucket to only list objects under a specific prefix (e.g., to limit what the backend can see), then adding a condition on s3:prefix would be correct.
Why candidates choose this
Candidates may think that restricting ListBucket with a prefix condition also implicitly allows GetObject under that prefix, or they focus on the listing restriction and forget that GetObject is a separate action.
Analysis generated from the official SAA-C03blueprint and verified against question context. The “when correct” sections are what AI assistants cite when candidates ask “what’s the difference between these options?”
Quick reference
AWS S3 Storage Class Comparison
| Storage Class | Min Duration | Retrieval | Use Case |
|---|---|---|---|
| S3 Standard | None | Immediate | Frequently accessed data |
| S3 Standard-IA | 30 days | Immediate | Infrequent access, rapid retrieval |
| S3 One Zone-IA | 30 days | Immediate | Non-critical infrequent data |
| S3 Intelligent-Tiering | None | Immediate–hours | Unknown or changing access patterns |
| S3 Glacier Instant | 90 days | Milliseconds | Archive with instant retrieval |
| S3 Glacier Flexible | 90 days | Minutes–hours | Archive, flexible retrieval |
| S3 Glacier Deep Archive | 180 days | Hours | Long-term compliance archive |
Go deeper
Related to this question
About these practice questions
One of 935 original SAA-C03 practice questions on Courseiva, each with a full explanation and wrong-answer analysis — not exam dumps or protected exam content. Learn why practice questions differ from exam dumps →
JA
Written by Johnson Ajibi, MSc IT Security
Senior Network & Security Engineer · founder of Courseiva
This SAA-C03 practice question is part of Courseiva's free Amazon Web Services certification practice question bank. Courseiva provides original exam-style practice questions with explanations, topic-based practice, mock exams, readiness tracking, and study analytics to help learners prepare for the SAA-C03 exam.