2.1
Users, Groups and Policy Documents
The root account, IAM users and groups, and every field of a JSON policy.
22 min Reading + animations
Tip: tap or hover any dotted-underlined term to see what it means.
By the end of this lesson you will be able to
- Tell authentication (who are you?) from authorization (what may you do?), and say which part of IAM does each.
- Explain why IAM is a global service, and what that means for users, groups and policies.
- Use the root user, IAM users and IAM groups for what each is for, and know the rules of groups (users only, no nesting, up to 10 per user).
- Apply the principle of least privilege when you grant permissions.
- Choose between AWS managed, customer managed and inline policies.
- Read and write every field of a JSON policy: Version, Id, Statement, Sid, Effect, Principal, Action, NotAction, Resource and Condition, and write ARNs correctly.
- Tell identity-based policies from resource-based policies, and check a policy with IAM Access Analyzer and the policy simulator before you trust it.
#One account, many hands
An AWS account starts with exactly one identity: the email address and password you signed up with. Everything you create (servers, databases, buckets) belongs to that account, and the account pays for all of it.
Very soon other people and programs need to work in the same account:
- a developer who deploys the application;
- an operations engineer who restarts servers at night;
- an auditor who must read everything and change nothing;
- the application itself, which writes files to S3 and reads from a database.
Sharing the sign-up password with all of them would be a disaster: everyone could do everything, nobody could tell who did what, and one leaked password would expose the whole account. AWS Identity and Access Management (IAM) solves this. It lets you create separate identities inside the account, give each one exactly the permissions it needs, and check every single request against those permissions.
IAM itself has no charge. You pay only for the resources that your users and applications create.
#Authentication and authorization
Every request to AWS (a click in the console, a CLI command, an API call from code) goes through two separate checks:
| Authentication | Authorization | |
|---|---|---|
| Question | Who are you? | Are you allowed to do this, to this resource, right now? |
| How AWS checks | Your credentials: a password at sign-in, or a signature made with an access key on every API call | Policies: JSON documents attached to you, to your groups or to the resource |
| Failure looks like | Sign-in fails, or the API says the security token or signature is invalid | AccessDenied: AWS knows who you are, but says no |
After authentication, AWS builds a request context for the authorization check. It holds:
- the principal: who is asking (an IAM user, a role, the root user);
- the action: what they want to do, such as
s3:GetObjectorec2:StartInstances; - the resource: what they want to do it to, named by its ARN;
- the environment: the source IP address, the Region, the time, whether the connection uses TLS;
- data about the resource, such as its tags.
AWS compares this context with every policy that applies. By default the answer is no: a request is allowed only if some policy explicitly allows it (and none denies it). Lesson 2.2 walks through the complete decision, including what happens when policies disagree.
What happens to one request: who are you, then may you?
Alice asks S3 for a file. Watch the two separate checks every request goes through, and what each failure looks like.
Scenario
Valid credentials and a policy that allows the action.
Alice asks for one object. Whether she clicks in the console or types a command, it becomes the same thing: one signed API call, s3:GetObject.
#IAM is a global service
Most AWS services are regional: an EC2 instance lives in one Region, an AMI belongs to one Region (lesson 4.3). IAM is different. IAM is global: when you create a user, a group, a role or a policy, it exists in every Region of the account at once. You do not choose a Region in the IAM console, and a user named alice can work in Mumbai and in Ireland with the same password and the same permissions.
What this means in practice:
- You manage identities once per account, not once per Region.
- The resources those identities use are still regional. A policy can name a resource in a particular Region, and the
aws:RequestedRegioncondition key can limit where a user may work. - IAM is eventually consistent. A change you make (a new user, an edited policy) is stored centrally and copied around the world, so it can take a short time before every Region sees it. Do not put IAM changes in the critical path of an application; create users and policies ahead of time.
#The identities in an account
IAM has a few kinds of identity. This lesson covers the first three; roles get their own lesson.
| Identity | What it is | Credentials | Use it for |
|---|---|---|---|
| Root user | The identity created with the account, signed in with the account email | Email + password (and optionally access keys, which you should not create) | Only the few tasks that need it, such as closing the account. Lesson 2.3. |
| IAM user | A person or program you create inside the account | Long-term: a console password and/or up to two access keys | People and programs that need their own permanent identity |
| IAM group | A collection of IAM users | None: you cannot sign in as a group | Giving the same permissions to many users at once |
| IAM role | An identity that someone or something assumes for a while | Temporary credentials only | AWS services (EC2, Lambda), other accounts, people who sign in elsewhere. Lesson 2.4. |
#The root user
The root user has complete access to everything in the account, including billing and closing the account, and IAM policies cannot limit it. That is exactly why you should not use it for daily work: one stolen root password and the attacker owns the account. Create an administrator for yourself, protect root with strong sign-in protection, and put the root credentials away. Lesson 2.3 covers what root is (and is not) for.
#IAM users
An IAM user is a permanent identity inside your account. It has:
- a name, unique in the account and not case-sensitive (you cannot have both
Aliceandalice), up to 64 characters; - an ARN that names it everywhere, for example
arn:aws:iam::111122223333:user/alice; - optionally a console password, to sign in at the account’s own sign-in page (
https://111122223333.signin.aws.amazon.com/console, or an alias you choose); - optionally up to two access keys, for the CLI and code (lesson 1.3). Two, so that you can create a new one, switch over, then delete the old one;
- permissions: policies attached to the user directly and through its groups.
A new IAM user can do nothing until a policy allows something. That is the starting point of least privilege.
Both the password and the access keys are long-term credentials: they work until someone changes or deletes them. That is their weakness. AWS’s current advice is to give people access through federation or IAM Identity Center (they sign in with the company’s identity system and get temporary credentials), and to give workloads an IAM role. IAM users remain common, especially in small accounts and on the exam, and everything you learn about policies applies to every identity.
#IAM groups
A group is a way to manage permissions for many users at once. You attach policies to the group, put users in it, and every member gets those permissions. When someone joins the operations team, add them to the operations group; when they move on, remove them.
The rules of groups:
- A group contains only users, never other groups. There is no nesting: you cannot put
developersinsideengineering. - A user does not have to be in a group. A user can have policies attached directly, or inline, instead.
- A user can be in several groups, up to 10. Their permissions are the combination of all of them: everything their groups and their own policies allow. No group has priority over another; when two policies disagree, the evaluation logic in lesson 2.2 decides (and an explicit deny wins).
- A group is not an identity. It has no credentials, nobody signs in as a group, and a group cannot be named as the
Principalin a resource-based policy. - An account can have 300 groups by default (raise it to 500), and 5,000 users.
Grouping people by job (developers, operations, auditors) and giving permissions to the job is called role-based access control (RBAC). A more flexible style, which grants permissions by matching tags on the user and on the resource, is attribute-based access control (ABAC); you will see its condition keys later in this lesson.
Groups: give permissions to a job, not to each person
Three groups, six users. Watch how users get permissions from their groups, what happens with two groups, and what groups cannot do.
Scenario
Effective permissions
| User | From | Can do |
|---|---|---|
| alice | developers | ec2:*, s3:* |
| bob | developers | ec2:*, s3:* |
| david | operations | restart EC2 |
| edward | audit | view only |
Policies are attached to the groups, not to the people. Every member gets everything the group’s policies allow.
Self-checkQuestion
An engineer wants to place the developers group and the testers group inside a new group called engineering, so that one policy on engineering applies to everyone. What happens?
#The principle of least privilege
Least privilege means: give every identity only the permissions it needs for its job, and nothing more. It is the single most tested best practice in IAM.
Why it matters:
- A leak does less damage. If an access key with permission to read one bucket leaks, the attacker reads one bucket. If an administrator key leaks, they own the account.
- Mistakes stay small. A script with a bug cannot delete a database it was never allowed to touch.
- Audits are easier. You can answer “who can delete production data?” by reading a short list of policies.
How to apply it:
- Start from nothing. New identities have no permissions, and that is the right default.
- Grant specific actions (
s3:GetObject, nots3:*) on specific resources (one bucket, not*), with conditions where they help (from the office network, in one Region). - It is fine to start a little broader while a project is new, for example with an AWS managed policy. Then tighten it: look at what the identity actually used (IAM Access Advisor shows last-accessed information, lesson 2.4) and remove the rest.
- Review regularly. People change jobs; permissions should follow.
#Policies: what they are and the three kinds
A policy is a JSON document that lists permissions. When a policy is attached to an identity (a user, a group or a role), it is an identity-based policy: it says what that identity may do. Identity-based policies come in three kinds:
| AWS managed | Customer managed | Inline | |
|---|---|---|---|
| Who writes it | AWS | You | You |
| Can you edit it | No | Yes | Yes |
| Reusable | Attach to any number of identities in any account | Attach to any number of identities in your account | No: it lives inside one user, group or role |
| Versions | AWS updates it (new services and actions appear automatically) | Up to 5 versions; one is the default; roll back by choosing an older default | No versions |
| When the identity is deleted | Policy stays | Policy stays | Deleted with it |
| Its ARN | arn:aws:iam::aws:policy/ReadOnlyAccess | arn:aws:iam::111122223333:policy/reports-read | None of its own |
| Good for | Getting started; standard job functions | Your real, least-privilege permissions | A strict one-to-one permission that must never be attached to anything else |
Some AWS managed policies you will meet:
AdministratorAccess: every action on every resource. For administrators only.PowerUserAccess: everything except managing IAM users, groups and Organizations. A common choice for developers in sandbox accounts.ReadOnlyAccess: read everything, including data such as S3 objects.ViewOnlyAccess: list and describe resources, without reading the data inside them. Closer to what an auditor usually needs.- Service policies such as
AmazonS3ReadOnlyAccessand job-function policies such asDatabaseAdministratorandSecurityAudit.
AWS managed policies are convenient but broad, and AWS can change them. Because they name * resources, they rarely meet least privilege on their own. The usual path: start with an AWS managed policy, then replace it with a customer managed one written for your resources.
Limits worth knowing: a user can have 10 managed policies attached (raise it to 20), a group 10, a role 20 (raise it to 25). A customer managed policy can be up to 6,144 characters; all inline policies of one user together up to 2,048 characters (group 5,120, role 10,240). White space does not count.
AWS managed, customer managed and inline policies
The same permissions can live in three kinds of policy. Watch who can edit each, how it is shared, and what happens on a bad change or a delete.
Scenario
ReadOnlyAccess is written by AWS. You can attach it, but not edit it, and AWS updates it when services gain new read actions.
#Anatomy of a JSON policy
Here is a complete identity-based policy. It lets its holder list one bucket and read and write the objects in it, but only from the office network:
{
"Version": "2012-10-17",
"Id": "reports-team-access",
"Statement": [
{
"Sid": "ListTheBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::example-reports"
},
{
"Sid": "ReadWriteObjectsFromOffice",
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::example-reports/*",
"Condition": {
"IpAddress": { "aws:SourceIp": "203.0.113.0/24" }
}
}
]
}
The fields, top to bottom:
| Field | Required? | What it does |
|---|---|---|
Version | Strongly recommended | The version of the policy language, not of your policy. Always "2012-10-17". |
Id | Optional | A name for the whole policy. Some services (SQS, SNS) like it in resource policies; for IAM it is informational. |
Statement | Required | One statement, or a list of statements. Each one is evaluated on its own. |
Sid | Optional | A statement ID, a label for one statement (letters and numbers). Makes policies easier to read and talk about. |
Effect | Required | "Allow" or "Deny". |
Principal | Only in resource-based policies | Who the statement is about. Never in identity-based policies: there, the principal is whoever the policy is attached to. |
Action / NotAction | One of them is required | What may (or may not) be done. |
Resource / NotResource | One of them is required in identity-based policies | To what, as ARNs. |
Condition | Optional | When the statement applies: IP range, Region, time, tags, and more. |
#Version: the language, not your edit number
"2012-10-17" is the current version of the IAM policy language. The older "2008-10-17" still exists for compatibility. If you leave Version out, AWS treats the policy as the old language, and newer features silently stop working. The best-known one: policy variables such as ${aws:username} are not replaced, so arn:aws:s3:::home/${aws:username}/* matches the literal text instead of each user’s own folder. Always write "Version": "2012-10-17", and never change it to today’s date.
#Effect
Each statement either allows or denies. Most policies are lists of Allow statements. Deny statements are used as guard rails (“never delete this bucket”, “never work outside these Regions”). Remember the default: anything not allowed is denied anyway. Lesson 2.2 explains why an explicit deny always beats an allow.
#Action: service prefix, name, wildcards
An action is written service:Operation: s3:GetObject, ec2:StartInstances, iam:CreateUser, dynamodb:Query. The prefix is the service’s short name, and the name matches an API operation.
- A list of actions is allowed:
["s3:GetObject", "s3:PutObject"]. - Wildcards:
*matches any run of characters and?matches one character.s3:*is every S3 action;ec2:Describe*is every read-only EC2 “describe” call;"*"alone is every action of every service. - Action names are not case-sensitive, but write them as the documentation does.
- A misspelled action (
s3:GetObjects) is not an error at run time. It simply matches nothing, so the request is denied. The policy editor’s validation (below) flags it.
Wildcards are powerful and dangerous. s3:Get* today includes actions AWS adds next year. Prefer explicit lists for anything sensitive.
#NotAction: everything except…
NotAction matches every action except the ones listed. It is not a deny; what it does depends on the Effect:
Allow+NotAction: allows everything except the listed actions."Effect": "Allow", "NotAction": "iam:*", "Resource": "*"gives access to every service except IAM, including every service AWS launches in future. That is broad; use it knowingly.Deny+NotAction: denies everything except the listed actions. A classic guard rail: deny every action outside two Regions, except the global services (IAM, Organizations, CloudFront, Route 53…) that are always called inus-east-1.
NotAction never grants the listed actions, and never denies them either; they are simply not covered by that statement. NotResource and NotPrincipal work the same way for their fields, and are rarely the right tool.
#Resource and ARNs
An Amazon Resource Name (ARN) names one AWS resource uniquely across all of AWS:
arn:partition:service:region:account-id:resource
- partition:
awsfor normal Regions (aws-cnfor China,aws-us-govfor the American government Regions); - service:
s3,ec2,iam,dynamodb…; - region: empty for global resources;
- account-id: the 12-digit account; empty where it is not needed;
- resource: the type and the name or ID, written the way that service defines it.
Real examples:
| Resource | ARN | Note |
|---|---|---|
| IAM user | arn:aws:iam::111122223333:user/alice | No Region: IAM is global |
| IAM group | arn:aws:iam::111122223333:group/developers | |
| AWS managed policy | arn:aws:iam::aws:policy/ReadOnlyAccess | Account is the word aws |
| S3 bucket | arn:aws:s3:::example-reports | No Region, no account: bucket names are globally unique |
| S3 objects in it | arn:aws:s3:::example-reports/* | The bucket and the objects are different resources |
| Objects under a prefix | arn:aws:s3:::example-reports/2026/* | |
| EC2 instance | arn:aws:ec2:ap-south-1:111122223333:instance/i-0abcd1234ef567890 | Region and account both present |
| DynamoDB table | arn:aws:dynamodb:eu-west-1:111122223333:table/orders |
Resource can be one ARN, a list, or contain wildcards (arn:aws:s3:::example-*). "Resource": "*" means every resource.
Some actions do not work on a particular resource at all, so they must use "Resource": "*". Most list and describe calls are like this: ec2:DescribeInstances lists all instances in a Region, so there is no single instance ARN to name. The Service Authorization Reference lists, for every action, which resource types and condition keys it supports.
#Condition: when the statement applies
A Condition block narrows a statement to certain situations. Its shape is always operator → key → value(s):
"Condition": {
"StringEquals": { "aws:RequestedRegion": ["eu-west-1", "ap-south-1"] },
"IpAddress": { "aws:SourceIp": "203.0.113.0/24" }
}
- Operators compare:
StringEquals,StringLike(with*and?),StringNotEquals,NumericLessThan,DateGreaterThan,Bool,IpAddressandNotIpAddress,ArnLike. AddingIfExists(StringEqualsIfExists) means “if the key is missing, treat it as a match”. - Keys are facts in the request context. Global keys start with
aws:; service keys with the service prefix, such ass3:prefixorec2:InstanceType. - The logic: every operator and every key in the block must match (and); several values for one key mean any of them (or). The example above matches a request to either of the two Regions and from the office range.
Global keys you will use often:
| Key | What it holds | Typical use |
|---|---|---|
aws:SourceIp | The public IP address the request came from | Allow only from the office or VPN range |
aws:RequestedRegion | The Region the API call goes to | Keep work inside approved Regions |
aws:SecureTransport | Whether the request used TLS | Deny plain HTTP to a bucket |
aws:CurrentTime | Date and time of the request | Access that ends on a date |
aws:PrincipalTag/<key>, aws:ResourceTag/<key> | Tags on the caller and on the resource | ABAC: “team = payments may touch resources tagged team = payments” |
aws:MultiFactorAuthPresent | Whether the caller signed in with a second factor | Protect dangerous actions (lesson 2.3) |
Two aws:SourceIp traps: a request that reaches AWS through a VPC endpoint carries a private address, so aws:SourceIp does not match it (use aws:SourceVpce or aws:VpcSourceIp); and when an AWS service (a deployment tool, for example) calls another service on your behalf, the source address is AWS’s, not yours, so a strict IP rule can break it (aws:ViaAWSService handles that case).
How a statement matches a request, field by field
The statement allows GetObject on example-reports/* from 203.0.113.0/24. Every field must match for it to apply. Try the usual mistakes.
Scenario
Request context
principal
arn:aws:iam::111122223333:user/report-builder
action
s3:GetObject
resource
arn:aws:s3:::example-reports/input/jan.csv
aws:SourceIp
203.0.113.25
The app downloads input/jan.csv from the office. IAM lines the request up against the statement.
#Identity-based and resource-based policies
So far every policy was attached to an identity. Some services also let you attach a policy to the resource itself: an S3 bucket policy, an SQS queue policy, an SNS topic policy, a KMS key policy, a Lambda function’s resource policy, and the trust policy of an IAM role. These are resource-based policies, and they are always inline on that one resource.
| Identity-based policy | Resource-based policy | |
|---|---|---|
| Attached to | A user, group or role | A resource (bucket, queue, key, role trust…) |
| Says | What this identity may do, on which resources | Who may do what to this resource |
Principal field | Not allowed (it is the identity it is attached to) | Required |
| Kinds | AWS managed, customer managed, inline | Inline only |
| Can grant other accounts access | No, only to itself | Yes: name a principal from another account |
A bucket policy that lets one user from another account read the bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PartnerCanRead",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::444455556666:user/partner-app" },
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::example-reports/*"
}
]
}
How the two combine (lesson 2.2 has the full picture):
- Inside one account, either kind is enough: if the user’s identity policy allows it or the bucket policy allows that user, the request is allowed (unless something denies it). Two exceptions to remember: a KMS key policy and a role’s trust policy must themselves allow the access.
- Across accounts, both are needed: the other account’s identity policy must allow its user to call your bucket, and your bucket policy must allow that user. Each account controls its own side.
"Principal": "*"means anyone, including the anonymous internet. In a bucket policy that makes data public, which is why S3 Block Public Access exists and is on by default.
Identity-based and resource-based policies, in one account and across two
A user’s policy speaks for the user; a bucket policy speaks for the bucket. Watch when one of them is enough and when both must agree.
Scenario
Alice’s identity policy allows GetObject on example-reports. The bucket policy says nothing about her. Inside one account, that is enough.
Self-checkQuestion
Which statement about the Principal element is correct?
#Building a policy step by step
A realistic request: “The analytics app runs as the IAM user report-builder. It must read last month’s input files under input/ in the bucket example-reports, write finished reports under output/, and list only those two folders. It must not delete anything. It runs from the office network 203.0.113.0/24.”
Write down the actions
Reading files is
s3:GetObject, writing iss3:PutObject, listing iss3:ListBucket. Deleting iss3:DeleteObject, which we simply leave out: anything not allowed is denied.Match each action to its resource
GetObjectonarn:aws:s3:::example-reports/input/*.PutObjectonarn:aws:s3:::example-reports/output/*.ListBucketon the bucket itself,arn:aws:s3:::example-reports. Three different resources, so three statements.Narrow the listing
ListBucketacts on the whole bucket, so limit which folders may be listed with the S3 condition keys3:prefix.Add the network condition
Add
IpAddresswithaws:SourceIpto every statement. (If the app moves into a VPC and reaches S3 through a gateway endpoint, this key stops matching; switch toaws:SourceVpce.)Validate, test, then attach
Paste the policy into the IAM policy editor, read the validation findings, test it in the policy simulator, and only then save it as a customer managed policy named
report-builder-s3and attach it.
The result:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadInput",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-reports/input/*",
"Condition": { "IpAddress": { "aws:SourceIp": "203.0.113.0/24" } }
},
{
"Sid": "WriteOutput",
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::example-reports/output/*",
"Condition": { "IpAddress": { "aws:SourceIp": "203.0.113.0/24" } }
},
{
"Sid": "ListOnlyTheTwoFolders",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::example-reports",
"Condition": {
"StringLike": { "s3:prefix": ["input/*", "output/*"] },
"IpAddress": { "aws:SourceIp": "203.0.113.0/24" }
}
}
]
}
Read it back as a sentence per statement: “allow reading objects under input, from the office”; “allow writing objects under output, from the office”; “allow listing the bucket, only for those prefixes, from the office”. If you cannot read a statement as one clear sentence, it is probably wrong.
#What goes wrong with policies
| Symptom | Cause | Fix |
|---|---|---|
AccessDenied although “the policy allows S3” | The action is misspelled (s3:GetObjects) or under the wrong service prefix | Copy action names from the Service Authorization Reference; read the editor’s validation |
| Listing works, downloads fail (or the other way round) | Bucket ARN and object ARN mixed up | ListBucket → bucket; object actions → bucket/* |
| Saving fails with “Principal not allowed” | Principal in an identity-based policy | Remove it; it belongs only in resource-based policies |
${aws:username} matches nothing | Version missing or set to 2008-10-17 | "Version": "2012-10-17" |
| A user can suddenly use a brand-new service | Allow + NotAction, or a broad wildcard | Replace with an explicit list of actions |
| An IP condition blocks a deployment run by an AWS service | The AWS service called on the user’s behalf from AWS’s own addresses | Add aws:ViaAWSService handling, or condition only the direct calls |
| A new permission works “a bit later” | IAM is eventually consistent | Make IAM changes ahead of time, not inside the application’s request path |
| Cannot add another inline policy | The 2,048-character total for a user’s inline policies | Use a customer managed policy (6,144 characters each) |
| Cannot attach an eleventh managed policy to a user | The default of 10 managed policies per user | Combine policies, use groups, or request the increase to 20 |
#Checking a policy before you trust it
Never attach a policy you have not checked. Three tools help, all free:
- IAM Access Analyzer policy validation. Runs automatically in the console’s policy editor, and through the
access-analyzer validate-policyAPI. It checks the policy against more than a hundred rules and reports errors (the policy will not work: invalid action, bad ARN format), security warnings (it is more permissive than it looks, such asAllowwithNotAction), warnings (it does not follow the grammar well) and suggestions (cleaner ways to write it). - Custom policy checks in Access Analyzer answer a precise question about a change, such as “does this new version grant any access the old one did not?”, and can run in a deployment pipeline.
- The IAM policy simulator (
https://policysim.aws.amazon.com, oraws iam simulate-principal-policy) asks: “if this user called this action on this resource, with this context, would it be allowed, and which statement decided?” It evaluates the real policies without making the call, so you can testDeleteObjectsafely.
Access Analyzer can also generate a starting policy from the actions an identity really used, and show unused access. Lesson 2.4 covers those, with the credentials report and Access Advisor.
#How it is used in system design
| Situation | Good design |
|---|---|
| A team of eight developers | One group, one customer managed policy for their actual work; no policies on individual users |
| One person needs a temporary extra permission | Add them to a second group, or attach a time-limited policy (condition on aws:CurrentTime); remove it afterwards |
| An application on EC2 needs S3 | An IAM role, not an IAM user with stored keys (lesson 2.4) |
| Another company’s account must read one bucket | A bucket policy naming their account or role, plus their own identity policy |
| Many teams, many resources | Tag both, write one ABAC policy that matches aws:PrincipalTag to aws:ResourceTag |
| “Nobody may work outside our two Regions” | A Deny with aws:RequestedRegion and NotAction for the global services, ideally as a service control policy (chapter 20) |
| Prove that a policy change grants nothing new | Access Analyzer custom policy check in the pipeline |
Exam patterns from this lesson:
- “Several users need the same permissions; least operational effort” → put them in a group and attach the policy to the group.
- “Give a user the permissions, but follow least privilege” → a customer managed policy naming specific actions and resources, not
AdministratorAccess. - “Make sure a policy is only ever used by this one user and is deleted with it” → an inline policy.
- “Roll back a bad change to a policy used by many groups” → set an earlier version of the customer managed policy as the default.
- “Allow access only from the corporate IP range” →
ConditionwithIpAddressandaws:SourceIp. - “Another account must access our S3 bucket” → a bucket policy (resource-based, with
Principal).
#Try it yourself
With the AWS CLI configured for an administrator (lesson 1.3), in a test account:
# Create a group and a user, and put the user in the group
aws iam create-group --group-name reports-team
aws iam create-user --user-name report-builder
aws iam add-user-to-group --group-name reports-team --user-name report-builder
# Validate the policy from this lesson before using it
aws accessanalyzer validate-policy \
--policy-type IDENTITY_POLICY \
--policy-document file://report-builder-s3.json
# Save it as a customer managed policy and attach it to the group
aws iam create-policy --policy-name report-builder-s3 \
--policy-document file://report-builder-s3.json
aws iam attach-group-policy --group-name reports-team \
--policy-arn arn:aws:iam::111122223333:policy/report-builder-s3
# Ask the simulator: may this user delete an object? (expect implicitDeny)
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::111122223333:user/report-builder \
--action-names s3:DeleteObject s3:GetObject \
--resource-arns arn:aws:s3:::example-reports/input/jan.csv
# See everything that applies to the user: direct, inline and through groups
aws iam list-groups-for-user --user-name report-builder
aws iam list-attached-user-policies --user-name report-builder
aws iam list-user-policies --user-name report-builder
Then try the mistakes on purpose: change s3:GetObject to s3:GetObjects and read the validation output; remove the bucket ARN statement and run aws s3 ls s3://example-reports/ as the user. Clean up with delete-user, delete-group and delete-policy when you finish (detach and remove first).
#Summary
Key takeaways
- IAM answers two questions on every request: authentication (who are you?) and authorization (may you do this?). By default the answer is no until a policy allows it.
- IAM is global: users, groups, roles and policies exist in every Region; the resources they use are regional. IAM is free and eventually consistent.
- The root user has unlimited access; never use it for daily work (lesson 2.3). IAM users have long-term credentials: a password and/or up to two access keys. Groups contain only users, cannot be nested, are not principals, and a user can be in up to 10; the user’s permissions are the combination of all of them.
- Least privilege: specific actions, specific resources, conditions where they help; start narrow, tighten over time.
- Identity-based policies are AWS managed (convenient, broad, not editable), customer managed (yours, reusable, up to 5 versions with rollback) or inline (one-to-one, deleted with the identity).
- A policy has
Version(always2012-10-17), optionalId, andStatements with optionalSid,Effect,Action/NotAction,Resource/NotResource, optionalCondition, andPrincipalonly in resource-based policies. - ARNs:
arn:partition:service:region:account:resource. IAM ARNs have no Region; S3 ARNs have neither Region nor account; a bucket (bucket) and its objects (bucket/*) are different resources. - Conditions: operator → key → values; different keys must all match, values of one key are alternatives.
aws:SourceIp,aws:RequestedRegion, tags for ABAC. - Resource-based policies (bucket, queue, key, trust policies) name a
Principaland can let other accounts in; across accounts both sides must allow. - Check policies with Access Analyzer validation and the policy simulator before attaching them.
Answer on your own first, then read the explanation, even when you got it right.
Self-checkQuestion
A developer signs in to the console successfully, then gets AccessDenied when opening an S3 bucket. Which step of the request failed?
Self-checkQuestion
Why do you never select a Region when you create an IAM user?
Self-checkQuestion
Which two statements about IAM groups are true? (Choose two.)
Choose 2
Self-checkQuestion
A company has 40 developers who need identical permissions. Permissions change every few months. What is the approach with the least operational effort?
Self-checkQuestion
What does the principle of least privilege require?
Self-checkQuestion
Which two are true about customer managed policies compared with inline policies? (Choose two.)
Choose 2
Self-checkQuestion
A security team wants a permission that can never be attached to any other identity by mistake, and that disappears automatically when the user is deleted. Which policy type fits?
Self-checkQuestion
An auditor must see the configuration of every resource but must not read the data inside S3 objects or database tables. Which AWS managed policy is the closer fit?
Self-checkQuestion
What is the correct value of the Version element in a new IAM policy written today?
Self-checkQuestion
A policy uses the resource arn:aws:s3:::home/${aws:username}/* so that each user can reach only their own folder, but no user can reach anything. The policy has no Version element. What is the likely cause?
Self-checkQuestion
Which element is required in every statement of an identity-based policy?
Self-checkQuestion
What does the action pattern ec2:Describe* match?
Self-checkQuestion
A statement has Effect Allow, NotAction iam:*, and Resource *. What does it do?
Self-checkQuestion
Which two of these ARNs are written correctly? (Choose two.)
Choose 2
Self-checkQuestion
A user’s policy allows s3:ListBucket and s3:GetObject on arn:aws:s3:::example-reports/* only. What happens?
Self-checkQuestion
A policy has a typo: s3:GetObjects instead of s3:GetObject. What happens when the user tries to download a file?
Self-checkQuestion
A condition block contains StringEquals with aws:RequestedRegion set to two Regions, and IpAddress with aws:SourceIp set to one range. When does the statement apply?
Self-checkQuestion
A company wants employees to access a bucket only from the office network 203.0.113.0/24. Which condition does that?
Self-checkQuestion
An application on EC2 in a private subnet reaches S3 through a gateway VPC endpoint. Its bucket access is limited with aws:SourceIp set to the company’s public range, and now every request is denied. Why?
Self-checkQuestion
Which two statements about resource-based policies are true? (Choose two.)
Choose 2
Self-checkQuestion
A user in account 111122223333 must read a bucket in account 444455556666. The bucket policy allows that user to read. The user still gets AccessDenied. What is most likely missing?
Self-checkQuestion
Inside one account, a user has no identity-based policy for S3 at all. The bucket policy of a bucket in the same account allows that user’s ARN to read objects. Can the user read?
Self-checkQuestion
What does Principal set to * mean in an S3 bucket policy statement that allows s3:GetObject?
Self-checkQuestion
A new IAM user is created with a console password and no policies. What can the user do after signing in?
Self-checkQuestion
Why can an IAM user have up to two access keys?
Self-checkQuestion
Which two actions are good ways to apply least privilege to an existing user who has AdministratorAccess but only works with one DynamoDB table? (Choose two.)
Choose 2
Self-checkQuestion
Which tool answers the question: would this user be allowed to call s3:DeleteObject on this object, and which statement decides, without actually deleting anything?
Self-checkQuestion
While writing a policy in the console, the editor shows a security warning: Allow with NotAction. Which feature produced it, and what does it mean?
Self-checkQuestion
An administrator edits a customer managed policy attached to six groups, and suddenly nobody can deploy. What is the fastest safe fix?
Self-checkQuestion
Which two are myths about IAM? (Choose two.)
Choose 2
Self-checkQuestion
A team adds a policy for a new hire and the first request a second later fails, but it works when retried a little later. What explains this?
Self-checkQuestion
A company has 40 project teams and wants one IAM policy that lets each developer manage only the EC2 instances of their own project, without editing the policy when a new project starts. Which condition fits?
Self-checkQuestion
A finance firm wants IAM users to be able to call AWS APIs only from the office network 203.0.113.0/24. Which condition key does the policy need?
Self-checkQuestion
Account 444455556666 needs to read objects in a bucket owned by account 111122223333. The bucket owner does not want to create a cross-account role. Which policy type makes this possible?
Self-checkQuestion
Before attaching a new policy to 200 developers, an admin wants to test whether it allows s3:PutObject on one bucket and denies ec2:TerminateInstances, without actually calling those APIs. Which tool fits?
Self-checkQuestion
A company’s data must stay in ap-southeast-1, and developers must not be able to create resources in any other Region. Which condition key is the right tool?