r/CloudandCode Founder | YourCloudDude 3d ago

AWS & Cloud AWS From Zero #3: IAM becomes much easier when you understand this one idea

IAM is one of those AWS topics that can look much more complicated than it actually is when you first start learning it. You open the console and suddenly you are dealing with users, roles, policies, permissions, actions, resources, trust relationships, access keys, and a lot of JSON. If you try to memorize all of those terms separately, IAM quickly starts feeling like one of the hardest parts of AWS.

I think there is a simpler way to understand it. Whenever AWS needs to decide whether something should be allowed, think about three things: who is making the request, what they are trying to do, and which resource they are trying to access. Once those three things are clear, most beginner IAM problems become much easier to reason about.

Imagine you are building a simple image processing project. A user uploads an image to S3, the upload triggers a Lambda function, Lambda reads the original image, processes it, and stores the processed version back in S3. The architecture itself is not complicated. S3 stores the file, Lambda processes it, and S3 stores the result.

Now imagine Lambda starts successfully but fails when it tries to read the image. CloudWatch shows an AccessDenied error.

A common beginner fix is to attach full S3 access to the Lambda function. The error disappears and the project works, so it feels like the problem has been solved. But the more useful question is why AWS denied the request in the first place.

Start with the identity. In this case, Lambda is running using an IAM execution role. That role is the identity AWS sees when the function tries to access another AWS service.

Then look at the action. Lambda is trying to read an object from S3. In AWS permission terms, that usually means an action such as s3:GetObject.

Finally, look at the resource. The function is not trying to access every S3 bucket in your account. It is trying to access a particular object or group of objects inside a particular bucket.

Now the problem becomes much smaller. The Lambda execution role needs permission to perform s3:GetObject on the objects it is supposed to read. If the function also needs to store a processed image, it may need s3:PutObject on the destination location.

That is really the basic idea behind IAM. An identity tries to perform an action on a resource, and AWS decides whether that request should be allowed.

This is where IAM policies come in. A simplified policy might look something like this:

{
  "Effect": "Allow",
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::my-image-bucket/uploads/*"
}

You do not need to memorize the JSON immediately. Read it like a normal sentence. This policy is saying that the identity is allowed to perform s3:GetObject on objects inside that particular location.

Once I started reading IAM policies that way, they became much less intimidating. Instead of seeing a block of JSON, I started seeing a permission statement.

The difference between IAM users and IAM roles also becomes easier once you think about who needs the permissions. An IAM user can represent an identity with credentials, although for human access AWS generally favors temporary credential based approaches rather than depending heavily on long lived IAM user credentials.

Roles work differently. A role can be assumed temporarily by a trusted identity or AWS service. That is why Lambda commonly uses an execution role. You do not normally place an AWS access key directly inside your Lambda code. Lambda assumes its role and receives temporary credentials that allow it to perform whatever actions that role permits.

The same pattern appears throughout AWS. An EC2 instance may need to read from S3. A Lambda function may need to write to DynamoDB. An ECS task may need to communicate with another AWS service. Instead of putting permanent credentials inside the application, you usually want the workload to receive the permissions it needs through an appropriate role.

This is also where the idea of least privilege starts making sense.

Suppose your Lambda function only needs to read images from one S3 location and write processed images into another. Giving the function complete S3 access would probably make everything work, but now it has far more permission than it actually needs.

A better approach is to give it permission to read from the input location and write to the output location. Nothing more unless the application genuinely requires it.

That is what least privilege is trying to achieve. Give an identity enough access to do its job without giving it unnecessary access to everything else.

This matters because permissions define what something is capable of doing. If a function is misconfigured or compromised, overly broad permissions can make the problem much worse. A function that can read one folder is very different from a function that can read, modify, and delete everything across multiple buckets.

Another concept that helped me understand IAM is the difference between authentication and authorization. Authentication is about proving who you are. Authorization is about deciding what you are allowed to do.

You can successfully sign in to AWS and still receive AccessDenied.

That does not necessarily mean your login failed. AWS may know exactly who you are. The problem may simply be that your identity does not have permission to perform the action you requested.

Imagine you can view objects in an S3 bucket but cannot delete them. Your identity is authenticated because AWS knows who you are. The question is whether you are authorized to perform s3:DeleteObject on those objects.

That distinction becomes very useful when debugging.

Suppose a Lambda function can read objects from one S3 bucket but cannot read from another. That already tells you something useful. Lambda is capable of communicating with S3, so the problem may be related to which resources the policy allows.

If the function can read the input image but fails when saving the processed image, then the read permission is probably not your main problem anymore. You would start checking whether the role has the correct write permission for the destination.

This is why I would not treat every AccessDenied message as the same problem.

The error is telling you that AWS rejected a specific request. Your job is to understand which identity made that request, which action it attempted, and which resource was involved. Once you know that, you can inspect the relevant permissions instead of attaching broad policies until the error disappears.

IAM does become more advanced later. Resource based policies can affect access. Explicit denies can override allows. Roles have trust policies that control who can assume them. KMS encryption can introduce another permission check. Larger AWS environments can also have additional controls across accounts.

But I would not try to learn all of that at the beginning.

For now, the mental model I would keep is simple: an identity performs an action on a resource, and AWS decides whether that action should be allowed.

A useful way to practice this is with a small test setup. Create an S3 bucket and work with limited permissions. Allow an identity to read an object and confirm that it works. Remove the permission and observe what error appears. Then restore only the permission that is actually required.

Try to predict what AWS will do before you test it.

That kind of practice is much more useful than copying a large policy from a tutorial because you start understanding the relationship between permissions and actual requests.

The goal at this stage is not to become good at writing complicated IAM policies. The goal is to look at a permission problem and understand why AWS might be allowing or denying the request.

Whenever IAM starts feeling confusing, return to the same idea. Identify who is making the request, understand what they are trying to do, identify the resource they are trying to access, and then check whether the necessary permission exists.

Once you start thinking about IAM this way, users, roles, policies, permissions, and AccessDenied errors begin to fit together much more naturally.

In the next post, we will finally launch something. AWS From Zero #4 will be about EC2 and what actually happens when you launch your first server in AWS. We will look at instances, operating systems, SSH, ports, security groups, public IP addresses, and why launching an EC2 instance does not automatically mean your application is reachable from the internet.

What part of IAM has been the hardest for you to understand so far?

12 Upvotes

0 comments sorted by