EduFlow
AWS Cloud Foundations
0%

Section 2 · Identity and Security

IAM Users, Groups, Roles and Policies

16 min4 min readChoose wisely

Lesson at a glance

Tell IAM users, groups and roles apart, know where identity-based and resource-based policies attach, and predict whether AWS allows a request using the deny-allow-deny rule.

  1. 1Anatomy of a request
  2. 2The identities
  3. 3Where policies live
  4. 4How IAM decides

No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.

At the end of section one you ran aws sts get-caller-identity and AWS answered. Behind that answer, and behind every other call, sits AWS Identity and Access Management (IAM). It answers one question billions of times a day: is this principal allowed to do this action on this resource, right now? Lantern’s old server had one answer for everything: whoever had the SSH key could do anything. This lesson gives you the vocabulary to do better.

Anatomy of a request

Every request to AWS, from the console, the CLI or code, carries four things:

  • Principal: who is asking. A user, a role session, or an AWS service.
  • Action: what they want, written service:Operation, such as s3:GetObject or dynamodb:PutItem.
  • Resource: what they want it on, identified by an ARN (Amazon Resource Name).
  • Context: everything else IAM can see, such as the source IP address, the time, whether MFA was used, or whether the request used TLS.

ARNs follow the pattern arn:partition:service:region:account-id:resource. Some parts are empty when they don’t apply:

Text
arn:aws:iam::111122223333:user/amara
arn:aws:s3:::lantern-posters/2026/street-food-festival.jpg
arn:aws:dynamodb:eu-west-1:111122223333:table/lantern-rsvps

IAM is global, so the user ARN has no Region. S3 bucket names are unique across all of AWS, so an S3 ARN has neither Region nor account. DynamoDB tables are regional and belong to an account, so their ARN has both. You will write ARNs constantly in the next lesson.

The identities

Users are long-term identities for one person or, in older setups, one application. A user can have a console password and up to two access keys. Users are the oldest part of IAM, and in section one you created exactly one, your admin.

Groups are collections of users. You attach policies to a group, and every member gets them. Lantern creates Admins, Developers and Billing, so that when a volunteer joins or leaves, you change one membership instead of hunting through individual permissions. Groups are not principals: you can’t sign in as a group or name one in a bucket policy.

Roles are identities with permissions but no long-term credentials. A trusted principal assumes a role, and AWS Security Token Service (STS) hands back temporary credentials that expire. A role’s trust policy says who may assume it: a Lambda function, an EC2 instance, a user in another account, or people signed in through IAM Identity Center. Roles are how code gets permissions without secrets, and lesson three of this section builds on them.

Terminal
aws iam create-group --group-name Developers
aws iam attach-group-policy --group-name Developers \
  --policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess
aws iam add-user-to-group --group-name Developers --user-name sam

Where policies live

A policy is a JSON document of statements that allow or deny actions on resources. Where it is attached changes how it reads:

  • Identity-based policies attach to a user, group or role and describe what that identity may do. They come as AWS managed policies (like ReadOnlyAccess), customer managed policies you write and reuse, or inline policies embedded in a single identity.
  • Resource-based policies attach to a resource and name the principal they apply to. An S3 bucket policy, a Lambda function’s resource policy and a role’s trust policy are all resource-based.

Within one account, a request is allowed if either kind of policy allows it and nothing denies it. Across accounts, both sides must allow it.

How IAM decides

The evaluation rule fits on an index card, and it explains nearly every AccessDenied error you will ever see.

Flowchart. A request first checks for any explicit deny; if found the result is deny. Otherwise it checks for any allow; if found the result is allow, otherwise the result is an implicit deny. Request Explicit Deny anywhere? yes Denied no Any Allow matches? yes Allowed no Implicitly denied
Explicit deny wins, then any allow, otherwise the default deny
  1. Default deny. Every request starts denied.
  2. Explicit deny wins. If any applicable policy has a matching Deny, the answer is no. Nothing can override it.
  3. Explicit allow permits. Otherwise, if a policy has a matching Allow, the answer is yes.
  4. No match means no. If nothing allowed it, the default deny stands. This is called an implicit deny.

Larger setups add further layers that can only narrow what is allowed, such as service control policies from AWS Organizations and permissions boundaries on individual users and roles. The rule above still holds; those layers add more places a deny can come from.

You can ask IAM to evaluate a request without making it:

Terminal
aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::111122223333:user/sam \
  --action-names s3:DeleteBucket \
  --resource-arns arn:aws:s3:::lantern-posters \
  --query "EvaluationResults[].EvalDecision"

The answer is allowed, explicitDeny or implicitDeny, which tells you not only whether but why.

You can now read who is asking and how the decision is made. Next you write the policies themselves, line by line.

Key takeaways

  • Every AWS request carries a principal, an action, a resource ARN and a context, and IAM evaluates all four before anything happens.
  • Users are long-term identities, groups are a way to give users the same policies, and roles are identities with no long-term credentials that trusted principals assume for temporary credentials.
  • Identity-based policies attach to users, groups and roles; resource-based policies, such as S3 bucket policies, attach to the resource and name a principal.
  • Everything is denied by default, an explicit allow is needed to permit a request, and an explicit deny anywhere always wins.

Further reading

Check your understanding

3 questions

Question 1 of 3

Lantern’s developer Sam has no policies that mention DynamoDB. Sam runs aws dynamodb scan --table-name lantern-rsvps. What happens?

Question 2 of 3

A policy allows s3:* on Lantern’s posters bucket for the Developers group, and a second policy explicitly denies s3:DeleteBucket for the same group. A developer tries to delete the bucket. What happens?

Question 3 of 3

Which statement about IAM roles is accurate?

Practice

Choose wisely

Allowed or denied?

All of this happens in Lantern’s single AWS account.

  • The Developers group (Sam is a member) has an identity-based policy that allows s3:GetObject and s3:DeleteObject on arn:aws:s3:::lantern-posters/*.
  • The lantern-posters bucket policy explicitly denies s3:DeleteObject to every principal, and allows s3:GetObject to the role lantern-thumbnailer.
  • The role lantern-thumbnailer has no identity-based policies at all.

Select every request that AWS allows.

Allowed or denied?