Manoj
←Back to Blog
·4 min read

IAM Roles and Policies: Understanding Who Can Access What

Understand IAM roles, trust policies, and permission policies through a practical file-upload service example.

awsiamsecuritybackend

IAM Roles and Policies: Understanding Who Can Access What

An access-denied error often sends developers straight to the permissions editor. Adding a broader policy can make the error disappear, but it also makes the system harder to explain.

Before changing permissions, describe the request in one sentence: this identity needs to perform this action on this resource for this reason. That sentence is a useful starting point for both granting access and debugging it.

Separate identity from permission

A role represents an identity that can be assumed. A policy describes permissions or other rules associated with access. They answer related questions, but they are not interchangeable.

For an upload service, the role is the identity used by the running workload. Its permission policy might allow writing objects to one bucket prefix. The application's users do not need to receive the role's credentials just because the service uses that role.

AWS recommends temporary credentials for workloads through roles where possible. Its IAM security guidance explains the broader credential and least-privilege recommendations.

Ask who can assume the role

A role's trust policy controls who can assume it. Its permission policies control what an assumed session can do. Granting S3 access does not, by itself, establish who may use the role.

Treat these as separate review steps. First identify the workload or trusted principal. Then identify the resources it needs. For cross-account access, review both sides of the arrangement rather than assuming one policy completes the configuration.

A helpful design note might look like this:

Role: upload-api
Trusted workload: the application's compute service
Required action: write an uploaded object
Required location: project-upload-bucket/incoming/*
Not required: read every bucket or delete existing objects

That note is not an IAM policy, but it makes the eventual policy easier to review.

Scope a permission to the actual operation

Here is an illustrative identity-based policy for object writes. Replace the bucket name with a resource you control before using it.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::project-upload-bucket/incoming/*"
    }
  ]
}

This deliberately says nothing about listing buckets, downloading objects, or deleting them. Those are different operations and should be justified separately. Encryption settings and other service requirements may introduce additional permissions, so test against the actual bucket configuration.

The important habit is to connect each action to a feature. If nobody can explain why a permission exists, it deserves another look.

An allow is not the entire decision

AWS evaluates the policies relevant to a request. Identity policies, resource policies, organizational controls, and permissions boundaries can affect the outcome, depending on the context. An applicable explicit deny overrides an allow. See the policy evaluation documentation.

That is why repeatedly attaching more allow statements may not solve a denial. You need to locate the constraint instead of guessing around it.

For debugging, capture the caller identity, requested action, resource ARN, account, and exact error. Verify you are testing the same role the application uses. Local credentials and deployed credentials can represent different identities even when the application code is identical.

Test the boundary, not just the happy path

A successful upload proves that one allowed operation works. It does not prove the role is appropriately limited.

In a safe test environment, also check operations that should fail: writing outside the intended prefix, deleting an object, or accessing another project's bucket. Keep these checks tied to the intended behavior so that future permission changes have something concrete to preserve.

Avoid making emergency wildcard permissions permanent. If a temporary diagnostic change is necessary, record the reason and remove it promptly after identifying the missing permission.

Review permissions when the application changes

Old capabilities often leave old permissions behind. A feature might stop downloading files while the role keeps read access for years.

Review the policy alongside the feature, the infrastructure, and the credentials used to deploy it. Small, understandable roles are easier to audit than a shared identity that powers unrelated services. The goal is a clear access story: who acts, what they can do, and why that access still belongs there.