READMEFEED GUIDES

EC2 can’t read S3? Check the caller, role, and policy path

An EC2 instance role is only part of the S3 authorization path. Identify the real caller, distinguish bucket and object permissions, and trace explicit denies.

You attached an IAM role to an EC2 instance, but the application still gets AccessDenied from S3. Adding more permissions before checking the caller often creates a larger role without fixing the failure. Start with the identity the application actually uses, then inspect the specific API operation and every policy boundary that can affect it.

This is a documentation-based troubleshooting workflow for applications on EC2. It does not assume that your application, the AWS CLI, and an interactive shell automatically select the same credential source.

1. Identify the actual caller

From the same execution context as the application, inspect the identity used by the AWS CLI:

aws sts get-caller-identity
aws configure list

The first command returns the account and ARN of the caller; it does not reveal secret access keys. The second helps identify the CLI’s active configuration source. Review the output privately, and redact account identifiers before posting it publicly. If the ARN belongs to a user or an unexpected assumed role, examine environment variables, profiles, and credentials configured by the application.

The CLI has documented configuration precedence, while an SDK’s credential-provider chain depends on the language and configuration. A working CLI command therefore narrows the problem but does not prove the running application uses the same identity. Service managers, containers, and scheduled jobs can have different environments.

2. Separate the role from the instance profile

EC2 exposes temporary role credentials through an instance profile associated with the instance. AWS’s console can create the profile as part of the role workflow; API and CLI workflows can require you to create and associate it explicitly. Confirm the instance profile contains the intended role and that its association is with the instance that runs the failing workload.

The role’s trust policy controls who can assume it. Its permissions policies control what the resulting session can do. These solve different parts of the path. A role that trusts EC2 still needs appropriate S3 permissions; an S3 policy does not make an unattached role available to an instance.

Use the supported SDK credential chain and temporary role credentials. Avoid copying a permanent access key onto the server as a workaround. Also distinguish an EC2 host role from an ECS task role if containers are scheduled by ECS: the task should have its own intended application permissions.

3. Match the S3 operation to its resource

List and read operations do not use the same resource ARN. Listing a bucket typically needs s3:ListBucket on the bucket; reading an object needs s3:GetObject on the object or intended prefix. A prefix-scoped policy can allow one object path and reject another.

What the application does Permission to inspect Resource shape
Lists objects s3:ListBucket arn:aws:s3:::example-bucket
Reads an object s3:GetObject arn:aws:s3:::example-bucket/approved-prefix/*
Reads an SSE-KMS object S3 read plus applicable KMS access The object and the relevant KMS key policy path

Use a known test object and the exact operation that fails. An application may list a prefix before reading a file, or inspect metadata as part of a library call. A successful action against a different object is not a complete test.

4. Look beyond the role’s allow statement

An explicit deny can override an allow. Relevant controls can include the bucket policy, service control policies, permissions boundaries, session policies, and VPC endpoint policies. Cross-account access adds another policy relationship; encrypted objects may also require a compatible KMS key policy and decryption permission. Conditions based on a source endpoint, principal, transport, or prefix can make a policy work in one environment and fail in another.

S3’s enhanced access-denied messages can help identify the denying policy type in supported scenarios, but they do not cover every case. Preserve the request ID and timestamp, and examine the applicable CloudTrail events where logging is enabled. Do not make a bucket public to determine whether the application’s identity is configured correctly.

5. Change one boundary, then retest the same request

Write down the caller ARN, operation, bucket, object prefix, encryption type, network path, and error before changing anything. Make the smallest policy correction supported by that evidence, then rerun the same request from the application’s context. Keep a rollback of the previous policy and avoid broad wildcard grants.

For help in the AWS forum, describe the runtime, whether credentials come from an instance profile or another source, the failing API action, and sanitized policy conditions. Keep credentials and customer object names out of the question.

Sources and review

Reviewed on 11 September 2026. The examples illustrate an investigation and were not executed against a sample AWS account for this article.

Working through a similar problem?

Share your environment and what you tried. The community can help you find the next step.

Ask a follow-up question →