This chapter covers S3 security mechanisms including bucket policies, Access Control Lists (ACLs), and encryption options. Understanding these is critical for the SAA-C03 exam, as S3 security questions appear in roughly 15-20% of exam scenarios, often requiring you to choose the correct combination of policies and encryption to meet compliance requirements. You will learn how to control access at the bucket and object level, enforce encryption in transit and at rest, and avoid common misconfigurations that lead to data exposure.
Jump to a section
Imagine a bank vault that stores safety deposit boxes. The vault itself has multiple layers of security: a perimeter fence (VPC endpoints), a front door (bucket policies), a guard who checks IDs (IAM policies), and each box has its own key lock (ACLs). The bank also has a policy that only certain tellers can open certain boxes, and they must present both their employee badge (IAM role) and the box-specific key (ACL). Additionally, the bank encrypts the contents of each box with a unique key (SSE-S3, SSE-KMS, or SSE-C) before storing it. If a customer wants to share a box with someone else, the bank can grant temporary access via a pre-signed URL (like a time-limited access code). The bank also maintains an audit log of every access (CloudTrail). Just as the bank's security is layered and each layer must be satisfied for access, S3 security requires that both the resource-based policy (bucket policy) and user identity (IAM) grant permission, and then the object itself may have additional ACL restrictions. Misconfiguring any layer can lead to unauthorized access or data breaches.
What is S3 Security and Why It Matters
Amazon S3 (Simple Storage Service) is a highly durable and scalable object storage service. Security in S3 is multi-layered, encompassing identity-based policies (IAM), resource-based policies (bucket policies and ACLs), encryption (at rest and in transit), and access logging. The SAA-C03 exam heavily tests your ability to design secure storage solutions that meet specific compliance and access control requirements.
Bucket Policies: The Primary Resource-Based Control
A bucket policy is a JSON-formatted resource-based policy attached directly to an S3 bucket. It defines who (principal) can perform what actions (effect, action) on which resources (resource) under what conditions (condition). Bucket policies are evaluated when an IAM principal makes a request to the bucket. The policy can grant or deny access to the entire bucket or specific objects (using a wildcard arn:aws:s3:::bucket-name/*).
Key elements of a bucket policy:
- Version: Always "2012-10-17" (the current policy language version).
- Statement: An array of individual permission statements.
- Effect: "Allow" or "Deny".
- Principal: The AWS account/user/role to which the policy applies. For cross-account access, you specify the AWS account ID.
- Action: S3 API actions like s3:GetObject, s3:PutObject, s3:ListBucket.
- Resource: The ARN of the bucket or objects, e.g., arn:aws:s3:::my-bucket for the bucket itself, arn:aws:s3:::my-bucket/* for all objects.
- Condition: Optional conditions using AWS global condition keys or S3-specific keys like s3:x-amz-acl, s3:VersionId, aws:SourceIp, aws:MultiFactorAuthPresent.
Example policy that grants public read access to objects in a bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}ACLs: Legacy Object-Level Control
Access Control Lists (ACLs) are a legacy access control mechanism that predates IAM and bucket policies. They can be applied at the bucket or object level. Each ACL consists of a set of grants specifying the grantee (e.g., an AWS account or a predefined group like AllUsers or AuthenticatedUsers) and the permission (e.g., READ, WRITE, FULL_CONTROL). ACLs are less flexible than bucket policies and are generally not recommended for new deployments. However, the exam tests your understanding of when ACLs are still relevant (e.g., when you need to grant access to specific objects to different AWS accounts without using IAM roles).
By default, ACLs are disabled on new S3 buckets unless you specifically enable them. The recommended approach is to use bucket policies and IAM for access control, and to disable ACLs (the default).
Encryption: Protecting Data at Rest
S3 offers several encryption options for data at rest:
- SSE-S3 (Server-Side Encryption with S3-Managed Keys): Amazon S3 manages the encryption keys. Each object is encrypted with a unique key, and the key itself is encrypted with a master key that rotates regularly. This is the simplest option, requiring no additional configuration from the user. To use SSE-S3, you set the x-amz-server-side-encryption header to AES256.
- SSE-KMS (Server-Side Encryption with AWS KMS-Managed Keys): You use AWS Key Management Service (KMS) to manage the encryption keys. This provides additional control, such as separate permissions for key usage (via KMS key policies) and the ability to audit key usage via CloudTrail. You can use a customer managed key or the default AWS managed key (aws/s3). To use SSE-KMS, set the header to aws:kms and optionally specify a key ID via x-amz-server-side-encryption-aws-kms-key-id.
- SSE-C (Server-Side Encryption with Customer-Provided Keys): You provide your own encryption key, and S3 manages the encryption/decryption process. The key is never stored by AWS; you must provide it with every request. This option is useful for organizations that need to control their own keys but want S3 to handle the encryption. The key is sent in the x-amz-server-side-encryption-customer-key header.
- Client-Side Encryption: You encrypt data before uploading it to S3 using your own encryption library or tools (e.g., Amazon S3 Encryption Client). AWS never sees the plaintext data or encryption keys.
Encryption in Transit
S3 supports both HTTP and HTTPS. To enforce encryption in transit, you can use a bucket policy that denies requests where aws:SecureTransport is false. Example:
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}How S3 Access Control Works: The Evaluation Logic
When a request is made to S3, the following evaluation logic applies: 1. The request must be authenticated (unless it's an anonymous request). 2. The user's identity-based policy (IAM) is evaluated. 3. The resource-based policy (bucket policy) is evaluated. 4. If ACLs are enabled, they are also evaluated. 5. The default is to deny all access. An explicit allow in any of the policies (IAM, bucket policy, ACL) will grant access, unless there is an explicit deny in any policy (deny overrides allow). 6. For cross-account access, both the requesting account's IAM policy and the resource account's bucket policy must allow the action.
Key Differences Between Bucket Policies and IAM
Bucket policies are attached to the bucket and can grant access to principals in other AWS accounts (cross-account) or to anonymous users (public access). They can also set conditions based on request attributes.
IAM policies are attached to users, groups, or roles and control what actions those principals can perform on which resources. They cannot grant access to principals outside the account unless combined with a bucket policy that allows cross-account access.
Block Public Access Settings
To prevent accidental public exposure, S3 provides four block public access settings at the bucket and account level:
- BlockPublicAcls: Blocks public ACLs.
- IgnorePublicAcls: Ignores public ACLs (treats them as if they don't exist).
- BlockPublicPolicy: Blocks public bucket policies (policies that grant access to Principal: "*" or Principal: { "AWS": "*" }).
- RestrictPublicBuckets: Restricts access to only AWS services and authorized users within the account, even if a bucket policy allows public access.
These settings can be applied at the account level via the S3 console or the PutPublicAccessBlock API, and they override any more permissive policies. The exam often tests that enabling these settings can prevent data leaks even if a bucket policy is misconfigured.
Pre-Signed URLs
Pre-signed URLs allow temporary access to a specific S3 object. They are generated by signing a URL with the credentials of a user who has permission to access the object. The URL includes an expiration time (default 3600 seconds, max 604800 seconds for AWS Signature V4). Pre-signed URLs are commonly used to allow users to upload or download objects without giving them permanent credentials. The exam tests that pre-signed URLs are generated using the AWS SDK or CLI, and that the expiration time can be set.
Logging and Monitoring
AWS CloudTrail: Records S3 API calls (e.g., PutObject, GetObject, DeleteBucket) for auditing.
S3 Server Access Logs: Detailed logs of requests made to a bucket, including requester, bucket name, request time, action, and response status. These logs are stored in another S3 bucket.
AWS Config: Can monitor bucket policies for changes and evaluate compliance with rules (e.g., whether encryption is enabled).
The exam may ask you to choose the appropriate logging mechanism for compliance or security analysis.
Authenticate the Request
When an S3 request arrives, AWS first determines if the request is anonymous or authenticated. For authenticated requests, the signature (AWS Signature V4) is verified using the access key ID and secret access key of the IAM user or role. If the signature is invalid, the request is denied with a 403 Forbidden error. This step ensures that only legitimate AWS credentials can initiate the request.
Evaluate Identity-Based Policies
If the request is authenticated, AWS evaluates the IAM policies attached to the principal (user, group, or role). These policies specify what actions the principal is allowed or denied on which resources. If the principal has an explicit deny for the requested action, the request is denied immediately (deny overrides allow). If there is no explicit allow, the default is deny. This step is performed for all authenticated requests.
Evaluate Resource-Based Policies
Next, AWS evaluates the bucket policy attached to the target S3 bucket. The bucket policy may grant or deny access to the principal (including cross-account or anonymous principals). If the bucket policy contains an explicit deny for the request, it is denied. If it contains an explicit allow, access is granted (provided no other policy denies it). For cross-account access, the bucket policy must explicitly allow the principal from the other account; otherwise, access is denied.
Evaluate ACLs (If Enabled)
If the bucket has ACLs enabled, AWS evaluates the ACLs at the bucket and object level. ACLs can grant permissions to specific AWS accounts or predefined groups. However, if BlockPublicAcls or IgnorePublicAcls is enabled, public ACLs are blocked or ignored. Note that ACLs are considered a legacy mechanism; by default, new buckets have ACLs disabled. The exam tests that ACLs are evaluated after bucket policies but are often overridden by block public access settings.
Combine and Apply the Decision
AWS combines the results from the previous steps. The default is deny. An explicit allow from any policy (IAM, bucket policy, or ACL) will grant access, unless an explicit deny exists in any policy (deny always wins). For cross-account requests, both the IAM policy of the requesting account and the bucket policy of the resource account must allow the action. If the request is allowed, the operation proceeds; otherwise, a 403 Forbidden error is returned.
Enterprise Scenario 1: Compliance with Encryption and Access Controls
A financial services company must store sensitive customer data in S3 with strict compliance requirements (e.g., PCI-DSS). They use SSE-KMS with a customer managed key to encrypt all objects at rest. To enforce encryption in transit, they attach a bucket policy that denies requests without aws:SecureTransport=true. They also enable S3 Block Public Access at the account level to prevent any accidental public exposure. Access is granted only to specific IAM roles used by applications, and cross-account access is not allowed. CloudTrail is enabled to log all API calls, and S3 server access logs are sent to a separate bucket for analysis. The company uses AWS Config to monitor bucket policies for any changes that might weaken security. A common misconfiguration is forgetting to set the x-amz-server-side-encryption header when uploading objects, which results in objects stored without encryption. To enforce encryption, they add a bucket policy that denies s3:PutObject if the header is missing or set to an incorrect value.
Enterprise Scenario 2: Cross-Account Data Sharing with Pre-Signed URLs
A media company uses S3 to store raw video footage. They need to allow external editors to download files temporarily. They generate pre-signed URLs using an IAM role that has read access to the bucket. The URLs are set to expire after 24 hours. The company also uses bucket policies to restrict access to only the specific IAM role that generates the pre-signed URLs, preventing any other access. They do not enable ACLs. A common issue is that the pre-signed URL expiration time is set too long, increasing the risk of unauthorized access if the URL is leaked. The exam tests that pre-signed URLs inherit the permissions of the IAM user who generated them, so that user must have the necessary S3 permissions.
Enterprise Scenario 3: Static Website Hosting with Public Access
A startup hosts a static website on S3. They need to allow public read access to all objects in the bucket. They attach a bucket policy that grants s3:GetObject to Principal: "*". They also enable static website hosting and configure the bucket for public access. However, they must ensure that the block public access settings are not enabled (or are configured to allow public bucket policies). A frequent mistake is enabling block public access at the account level, which overrides the bucket policy and causes the website to return 403 errors. The exam tests that for public access, you must explicitly allow it in the bucket policy and ensure block public access settings are not blocking it.
SAA-C03 Exam Focus: S3 Security
The SAA-C03 exam tests S3 security under Domain 1: Secure Architectures (Objective 1.5: Design secure access to AWS resources). Specific topics include: - Bucket Policies vs. IAM Policies: Know when to use each. Bucket policies are for resource-based control (including cross-account and public access). IAM policies are for identity-based control within your account. - Encryption Options: Be able to choose between SSE-S3, SSE-KMS, SSE-C, and client-side encryption based on requirements like key control, auditability, and performance. SSE-KMS is often the correct answer when you need separate permissions for key usage and auditing. - Block Public Access: Understand the four settings and that account-level settings override bucket-level settings. If a question says "a bucket is publicly accessible despite a bucket policy," check if block public access is disabled. - Pre-Signed URLs: Know that they grant temporary access based on the signer's permissions, and the expiration time can be set up to 7 days (604800 seconds) for Signature V4. - Cross-Account Access: Requires both the requesting account's IAM policy and the resource account's bucket policy to allow the action. ACLs can also be used but are legacy.
Common Wrong Answers and Traps
"Use ACLs for all access control": Candidates often choose ACLs because they are familiar from on-premises systems. However, the recommended approach is bucket policies and IAM. ACLs are legacy and less flexible; they are only needed for specific legacy scenarios.
"SSE-S3 provides the most control": SSE-S3 is the simplest but offers no key control or auditability. SSE-KMS is the answer when you need key rotation policies, separate permissions, or auditing.
"A bucket policy with a Deny effect overrides everything": While deny does override allow, the evaluation logic considers both IAM and bucket policies. An explicit deny in either will deny access, but an allow in both is required for cross-account access.
"Pre-signed URLs grant access to any object": Pre-signed URLs are object-specific and inherit the permissions of the signing user. They do not grant access to objects the signer cannot access.
Exam Numbers and Values
Default pre-signed URL expiration: 3600 seconds (1 hour). Maximum: 604800 seconds (7 days) for Signature V4.
Block Public Access settings: 4 settings (BlockPublicAcls, IgnorePublicAcls, BlockPublicPolicy, RestrictPublicBuckets).
Encryption headers: x-amz-server-side-encryption with values AES256 (SSE-S3), aws:kms (SSE-KMS), and customer-provided key headers for SSE-C.
Condition key for encryption in transit: aws:SecureTransport with Bool condition.
Cross-account access: Requires both IAM and bucket policy allows.
Edge Cases
If a bucket policy allows public access but block public access is enabled at the account level, the block overrides and public access is denied.
If you use SSE-KMS, you must also grant the KMS key permissions to the principal performing the upload/download via the KMS key policy.
ACLs can be used to grant access to a specific object to a different AWS account, but bucket policies are preferred.
Bucket policies are resource-based and can grant cross-account and public access; IAM policies are identity-based and grant access within the same account.
SSE-KMS provides the most control over encryption keys and is auditable via CloudTrail.
Block Public Access settings at the account level override bucket-level settings and can prevent public exposure even if a bucket policy allows it.
Pre-signed URLs inherit the permissions of the signing IAM user and have a maximum expiration of 7 days (604800 seconds).
To enforce encryption in transit, use a bucket policy with a Deny effect on `aws:SecureTransport` equal to false.
Cross-account access requires both the requesting account's IAM policy and the resource account's bucket policy to allow the action.
ACLs are legacy and disabled by default; use bucket policies and IAM instead.
These come up on the exam all the time. Here's how to tell them apart.
Bucket Policies
Resource-based policy attached to the S3 bucket.
Can grant access to principals in other AWS accounts (cross-account).
Can grant anonymous (public) access.
Supports conditions like IP address, source VPC, etc.
Evaluated after IAM policies; explicit deny overrides.
IAM Policies
Identity-based policy attached to IAM users, groups, or roles.
Can only grant access to resources within the same account (unless combined with bucket policy).
Cannot grant anonymous access.
Supports conditions but not S3-specific ones like `s3:x-amz-acl`.
Evaluated before bucket policies; explicit deny overrides.
SSE-S3
Amazon S3 manages encryption keys.
No additional cost for key management.
No ability to control key rotation or access.
No audit trail of key usage.
Simple to enable by setting header to `AES256`.
SSE-KMS
AWS KMS manages encryption keys with customer control.
Additional cost for KMS key usage.
Can create customer managed keys with custom key policies.
Provides audit trail via CloudTrail for key usage.
Requires KMS key permissions for upload/download.
Mistake
Bucket policies are the only way to control access to S3 objects.
Correct
Access can also be controlled via IAM policies, ACLs, and pre-signed URLs. Bucket policies are resource-based, while IAM policies are identity-based.
Mistake
SSE-S3 encryption is the most secure option because it uses 256-bit encryption.
Correct
All server-side encryption options use AES-256. SSE-KMS provides additional security features like separate permissions, key rotation, and audit trails.
Mistake
Block public access settings only apply to the bucket they are configured on.
Correct
Block public access can be set at the account level, which applies to all current and future buckets in the account.
Mistake
Pre-signed URLs can be generated for any object even if the generating user does not have access to that object.
Correct
Pre-signed URLs inherit the permissions of the generating user. If the user does not have `s3:GetObject` permission on the object, the pre-signed URL will fail.
Mistake
ACLs are the recommended way to grant cross-account access.
Correct
Bucket policies are the recommended method for cross-account access. ACLs are legacy and should only be used when necessary.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
A bucket policy is a resource-based policy attached to an S3 bucket that defines who can access the bucket and its objects. It can grant access to principals in other AWS accounts or to anonymous users. An IAM policy is an identity-based policy attached to IAM users, groups, or roles that defines what actions those principals can perform on which resources. IAM policies cannot grant access to principals outside the account unless combined with a bucket policy. The exam tests that bucket policies are used for cross-account and public access, while IAM policies are for fine-grained control within your account.
You can enforce encryption at rest by using a bucket policy that denies `s3:PutObject` if the `x-amz-server-side-encryption` header is missing or set to an incorrect value. For example, to require SSE-S3, you would deny `s3:PutObject` unless the header equals `AES256`. Alternatively, you can enable default encryption on the bucket, which automatically applies encryption to any object uploaded without an encryption header. The exam tests that default encryption is a bucket-level setting, while bucket policies can enforce encryption on a per-request basis.
Yes, you can use ACLs to grant public read access to a specific object by adding a grant for `AllUsers` with `READ` permission. However, this is not recommended because ACLs are legacy and less secure. The modern approach is to use a bucket policy that grants `s3:GetObject` to `Principal: "*"` for the specific object ARN. Additionally, you must ensure that block public access settings are not blocking public ACLs or policies. The exam tests that ACLs are still functional but discouraged.
S3 Block Public Access provides four settings that can be applied at the bucket or account level to prevent public access to S3 buckets and objects. The settings are: BlockPublicAcls, IgnorePublicAcls, BlockPublicPolicy, and RestrictPublicBuckets. These settings act as an additional layer of security, overriding any bucket policies or ACLs that would grant public access. They are commonly used to prevent accidental data leaks. The exam tests that account-level settings apply to all buckets in the account, and that they can block public access even if a bucket policy allows it.
A pre-signed URL is a URL that grants temporary access to a specific S3 object. It is generated by signing the URL with the credentials of an IAM user who has permission to access the object. The URL includes an expiration time (default 3600 seconds, max 604800 seconds for Signature V4). When someone uses the URL, S3 verifies the signature and checks that the signer's permissions have not changed. If the signer had `s3:GetObject` permission at the time of signing, the URL allows download. The exam tests that pre-signed URLs inherit the permissions of the signer and that the expiration time can be set.
Server-side encryption (SSE) encrypts data at rest after it is received by S3. AWS manages the encryption process, and you can choose between S3-managed keys (SSE-S3), AWS KMS-managed keys (SSE-KMS), or customer-provided keys (SSE-C). Client-side encryption encrypts data before it is sent to S3, so AWS never sees the plaintext. You manage the encryption keys and process. The exam tests that client-side encryption is used when you want full control over encryption keys and do not want AWS to have access to plaintext.
Yes, you can use a condition in the bucket policy with the `aws:SourceIp` condition key to allow or deny access based on the requester's IP address. For example, you can deny all access except from a specific IP range. The condition uses CIDR notation. This is commonly used to restrict access to a corporate network. The exam tests that `aws:SourceIp` works with bucket policies and IAM policies.
You've just covered S3 Security: Bucket Policies, ACLs, Encryption — now see how well it sticks with free SAA-C03 practice questions. Full explanations included, no account needed.
Done with this chapter?