DEV Community

Jonathan Vogel for AWS

Posted on • Originally published at builder.aws.com

Access Denied: What Every AWS Beginner Gets Wrong About IAM

The IAM mental model I wish someone had drawn on a whiteboard for me when I was starting out with AWS.

If you want a video to follow along with this blog, you can find it on the AWS Developers Youtube Channel

I spun up a Lambda function and tried to have it read from an S3 bucket only to get Access Denied.

This wasn't a typo or misconfiguration. I just straight up didn't understand IAM. So I did what every beginner does, I attached AdministratorAccess, the error went away, and I moved on.

What I didn't think about at the time is that I'd just given that Lambda function permission to do anything in my account. Delete databases. Create resources that cost money. Access data across every service it had no business touching. All because it needed to read from one S3 bucket.

I talk to students and developers getting started with AWS all the time, and this is the pattern. Everything goes smooth when you follow the tutorial. When it comes to implementing your own project, you run into a permission blocker. You come up with an easy solution. You slap on AdministratorAccess and now you have a security problem you don't even know about. The Access Denied error was actually trying to help you. It was telling you exactly which permission was missing. You just didn't know how to read it yet.

This post is the mental model I wish I'd had. Once you understand what I'm about to lay out, Access Denied stops being a wall and starts being a useful message.

What IAM Actually Is

IAM stands for Identity and Access Management. Not sure if that name really helps you, let me put it differently.

IAM is the bouncer at the door of every AWS service. Every time anything happens in your account, whether you click a button in the console, your code calls an API, or a Lambda function tries to read from a database, IAM checks two things.

  1. Who are you?
  2. Are you allowed to do this?

If the answer to either question is "no," you get Access Denied. Those two questions are the entire foundation. The rest of this post is about how they get answered.

Users, Roles and Policies

Three concepts make up the whole model when you're getting started.

IAM Users = Employee Badge

An IAM user is a persistent identity. It represents a person who needs to log into the console or use the CLI. It has long-term credentials, a username and password for the console, or access keys for programmatic access.

Think of it like an employee badge. It's yours, it has your name on it, and it works every day until someone revokes it.

IAM Roles = Visitor Pass

An IAM role is temporary. It doesn't belong to anyone permanently. Instead, it gets assumed (borrowed) by whoever needs it at that moment. AWS gives the assumer temporary credentials that expire automatically.

Think of it like a visitor pass at an office. You check in, you get a badge, it works for a few hours, then it stops working.

Rule of thumb. If it's a person logging in, that's a user. If it's a service doing something, a Lambda function, an EC2 instance, another AWS account, that's a role. Roles are how Lambda functions access S3, how EC2 instances talk to DynamoDB and how one AWS account talks to another. The credentials are always short-lived, so there's nothing sitting around that could be stolen.

Policies = Permission Slip

A policy is a JSON document that says "this identity is allowed to do these actions on these resources." You attach policies to users or roles. Without a policy attached, an IAM identity can do nothing. You have to explicitly grant every single permission.

A simple policy looks like this:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

This says: allow reading objects from one specific S3 bucket. Nothing else.

The Mental Model

A user or role is who you are. A policy is what you're allowed to do. Identity plus permission. That's the whole thing.

The Least Privilege Principle

This is the one concept that makes everything in IAM make sense. It applies across all of computer security, not just cloud.

Least privilege means: give every identity only the permissions it needs to do its job. Nothing more.

You already saw the wrong version in my story. I gave a Lambda function permission to do everything because it needed to do one thing. AdministratorAccess makes the error go away, but it also means anything in your account can do anything to your account.

That's like giving every employee in a company a key that opens every door because they needed to open one.

The right approach is to figure out exactly which actions your identity needs, on exactly which resources, and grant only that. That Lambda function I mentioned at the start? The policy it actually needed:

{
  "Effect": "Allow",
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::my-bucket/*"
}
Enter fullscreen mode Exit fullscreen mode

One action. One bucket. If that function ever gets compromised, the damage is limited to reading objects from one bucket, not your entire account.

Screenshot of AdministratorAccess policy vs scoped policy side by side

"But figuring out exact permissions sounds like a lot of work." It can take some extra minutes upfront. AWS gives you a tool called IAM Access Analyzer that looks at what your identity actually used over a period of time and generates a scoped policy based on real activity. You let your service run, then Access Analyzer tells you what it actually needed. You don't have to guess.

Your IAM Starter Checklist

I share this with every student setting up a new AWS account. Bookmark it and come back at the end of every project.

1. Lock down your root user

When you first create an AWS account, you start as the root user. Root can do anything, including things no other identity can do, like closing the account entirely. It's the "break glass in case of emergency" identity.

Enable MFA on root immediately. That's multi-factor authentication, so even if someone gets your password, they still can't log in without your second factor. Then stop using root for daily development.

2. Set up daily access

For day-to-day work, create a separate identity. If you're learning on a personal account, an IAM user with MFA works fine. If you're working with a team or thinking about production, IAM Identity Center is the current best practice. It gives you temporary credentials and scales well when you add team members.

3. Use roles for services

When you build things, Lambda functions, EC2 instances, anything running code, use roles. They don't need long-lived access keys. They need roles with temporary credentials.

4. Start with managed policies, then tighten

AWS has pre-built managed policies for common use cases. They're a reasonable starting point when you're learning. As you understand what your application actually needs, narrow the permissions down. You don't have to write perfect policies on day one, but you should be moving toward least privilege over time.

5. Never put access keys in your code

Putting keys directly in source code is a bad idea. They should never be in config files or any variable pushed to Git. Use roles instead. If you ever accidentally push AWS keys to a public repo, rotate them immediately. Bots scan for exposed keys within minutes.

Quick Reference

Step What to Do Why
Lock down root Enable MFA, stop using root daily Root = key that opens all doors
Set up daily access IAM user (learning) or Identity Center (teams) Limits root exposure
Use roles for services Lambda, EC2 get roles, not users Temporary credentials, nothing to steal
Start managed, then tighten Use AWS managed policies first Don't guess permissions on day one
No keys in code Use roles, not hardcoded credentials Bots scan for exposed keys within minutes

What I Tell Students Who Are Afraid of IAM

Every time someone tells me "I just attach AdministratorAccess because IAM is confusing," I tell them the same thing. The confusion comes from not having the mental model. Now you have it.

Users are people. Roles are services. Policies define what any of them can do. Least privilege means only what you need, nothing more. And Access Denied is IAM telling you exactly which permission is missing. Read the error. It's trying to help you.

Next time you get Access Denied, and you will, don't reach for AdministratorAccess. Check the policy. You've got this.


The best time to learn IAM was when you created your AWS account. The second best time is right now.

Click here for more info on AWS Free Tier.

Top comments (0)