DEV Community

Cover image for IAM Permissions I Got Wrong (And What I Learned)
Sahinur
Sahinur

Posted on

IAM Permissions I Got Wrong (And What I Learned)

IAM is one of those AWS services that looks simple at first.

Create a user or role, attach a policy, give it access, and move on.

Then one day you deploy an application and see:

AccessDenied
Enter fullscreen mode Exit fullscreen mode

And suddenly you're asking:

Which permission is missing?

Working with AWS has taught me that IAM isn't just about making something work.

It's about giving the application exactly the permissions it needs—and nothing more.

Here are some of the lessons I've learned.

Mistake 1: Using * just to get it working

One of the easiest ways to solve an AWS permission problem is to make the policy extremely broad.

For example:

{
  "Effect": "Allow",
  "Action": "*",
  "Resource": "*"
}
Enter fullscreen mode Exit fullscreen mode

Technically, this can make many permission errors disappear.

But it creates a much bigger security problem.

The application now has permission to perform actions it may never need.

For example, if a backend only needs to upload objects to one S3 bucket, it shouldn't automatically have permission to:

Delete buckets
Create IAM users
Modify EC2 instances
Read unrelated databases
Access every S3 bucket
Enter fullscreen mode Exit fullscreen mode

The better approach is to scope permissions to the actual requirement.

For example:

{
  "Effect": "Allow",
  "Action": [
    "s3:PutObject"
  ],
  "Resource": "arn:aws:s3:::my-app-uploads/*"
}
Enter fullscreen mode Exit fullscreen mode

Now the role has a much smaller permission boundary.

The lesson is simple:

Don't use broad permissions as the permanent solution to a permission error.

Mistake 2: Confusing users and roles

Another important concept is understanding when to use an IAM user and when to use an IAM role.

For applications running on AWS, I prefer the application to assume a role rather than embedding long-term AWS credentials inside the application.

For example:

EC2
  ↓
IAM Role
  ↓
AWS Services
Enter fullscreen mode Exit fullscreen mode

Instead of:

EC2
  ↓
AWS Access Key
  ↓
AWS Services
Enter fullscreen mode Exit fullscreen mode

The role-based approach allows AWS services to obtain temporary credentials without storing permanent access keys in the application.

This is especially important for workloads running on services such as EC2, Lambda, and ECS.

Mistake 3: Giving the wrong resource access

Another common IAM problem is getting the action right but the resource wrong.

For example, you may allow:

"Action": "s3:GetObject"
Enter fullscreen mode Exit fullscreen mode

but the resource doesn't match the actual object ARN.

A policy can look correct at first glance while still producing:

AccessDenied
Enter fullscreen mode Exit fullscreen mode

That's why debugging IAM requires checking both:

Action
+
Resource
Enter fullscreen mode Exit fullscreen mode

For S3, for example, bucket-level and object-level ARNs can be different depending on the operation.

Mistake 4: Forgetting that permissions can come from multiple places

IAM authorization isn't always as simple as looking at one policy.

When debugging access, I consider:

Identity-based policies
        +
Resource-based policies
        +
Permissions boundaries
        +
Session policies
        +
Service control policies
        +
Resource configuration
Enter fullscreen mode Exit fullscreen mode

This is one reason IAM errors can sometimes be confusing.

You might add an Allow policy and still receive AccessDenied.

An explicit Deny somewhere else can override an Allow.

So my debugging process starts with understanding where the permission decision is actually coming from.

How I approach an AccessDenied error

When an AWS operation fails, I don't immediately start adding more permissions.

I first identify:

1. Who is making the request?

Is it:

IAM User?
IAM Role?
EC2 Instance Role?
Lambda Execution Role?
ECS Task Role?
Enter fullscreen mode Exit fullscreen mode

2. What action is being attempted?

For example:

s3:GetObject
s3:PutObject
dynamodb:GetItem
secretsmanager:GetSecretValue
Enter fullscreen mode Exit fullscreen mode

3. Which resource is being accessed?

For example:

S3 bucket/object
DynamoDB table
Secrets Manager secret
Enter fullscreen mode Exit fullscreen mode

4. Which policy should allow the operation?

Then I check the relevant policy instead of randomly adding permissions.

This makes debugging much more systematic.

Least privilege

The principle I try to follow is:

Give the application the minimum permissions required to perform its job.

Imagine an API that only needs to upload user profile images.

Instead of:

S3: *
Enter fullscreen mode Exit fullscreen mode

I'd want something closer to:

s3:PutObject
       ↓
specific bucket
       ↓
specific path
Enter fullscreen mode Exit fullscreen mode

The same principle applies to other AWS services.

Instead of:

DynamoDB: *
Enter fullscreen mode Exit fullscreen mode

use the specific actions required by the application.

Instead of:

Secrets Manager: *
Enter fullscreen mode Exit fullscreen mode

allow access only to the secrets the application actually needs.

This reduces the potential impact if credentials or an application component are compromised.

Tools that help

AWS provides several tools that make IAM troubleshooting easier.

IAM Policy Simulator

The IAM Policy Simulator can help test whether a policy allows or denies specific actions.

Instead of repeatedly deploying an application just to test permissions, you can reason about the policy directly.

IAM Access Analyzer

Access Analyzer can help identify overly broad access and unintended external access.

It's particularly useful when reviewing policies and trying to move toward least-privilege permissions.

CloudTrail

When debugging AWS activity, CloudTrail can provide valuable information about API calls.

It helps answer questions such as:

Who made the request?

What AWS API was called?

When did it happen?

What resource was involved?
Enter fullscreen mode Exit fullscreen mode

That context can make an IAM problem much easier to understand.

A better IAM workflow

My preferred workflow looks like this:

Application needs AWS access
          ↓
Identify exact AWS action
          ↓
Identify exact resource
          ↓
Create minimum required policy
          ↓
Test
          ↓
Review permissions
          ↓
Monitor
Enter fullscreen mode Exit fullscreen mode

Not:

AccessDenied
    ↓
Add AdministratorAccess
    ↓
Problem solved
Enter fullscreen mode Exit fullscreen mode

The second approach may be faster for five minutes, but it's much harder to defend from a security perspective.

IAM checklist

Before considering an application role ready for production, I'd ask:

[ ] Does the application use an IAM role where appropriate?
[ ] Are long-term credentials avoided?
[ ] Are permissions limited to required actions?
[ ] Are resources scoped as narrowly as practical?
[ ] Have wildcard permissions been reviewed?
[ ] Have explicit denies been considered?
[ ] Have IAM Access Analyzer findings been reviewed?
[ ] Have policies been tested?
[ ] Are production and development permissions separated?
[ ] Are unused permissions removed?
Enter fullscreen mode Exit fullscreen mode

What I learned

The biggest lesson is that IAM isn't something you should solve by trial and error forever.

When I see:

AccessDenied
Enter fullscreen mode Exit fullscreen mode

I now try to understand the authorization path instead of immediately adding another policy.

The question isn't:

"How can I give this application more access?"

It's:

"What is the smallest amount of access this application actually needs?"

That mindset changes the way you design AWS infrastructure.

Final takeaway

IAM can feel frustrating when you're starting with AWS.

But once you stop treating permissions as random configuration and start thinking in terms of:

Principal
   ↓
Action
   ↓
Resource
   ↓
Policy
   ↓
Authorization
Enter fullscreen mode Exit fullscreen mode

the system becomes much easier to reason about.

And one of the most important AWS security habits I've learned is:

Make it work with the minimum permissions—not maximum permissions.

Top comments (0)