An Amazon S3 PutObject 403 means AWS denied the specific write request. The fastest reliable fix is to trace the exact principal, bucket, object key, request headers, encryption mode, and network path, then check every policy layer that can allow or deny that request. In most cases, the missing permission is s3:PutObject on an object ARN rather than the bucket ARN, an explicit deny or condition is winning, or an optional feature such as ACLs, tags, SSE-KMS, or a VPC endpoint adds another authorization requirement.
What “Access Denied” means for PutObject
PutObject is an authorization decision, not a diagnosis of one particular problem. A request can have an identity policy that appears to allow S3 writes and still receive HTTP 403 because another applicable policy denies it or because the request includes a feature requiring an additional permission.
As an Amazon Associate I earn from qualifying purchases.
The decision is evaluated for one caller and one exact request. The caller might be an IAM user, an assumed-role session, an AWS service role, or a federated principal. The target is not merely a bucket: it includes the bucket, region, access point (if used), and complete object key, including every prefix. Headers for ACLs, object tags, and server-side encryption also affect the decision. Organization controls, permissions boundaries, session policies, endpoint policies, and network conditions can narrow an otherwise broad allow.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problems- A bucket ARN such as
arn:aws:s3:::example-bucketidentifies the bucket itself. - An object ARN such as
arn:aws:s3:::example-bucket/uploads/*identifies objects beneath a prefix. s3:PutObjectmust be allowed on the object ARN for the key being written; allowing only the bucket ARN does not authorize an object write.
Start with the smallest factual description of the failed call. Do not change several policies at once; doing so can hide the layer that actually caused the denial and often creates excessive permissions.
#1 Best Overall
1. Record the caller and the exact request
Before editing permissions, capture the values below from the application configuration, SDK logs, or the command that failed. An assumed role’s session ARN and account can differ from the human or workload that launched it.
- Principal: IAM user ARN, role ARN, or assumed-role session ARN, plus the AWS account that owns it.
- Target: AWS Region, bucket name, complete key (including prefix), and whether an S3 access point is involved.
- Request options: canned ACL, explicit tagging, server-side encryption headers, multipart upload, or a custom endpoint.
- Network path: public S3 endpoint, gateway or interface VPC endpoint, source VPC, and endpoint ID.
- Policy context: whether the bucket and caller are in the same account or organization, and whether a permissions boundary, session policy, SCP, or RCP applies.
For a CLI test, use the same credentials and region as the failing application. Environment variables keep the example reusable without placing credentials in a command line:
export AWS_PROFILE=the-profile-used-by-the-app
export AWS_REGION=the-bucket-region
export BUCKET=the-bucket-name
export KEY=the/exact/key.txt
printf 'permission proben' > /tmp/s3-probe.txt
aws s3api put-object --bucket "$BUCKET" --key "$KEY" --body /tmp/s3-probe.txt --region "$AWS_REGION"
If this minimal call succeeds while the application fails, compare the application’s additional headers and endpoint settings rather than broadening IAM access.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →2. Grant the baseline object permission
The caller needs s3:PutObject on the object resource that includes the key. A least-privilege identity policy for a prefix looks like this:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::BUCKET/PREFIX/*"
}]
}
Replace BUCKET and PREFIX with the real values. If the application writes to the bucket root, the resource can be arn:aws:s3:::BUCKET/*. If it writes several prefixes, list only those object ARNs or use separate statements. A resource ending at the bucket name is not a substitute for the object ARN.
Check the policy attached to the principal that actually made the call. A policy attached to a different user, role, or parent group does not help if the workload is using another assumed role. Also verify that the key is spelled exactly as authorized: S3 keys are case-sensitive, and a missing or extra prefix places the request outside the permitted resource.
3. Add permissions for features the request actually uses
ACL headers
If the client sends an ACL, such as x-amz-acl: bucket-owner-full-control, the caller also needs s3:PutObjectAcl for the same object. Remove the ACL header only as a diagnostic when the bucket’s ownership and policy permit a test without it; do not remove a required ownership control in production.
Rank #2
Object tags
If the request writes tags at upload time, add s3:PutObjectTagging on the object resource. A request that combines an otherwise valid upload with an unauthorized tag operation can fail even though s3:PutObject is allowed.
Multipart uploads
Multipart workflows perform several API calls rather than one. Check permissions for the complete sequence used by the client, and test a single-part upload separately. With SSE-KMS, completion and later reads can additionally require kms:Decrypt, as described below.
4. Inspect every policy layer for allows and explicit denies
An allow must survive all applicable policy boundaries. An explicit deny wins over an allow, and a condition that evaluates false means the statement does not authorize the request.
| Policy or control | What to inspect | Typical reason for a 403 |
|---|---|---|
| IAM identity policy | Action, object ARN, and conditions attached to the actual user or role | s3:PutObject targets only the bucket ARN or the wrong prefix |
| Bucket policy | Principal, resource, account, source network, TLS, and encryption conditions | An explicit deny or an allow restricted to a different role or account |
| Access-point policy | Access-point name, object path, and principal conditions | The request uses an access point whose policy is narrower than the bucket policy |
| Permissions boundary | Whether the boundary permits the S3 action and resource | The identity policy allows the write but the boundary caps it |
| Session policy | Policy passed when the role session was created | A federated session is narrower than the role’s attached policies |
| Organizations SCP or RCP | Organization-level denies and resource conditions | An account-level guardrail blocks S3 writes or the target Region |
| VPC endpoint policy | Allowed principals, actions, buckets, and prefixes | The endpoint denies the request before S3 can honor an identity allow |
| Block Public Access and ownership controls | Whether the request relies on public access or an ACL model disabled by the bucket | A public or ACL-based pattern conflicts with the bucket’s controls |
Search for statements with "Effect": "Deny" and conditions involving the principal ARN, account ID, object prefix, source VPC, VPC endpoint, aws:SecureTransport, encryption headers, or required tags. A deny that applies to every principal except a short allow-list will also affect an otherwise authorized role.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
5. Check the bucket and access-point policy
Resource policies are especially important for cross-account writes. A bucket policy can allow a role in another account to write only to a defined prefix:
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "AllowPartnerPrefixUpload",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::111122223333:role/UploadRole"},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::BUCKET/incoming/*"
}]
}
Adapt the account ID, role name, bucket, and prefix. If the caller sends an ACL, add s3:PutObjectAcl to the action list and make sure the ownership model supports that ACL. If the policy requires a particular encryption header, the client must send exactly that value; a missing or different header causes the condition to fail.
When an access point is used, inspect both the access-point policy and the underlying bucket policy. The ARN and request host differ from a direct bucket request, so a statement written only for the bucket path may not match the access-point request.
Rank #3
6. Resolve cross-account upload failures
For a cross-account upload, authorization commonly has two independent sides: the caller’s account must authorize the role session, and the bucket owner’s resource policy must trust that principal and resource. Confirm all of the following:
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minute- The caller is the intended role session, not a similarly named role in another account.
- The role’s identity policy allows
s3:PutObjecton the exact bucket-and-prefix object ARN. - The bucket policy names the correct role ARN and object resource.
- Any ACL requirement is satisfied with
s3:PutObjectAcl, or the bucket uses bucket-owner-enforced Object Ownership and the client does not send an incompatible ACL. - If SSE-KMS is used, the KMS key policy and caller IAM policy authorize the required KMS operations across both accounts.
- No SCP, RCP, permissions boundary, session policy, endpoint policy, or explicit deny blocks the request.
The AWS-managed aws/s3 KMS key cannot provide cross-account default encryption. A customer-managed KMS key with a policy that trusts the uploading principal is required for that topology.
7. Verify SSE-KMS permissions and encryption conditions
Server-side encryption with AWS KMS keys adds a second authorization system. For an SSE-KMS upload, the caller generally needs kms:GenerateDataKey. Multipart completion or later operations can also require kms:Decrypt. Both the caller’s IAM identity policy and the customer-managed KMS key policy must authorize the operation.
KMS actions cannot be granted through an S3 bucket policy. Add them to the caller’s IAM policy and authorize the principal in the key policy (or through a permitted KMS grant). Scope the permissions to the specific key where practical:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["kms:GenerateDataKey", "kms:Decrypt"],
"Resource": "arn:aws:kms:REGION:ACCOUNT:key/KEY-ID"
}]
}
Use the exact Region and key ARN. A bucket policy condition requiring s3:x-amz-server-side-encryption or s3:x-amz-server-side-encryption-aws-kms-key-id must match the headers sent by the SDK. Conversely, if the application sends an SSE-KMS header but the key policy does not trust its role, S3 can return AccessDenied even though the S3 action is allowed.
For cross-account encryption, grant the principal in the key policy owned by the key’s account and in the uploading role’s IAM policy. Check key state, Region, and grants as well as policy text. Do not “fix” a KMS denial by silently removing required encryption; that changes the bucket’s security control rather than repairing authorization.
8. Check Object Ownership and ACL behavior
With S3 Object Ownership set to Bucket owner enforced, ACLs are disabled. Requests that attempt to set an ACL other than the permitted bucket-owner-full-control behavior can fail because the bucket no longer accepts ACL management. Remove unnecessary ACL headers and rely on the ownership setting.
In an ACL-enabled cross-account configuration, the bucket owner may require the uploader to send the bucket-owner-full-control canned ACL. That request needs both the ACL header and s3:PutObjectAcl. The bucket policy must allow the principal and the object path, and the object owner result should match the intended access model.
Determine the ownership mode before changing permissions. Adding ACL permissions to a bucket-owner-enforced bucket does not solve an incompatible request; changing ownership mode solely to accommodate an old client can create a broader access-management burden.
Free tools Windows power users keep installed
One-click scans. No signup required.
9. Investigate network and organization controls
VPC endpoint policies
A gateway or interface VPC endpoint can impose its own allow-list. Inspect the endpoint policy for the S3 action, bucket ARN, object prefix, and principal. A restrictive endpoint policy can deny a request even when IAM and the bucket policy look correct. Compare the failing application’s route with the successful CLI test; they may use different endpoints.
Conditions on source and transport
Bucket and identity policies often require a particular source VPC, VPC endpoint, account, or secure transport. Verify the request context actually contains the expected values. A condition on aws:SourceVpce, for example, will not match traffic that leaves through a different endpoint or a public S3 path.
Organizations controls
Ask the organization administrator to inspect SCPs and resource control policies for denies affecting S3, KMS, the account, or Region. These controls are outside the bucket and role documents, so editing those documents cannot override an organization-level deny.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.10. Use the error message and CloudTrail to identify the denying layer
Same-account and same-organization requests may return enhanced AccessDenied text that identifies the policy type or ARN responsible. Read the complete error, including any named principal, condition, or policy. Cross-account requests outside the organization and directory-bucket requests may return only generic AccessDenied, so do not assume that a short message means IAM is the only suspect.
Recommended Free Tools
Correlate the request with CloudTrail data events for the bucket. Match event time, principal ARN, bucket, key, source IP or VPC endpoint, and encryption fields. Then inspect the bucket policy, access-point policy, endpoint policy, boundaries, session policy, SCP/RCP, and KMS key policy that applied at that time. CloudTrail confirms what was called and by whom; it does not replace reviewing every policy that can deny the call.
Best Value
11. Retest safely with the smallest request
- Use the exact failing principal, Region, bucket, and key prefix.
- Run a single-part
PutObjectwithout optional ACL and tag headers, only if the bucket policy allows such a test. - Keep required TLS, network, and encryption controls in place; do not disable them merely to obtain a success response.
- If the minimal request succeeds, add back one feature at a time: ACL, tags, SSE-KMS, multipart behavior, and finally the production endpoint.
- After the cause is found, narrow the policy to the required object prefix, principal, key, and conditions. Remove temporary broad allows and test credentials.
A successful probe proves only that that exact principal and request were authorized. It does not prove that every application role, prefix, Region, or encryption key is configured correctly.
Common failure patterns and their precise fixes
“I have s3:PutObject, but it still returns 403”
Inspect the resource in the statement first. If it ends at arn:aws:s3:::BUCKET, change it to the object ARN matching the key. Then search all policy layers for an explicit deny or a condition that excludes the request.
The upload works without encryption but fails with SSE-KMS
Keep the required encryption setting and authorize kms:GenerateDataKey in the caller’s IAM policy and KMS key policy. Add kms:Decrypt where the multipart or read path needs it, and verify the key ARN and Region.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →A cross-account uploader is denied
Validate the role ARN on both sides, the bucket policy’s object resource, and any ACL or ownership requirement. Then check the customer-managed KMS key policy and organization or endpoint controls. The AWS-managed aws/s3 key is not a cross-account solution for default encryption.
The application fails but a basic CLI command works
Compare headers and transport. The application may add an ACL, tags, SSE-KMS, multipart calls, or a VPC endpoint that the CLI probe did not use. Grant only the additional action required by that feature.
The error names no policy
Generic text is expected for some cross-account and directory-bucket requests. Use CloudTrail and review every applicable layer rather than relying on the message to identify the deny.
Quick Recap
Final least-privilege checklist
- Principal ARN and account are confirmed from the failing request.
s3:PutObjecttargets the exact object ARN and prefix.s3:PutObjectAclis present only when an ACL is sent and supported.s3:PutObjectTaggingis present only when upload-time tags are written.- Bucket or access-point policy trusts the correct principal and key path.
- No explicit deny or unmet condition exists in IAM, resource, endpoint, boundary, session, SCP/RCP, or Block Public Access controls.
- SSE-KMS requests have the required KMS permissions in both IAM and the customer-managed key policy.
- Object Ownership and ACL behavior match the client’s headers and cross-account design.
- The final test uses the production principal, network path, encryption, and request shape.
If you prefer an automated Windows maintenance shortcut while investigating local tooling or environment issues, Outbyte PC Repair can check common system problems, tune resource-heavy settings, clean temporary and cache files, and provide crash logs. It complements antivirus software rather than replacing it; results vary and no tool repairs every crash. It runs on Windows 11, 10, 8, and 7, with a category-limited free trial of at least two days before a subscription.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

