Courses / Hands-on Cloud for Freshers
Session 2 of 8
Who can do what: identities and permissions
Overview
Unit 2 — Who Can Do What: Identities and Permissions
Course: Hands-on Cloud for Freshers
Prerequisites: You have an AWS account with an everyday administrator IAM user, hoc-admin,
protected by MFA, as built in Unit 1, and you can sign in to the console as that user. You can open a
terminal on your own computer and run a command in it. You can read a short JSON document: objects in
braces, lists in square brackets, strings in double quotes.
What the reader can do after this unit:
- Read an IAM policy statement and say, for a given request, whether AWS allows it, denies it explicitly, or denies it implicitly — and which statement decided.
- Write a least-privilege identity-based policy for a named bucket, choosing the right ARN for a bucket-level action and for an object-level action, and prove it with the IAM policy simulator before attaching it to anything.
- Install the AWS CLI version 2, sign it in with
aws loginso that it holds only short-lived credentials, and confirm which identity it is acting as withaws sts get-caller-identity.
Core question this unit answers: When AWS receives a request, how does it decide yes or no — and how do you write a policy that says yes to exactly what you need and nothing more?
Connections:
- Builds on: Unit 1’s identities — the root user, the
hoc-adminuser and its group — and the denial message a user with no policies received at the end of Unit 1’s project. - Leads into: Unit 3, which creates the storage bucket this unit’s policy is written for, and uses the signed-in command line from this unit to upload files to it.
Your answers are scored
This unit is assessed. The quiz is marked against a key held separately from your materials. Questions 1–8 are multiple choice and are marked by comparing your letter with the key. Questions 9–11 ask you to write an answer in an exact format, and each one is marked by checks printed with the question — for the policy question, by running the AWS policy simulator against a printed list of requests that must be allowed and requests that must be denied.
- You can check your constructed answers completely before you submit them. The requests the grader simulates are printed in the question, and the simulator is the same one you use in the project.
- Style is not marked. A longer policy that produces the required decisions scores exactly what a shorter one does.
Notes
Hands-on Cloud for Freshers — Unit 2: Who Can Do What: Identities and Permissions
Before you start
You need the hoc-admin user from Unit 1, with its password and MFA device, and a computer where you
can install software. Nothing in this unit creates a server, storage or database. IAM is documented
as “offered at no additional charge”, and the policy simulator evaluates policies without sending a
real request to any AWS service.
If you are starting here without Unit 1, you need an AWS account whose root user has an MFA
device, and an everyday administrator user: an IAM user named hoc-admin with console access and
MFA, in a group hoc-admins that has the AWS managed policy AdministratorAccess. You also need one
Region to work in; the examples use ap-south-1. The project for this unit lists the console steps
for all three under If you do not have Unit 1’s setup, and the AWS pages they come from are under
Sources.
Every statement here about how AWS behaves is taken from the AWS documentation pages listed under Sources at the end, retrieved on 2026-10-02. Commands are shown for a Linux or macOS terminal; where Windows differs, the difference is noted.
Summary
Every action in AWS — clicking a button in the console, running a command, a program calling an API — arrives at AWS as a request, and AWS answers each request with yes or no. The answer comes from policies: JSON documents that list which actions are allowed or denied on which resources. Three rules decide the answer: everything is denied unless something allows it, an allow is needed to say yes, and an explicit deny anywhere beats every allow. This unit teaches you to read and write those policies, to name resources precisely with ARNs, and to prove what a policy does with the policy simulator before it touches anything real. It also sets up the AWS command line, signed in with short-lived credentials, so that from Unit 3 onward you can build from a terminal without ever creating a long-term access key.
Key concepts
| Term | Definition |
|---|---|
| Principal | The identity making a request: the root user, an IAM user, or a role that someone or something has assumed |
| Request | One attempt to do one action on one resource, such as “list the objects in bucket X”. AWS allows or denies each request separately |
| Policy | A JSON document of statements that allow or deny actions on resources. AWS evaluates the policies that apply to a request to decide it |
| Identity-based policy | A policy attached to a user, group or role. It says what that identity may do |
| Resource-based policy | A policy attached to a resource, such as a bucket policy. It names which principals may act on that resource |
| Statement | One rule inside a policy, with an Effect, an Action list and a Resource list |
| Effect | Allow or Deny — what the statement does when it matches a request |
| Action | The operation a statement covers, written service:Operation, for example s3:GetObject |
| ARN | Amazon Resource Name: the unique, written-out name of a resource, such as arn:aws:s3:::my-bucket. Used in the Resource element |
| Implicit deny | The default answer: a request that no statement allows is denied without any statement saying so |
| Explicit deny | A Deny statement that matches the request. It overrides every allow |
| AWS managed policy | A ready-made policy created and maintained by AWS, such as AdministratorAccess |
| Customer managed policy | A policy you write and store in your own account, which you can attach to many identities |
| Role | An identity with permissions but no password or access keys. Whoever assumes it receives temporary credentials |
| Trust policy | The resource-based policy on a role that says which principals may assume it |
| Least privilege | Granting only the actions a task needs, on only the resources it needs |
| AWS CLI | The AWS Command Line Interface: the aws command, which sends the same requests the console sends |
| Profile | A named set of CLI settings — Region, how to get credentials — stored in your CLI configuration |
Explanations
The failure, before the explanation
A learner wants a teammate to be able to read the files in one bucket, hoc-site-ar-4821, and nothing
else. They write this policy, which looks right:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:ListBucket", "s3:GetObject"],
"Resource": "arn:aws:s3:::hoc-site-ar-4821/*"
}
]
}
The teammate can download a file if they know its exact name. But when they ask for the list of files
in the bucket, they get an access-denied error. Nothing in the policy says “deny”, and s3:ListBucket
is written right there.
Run the same two requests through the IAM policy simulator and it shows the difference:
| Action | Resource the request is about | Simulator decision |
|---|---|---|
s3:GetObject |
arn:aws:s3:::hoc-site-ar-4821/index.html |
allowed |
s3:ListBucket |
arn:aws:s3:::hoc-site-ar-4821 |
implicitDeny |
Listing is something you do to the bucket. Reading is something you do to an object inside it.
The policy only names the objects — /* means “everything inside” — so the listing request is about a
resource that no statement covers. It is not refused by a rule; it is refused because no rule says yes.
The rest of this unit explains why, and how to write it correctly.
How AWS decides: three rules
Start with entry to a college fest. The gate starts from “nobody gets in”. Your name on the guest list gets you in. But if your name is also on the banned list, the guest list does not matter. And a name that appears on neither list is simply turned away, even though nobody wrote “turn this person away”.
AWS decides every request the same way. Its policy evaluation documentation summarises the logic in three lines:
“By default, all requests are implicitly denied with the exception of the AWS account root user, which has full access. Requests must be explicitly allowed by a policy or set of policies … An explicit deny overrides an explicit allow.”
So, for an IAM user or role:
- Start at no. Every request begins denied.
- Look for a deny. If any applicable policy has a
Denystatement matching the request, the answer is no — final, whatever else says yes. - Look for an allow. If no deny matched, the request needs at least one statement that allows it. Without one, it stays at the starting no: an implicit deny.
Back to the fest: “nobody gets in” is the implicit deny, the guest list is an allow, and the banned list is an explicit deny.
A second way to see it: think of the three outcomes as three different error messages for three different fixes. An explicit deny means someone deliberately blocked this; adding another allow will not help, and you must find and change the deny. An implicit deny means nobody granted it; the fix is to add a correctly-written allow. Allowed means the policies are not your problem. The policy simulator reports exactly these three words, which is why you run it before guessing.
This explains the denial your hoc-practice user saw at the end of Unit 1: it had no policies at all,
so every request it sent stopped at rule 1.
The anatomy of a policy
Think of a policy as a printed permission slip with three blanks filled in: allowed or not, to do what, to which thing. Here is a real one, filled in to let someone read the files in one bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadOneBucket",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::hoc-site-ar-4821/*"
}
]
}
Versionis the version of the policy language, not of your policy. AWS says to always include it and set it to2012-10-17; with the older2008-10-17, features such as policy variables like${aws:username}are not recognised and are treated as plain text.Statementis a list of rules. A policy can hold several.Sidis an optional label so that you can tell statements apart.Effect,Action,Resourceare the heart of each rule: allow or deny, which operations, on which named resources.ActionandResourcecan each be a single string or a list.Principaldoes not appear in an identity-based policy, because the identity it is attached to is the principal. It appears in resource-based policies, such as a role’s trust policy, to say who the rule is about.
The order of elements inside a statement does not matter, and some pairs cannot appear together in
one statement — for example Action and NotAction.
A second way to read any policy is aloud, as one sentence per statement: “Allow s3:GetObject on
every object in hoc-site-ar-4821.” If you cannot say a statement as a sentence, you do not yet know
what it does.
Naming resources: ARNs
A postal address works because it narrows down step by step — country, state, city, street, house — until exactly one door matches. An ARN does the same for a resource in AWS: it is the full written name that a policy uses to point at exactly one thing, or at a pattern of things. AWS documents the general shape as:
arn:partition:service:region:account-id:resource
Some resources leave fields empty. Compare:
| Resource | ARN | Why it looks like that |
|---|---|---|
| An IAM user | arn:aws:iam::111122223333:user/hoc-admin |
IAM is global, so the Region field is empty |
| An S3 bucket | arn:aws:s3:::hoc-site-ar-4821 |
A general purpose bucket name is unique across all accounts and Regions within a partition, so Region and account are empty |
| Every object in that bucket | arn:aws:s3:::hoc-site-ar-4821/* |
The /* after the bucket name means every object key inside it |
| Objects under one prefix | arn:aws:s3:::hoc-site-ar-4821/private/* |
Only keys that begin with private/ |
A second way to picture it: the ARN is the address on the envelope, and a policy statement only delivers to the addresses written on it. A letter to “the house” does not reach “everyone inside the house”, and the reverse is also true.
Now the failure from the start of the unit makes sense. AWS’s own S3 example policy for one bucket
puts s3:ListBucket on arn:aws:s3:::amzn-s3-demo-bucket1 and s3:GetObject on
arn:aws:s3:::amzn-s3-demo-bucket1/*. Bucket-level actions take the bucket ARN; object-level actions
take an object ARN. The corrected policy has two statements:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListTheBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::hoc-site-ar-4821"
},
{
"Sid": "ReadItsObjects",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::hoc-site-ar-4821/*"
}
]
}
One warning about shortcuts. AWS documents that an incomplete ARN in an identity-based policy is
completed with wildcards, so arn:aws:sqs is treated as arn:aws:sqs:*:*:* — every queue in every
Region and account. A short ARN is not a narrow one.
Explicit deny in practice
Imagine you lend a friend your hostel room key so they can use anything in the room — except they must never throw away the files in one drawer. You do not list every allowed object; you give the broad permission and add one firm exception. Explicit deny is how you write that exception. Suppose a policy allows every S3 action on every object in the bucket but must protect one folder:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "arn:aws:s3:::hoc-site-ar-4821/*"
},
{
"Effect": "Deny",
"Action": "s3:DeleteObject",
"Resource": "arn:aws:s3:::hoc-site-ar-4821/private/*"
}
]
}
| Request | Decision | Which rule decided |
|---|---|---|
s3:DeleteObject on …/notes.txt |
allowed |
The first statement allows it; no deny matches |
s3:DeleteObject on …/private/keep.txt |
explicitDeny |
The second statement matches; it overrides the allow |
s3:GetObject on …/private/keep.txt |
allowed |
The deny is only for deleting |
s3:ListBucket on arn:aws:s3:::hoc-site-ar-4821 |
implicitDeny |
The allow names objects, not the bucket |
The last row is the opening failure again, hiding inside a policy that looks generous.
A second way to think about it: an explicit deny is a fence, and allows are gates. You can open as many gates as you like, but none of them lets anyone through the fence.
Identity-based and resource-based policies together
A library card says what a member may borrow anywhere; a sign on one shelf can also say “open to all visitors”. Either one can let you take a book from that shelf, and a “not for loan” label on the book beats both. AWS has the same two places for permissions.
Some resources carry their own policy — an S3 bucket policy is the common example. AWS documents that when a user or role in the same account requests such a resource, “the resulting permissions are the union” of the identity-based and resource-based policies: an allow in either is enough, and “an explicit deny in either of these policies overrides the allow”. Put as a rule of thumb: when checking a same-account request, look in two places for a yes and in two places for a no. Unit 3 uses a bucket policy to make a website readable by the public, and this rule is how you reason about it.
Roles: permissions without a password
At a hotel desk you are handed a key card programmed for certain doors. It is not anyone’s personal key: whoever is handed it can open those doors until the card expires, and the desk decides who may be handed one. A role is that key card. It is an identity with permission policies, like a user, but AWS describes the key difference: “a role does not have standard long-term credentials such as a password or access keys associated with it. Instead, when you assume a role, it provides you with temporary security credentials.” A role has two policies doing two jobs:
- its permissions policy says what the role may do;
- its trust policy says who may assume it — for example, the Lambda service or the EC2 service.
A second picture: a company car. No employee owns it; the transport desk decides who may sign it out,
and the car can only be driven where its permit allows. In later units your server and your function will each be handed a hoc- role
this way, so that no access key is ever stored on them — which is what AWS recommends: “Require
workloads to use temporary credentials with IAM roles to access AWS.”
Start broad, then narrow
A new intern is often given a visitor pass to the whole office on day one, and a badge for just their
team’s floor once everyone knows what they actually need. Permissions grow up the same way. AWS’s best
practices say to grant “only the permissions required to perform a task”, and describe a
path to get there: start with AWS managed policies, which “might not grant least-privilege permissions
for your specific use cases because they are available for use by all AWS customers”, and move to
customer managed policies written for your case. Your hoc-admin user is the broad start. The policy
you write in this unit’s project is the narrow end: one bucket, read only. Another way to see it: every
action a policy allows is something that a mistake, or a stolen credential, can also do.
The command line, signed in without keys
Picture a learner who pastes an access key into a script and pushes the script to a public code repository. Anyone who reads the file can now send requests as that user, and AWS describes access keys as “long-term credentials”: the key keeps working until it is deactivated or deleted. That is the risk the rest of this section avoids.
The AWS CLI sends the same requests as the console. To use it you need credentials. AWS now documents
aws login, which uses your existing console sign-in instead of an access key:
- It needs AWS CLI version 2.32.0 or later.
- It works for the root user, an IAM user or a federated identity. An IAM identity needs the
SignInLocalDevelopmentAccessmanaged policy or equivalent permissions;hoc-adminalready has them, becauseAdministratorAccessallows every action. aws loginopens your browser, you choose the console identity to use, and the CLI receives temporary credentials. It asks for a Region the first time; give it the Region you chose in Unit 1 (or, if you are starting here, the one Region you picked).- The CLI refreshes the credentials automatically every 15 minutes, for up to 12 hours at most; after
that you run
aws loginagain.aws logoutdeletes the cached credentials. - The result is stored as a profile in your CLI configuration with a
login_sessionline naming your identity’s ARN, and the temporary credentials are cached under~/.aws/login/cache.
A second way to compare the two: an access key is a house key you cut once and must remember to take
back; aws login is a guest pass that stops working on its own.
To check which identity the CLI is using, run:
aws sts get-caller-identity
It prints your account ID, a user ID and your ARN, and AWS notes it needs no permissions at all — which makes it the first command to run whenever something is denied: before asking “what am I allowed to do?”, ask “who am I?”.
Proving a policy before it touches anything: the policy simulator
Pilots practise an engine failure in a flight simulator, not in the air. The answer is the same as it
would be in a real cockpit, but nothing can crash. The IAM policy simulator evaluates policies against requests “without sending a real request to any
AWS service”. In Custom mode you paste a policy you are still drafting; nothing is saved to your
account. From the CLI, aws iam simulate-custom-policy does the same thing:
aws iam simulate-custom-policy \
--policy-input-list file://hoc-read-policy.json \
--action-names s3:ListBucket \
--resource-arns arn:aws:s3:::hoc-site-ar-4821
The answer for each action and resource is one of allowed, explicitDeny or implicitDeny — the
three outcomes from the start of this unit. A second way to use it: as a test suite for a policy. Write
down the requests that must be allowed and the ones that must be denied, then run all of them every
time you change the policy. file:// tells the CLI to read the value from a file
relative to your current directory. AWS also warns that simulator results “can differ from your live
AWS environment” in some advanced setups, so the simulator is your first check, not your only one.
Flashcards
Say the answer aloud before revealing it. Speaking it is what exposes the gaps that reading past a written answer hides.
What is the starting answer to every request from an IAM user?
No. Requests are implicitly denied until a policy allows them; only the root user starts with full access.
A request matches one Allow and one Deny statement. What happens?
It is denied. An explicit deny overrides any number of allows.
What is the difference between `implicitDeny` and `explicitDeny`?
Implicit: nothing allowed it, so you fix it by adding a correct allow. Explicit: a Deny statement matched, so another allow will not help — you must change the deny.
Why does `s3:ListBucket` on `arn:aws:s3:::bucket/*` not let you list the bucket?
Listing is a request about the bucket, whose ARN is arn:aws:s3:::bucket. The /* form names only the objects inside it, so the request matches no statement.
Why are the Region and account fields empty in an S3 bucket ARN?
A general purpose bucket name is unique across all accounts and Regions within a partition, so the name alone identifies the bucket.
What `Version` should every new policy use, and what breaks without it?
2012-10-17. With the older version, policy variables such as ${aws:username} are treated as plain text.
Why is there no `Principal` in an identity-based policy?
The identity the policy is attached to is the principal. Principal is used in resource-based policies, such as trust policies.
How is a role different from a user?
A role has no password or long-term access keys; whoever assumes it gets temporary credentials. A trust policy says who may assume it.
What does `aws login` need, and what does it give you?
CLI version 2.32.0 or later and a console identity with sign-in permissions. It gives the CLI temporary credentials that refresh automatically, so no access key is ever created.
Which command tells you which identity the CLI is acting as?
aws sts get-caller-identity. AWS notes it needs no permissions.
Does the policy simulator create or change anything?
No. It evaluates the policy without sending a real request, and a custom policy is not saved to your account.
Is `arn:aws:sqs` in an identity-based policy a narrow resource?
No. AWS completes an incomplete ARN with wildcards, so it means every queue in every Region and account.
Model answer
The question: “A teammate’s script gets an access-denied error when it lists a bucket, but their policy ‘allows S3 read’. Talk me through how you find the cause and fix it.”
A good answer covers five beats, in this order: who, what exactly, which kind of no, smallest fix, prove both sides. Missing one is a failure state: each beat removes one place the fault could be hiding, and a fix proposed before them is a guess. Spoken, it sounds like this:
“First, who: I run
aws sts get-caller-identitywith the script’s own profile, because if the script is running as a different user or role, everything after this answers the wrong question. Second, what exactly: I write the failing request as an action and a resource ARN —s3:ListBucketonarn:aws:s3:::the-bucket— rather than ‘reading the bucket’. Third, which kind of no: I put the policy and that request into the policy simulator. If it saysexplicitDeny, I go looking for the Deny statement; if it saysimplicitDeny, nothing matches, so I compare each statement’sResourcewith the request’s ARN — and here the policy names onlythe-bucket/*, the objects, not the bucket. Fourth, the smallest fix: I moves3:ListBucketinto its own statement on the bucket ARN and leaves3:GetObjecton the objects, without widening anything tos3:*. Fifth, I prove both sides: I re-run the simulator for the request that must now be allowed and for one that must still be denied, such ass3:DeleteObject, because a fix tested only on the failing case can quietly open something else.”
Beat five is the one most answers drop.
Why this matters
- “It works on my laptop but not on the server.” The two can be different principals — your user locally, a role on the server. Beat one finds out in a single command.
- A bucket accidentally made writable to everyone. A policy written with
s3:*and*to “just make it work” grants far more than reading. Least privilege is what stops a convenience becoming an incident. - A leaked access key in a public code repository. Long-term keys keep working until they are
deactivated or deleted. Temporary credentials from
aws loginand roles expire on their own, which is why AWS recommends them. - Explaining a permission to a teammate. “What wins, allow or deny?” and “why can’t this user list the bucket?” are questions you can now answer from the three rules and an ARN, and prove with the simulator rather than argue about.
After this unit
The project for this unit is Sign In, Then Prove a Policy (project.md). You will install the AWS
CLI and sign it in with aws login, write a read-only policy for the bucket you will create in Unit 3,
prove it with the simulator against requests that must be allowed and must be denied, store it in your
account as a customer managed policy, and then delete it and sign out.
Unit 3 creates that bucket for real, uploads a small website to it from the command line you set up here, and uses a bucket policy — a resource-based policy — to let the public read it.
Sources
All retrieved 2026-10-02.
- https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html — fetched 2026-10-02
- https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic_policy-eval-denyallow.html — fetched 2026-10-02
- https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html — fetched 2026-10-02
- https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_version.html — fetched 2026-10-02
- https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html — fetched 2026-10-02
- https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html — fetched 2026-10-02
- https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html — fetched 2026-10-02
- https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_testing-policies.html — fetched 2026-10-02
- https://docs.aws.amazon.com/IAM/latest/UserGuide/id_tags.html — fetched 2026-10-02
- https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AdministratorAccess.html — fetched 2026-10-02
- https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-policies-s3.html — fetched 2026-10-02
- https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html — fetched 2026-10-02
- https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sign-in.html — fetched 2026-10-02
- https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-parameters-file.html — fetched 2026-10-02
- https://docs.aws.amazon.com/cli/latest/reference/sts/get-caller-identity.html — fetched 2026-10-02
- https://docs.aws.amazon.com/cli/latest/reference/iam/simulate-custom-policy.html — fetched 2026-10-02
- https://docs.aws.amazon.com/cli/latest/reference/iam/create-policy.html — fetched 2026-10-02
- https://docs.aws.amazon.com/cli/latest/reference/iam/delete-policy.html — fetched 2026-10-02
- https://docs.aws.amazon.com/accounts/latest/reference/getting-started.html — fetched 2026-10-02
- https://docs.aws.amazon.com/IAM/latest/UserGuide/enable-virt-mfa-for-root.html — fetched 2026-10-02
- https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html — fetched 2026-10-02
- https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html — fetched 2026-10-02
- https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html — fetched 2026-10-02
- https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_remove.html — fetched 2026-10-02
- https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html — fetched 2026-10-02
Project
Hands-on Project — Sign In, Then Prove a Policy
Objective
Set up the AWS command line so that it holds only short-lived credentials, then write a read-only policy for the bucket you will create in Unit 3, prove with the policy simulator that it allows exactly what it should and denies everything else in a test list, store it in your account, and delete it again. You finish holding a working, signed-in command line and a tested policy file — and an account with nothing new left in it.
What this project needs: your hoc-admin user from Unit 1, a computer on which you can install the
AWS CLI, and a text editor. The project creates no server, storage or database: IAM is documented as
“offered at no additional charge”, and the policy simulator evaluates a policy “without sending a real
request to any AWS service” (see Sources).
If you do not have Unit 1’s setup. You need two things from it, and possibly an account first:
- No AWS account yet? Create one from
https://aws.amazon.com(Create account) following AWS’s sign-up steps, choosing the Free account plan when asked to choose your account plan. Then sign in as the root user, open your account name → Security credentials, and under Multi-Factor Authentication (MFA) choose Assign MFA device (see Sources). - An everyday administrator user. Sign in as the root user, open IAM → Users → Create user,
name it
hoc-admin, tick Provide user access to the AWS Management Console, choose I want to create an IAM user and a custom password. On Set permissions, create a grouphoc-adminswith the AWS managed policy AdministratorAccess and add the user to it. Sign in ashoc-adminathttps://<your-12-digit-account-id>.signin.aws.amazon.com/consoleand assign it an MFA device under Security credentials. - One Region. Pick one Region code — the examples use
ap-south-1— and use it for every unit.
Your evidence file. Keep one plain-text file, unit2-evidence.txt, with one key: value line for
each output below. The rule for each value is printed beside it, so you can check your own file.
Choose your bucket name now, because Unit 3 creates it with this exact name:
hoc-site-<your-initials>-<random-digits>, all lowercase — for example hoc-site-ar-4821. The
examples below use hoc-site-ar-4821; replace it with yours everywhere.
Task 1 — Install the CLI and sign it in without a key
Scope: one installed CLI, one signed-in profile, one identity check. Do not create an access key at any point.
-
Install the AWS CLI version 2 with one of the methods in the AWS install guide (Installing or updating to the latest version of the AWS CLI, see Sources). The guide’s installer packages are:
- Linux x86 (64-bit):
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip", thenunzip awscliv2.zip, thensudo ./aws/install - macOS: download and run
https://awscli.amazonaws.com/AWSCLIV2.pkg - Windows: download and run
https://awscli.amazonaws.com/AWSCLIV2.msi
The same guide also documents an install script, which it calls the recommended method on all three systems:
curl -fsSL https://awscli.amazonaws.com/v2/install.sh | bashon Linux and macOS, andirm https://awscli.amazonaws.com/v2/install.ps1 | iexin PowerShell on Windows. Use either route. - Linux x86 (64-bit):
-
Check the version:
aws --version.aws loginneeds 2.32.0 or later. If yours is older, update it by following the update instructions in the same install guide. -
Make sure you are signed in to the console as
hoc-adminin your browser, then run:aws loginWhen asked for a Region, enter the Region you chose in Unit 1 or in the setup path above (for example
ap-south-1). Your browser opens; choosehoc-adminand return to the terminal. -
Run
aws sts get-caller-identityand read theArnit prints. It should name the user you chose in step 3; if it names anything else, stop and work out why before continuing. -
Open your CLI configuration file —
~/.aws/configon Linux and macOS,%USERPROFILE%\.aws\configon Windows — and find thelogin_sessionline. Confirm that there is no~/.aws/credentialsfile containing an access key for this account.
Time budget: 30 minutes
Output: add these lines to unit2-evidence.txt:
| Line | Rule for the value |
|---|---|
cli-version: <value> |
the version number from aws --version, such as 2.32.4; three numbers, the first 2 |
caller-arn: <value> |
the Arn value copied from aws sts get-caller-identity |
login-session-line: <value> |
the whole line from your config file that begins login_session |
credentials-file-has-key: <value> |
yes or no: whether a credentials file for this account contains an access key |
Task 2 — Write the policy and prove it in the simulator
Scope: one policy file, eight simulated requests. Stop when you have recorded all eight.
-
In an empty folder, create
hoc-read-policy.jsonwith a policy whose intent is: its holder may list your bucket and read its objects, and do nothing else. Include"Version": "2012-10-17". Use the notes’ section on ARNs to decide which resource each action needs. -
From that folder, simulate each request below. One example:
aws iam simulate-custom-policy \ --policy-input-list file://hoc-read-policy.json \ --action-names s3:ListBucket \ --resource-arns arn:aws:s3:::hoc-site-ar-4821On Windows Command Prompt, put the command on one line instead of using
\. -
Record the
EvalDecisionthe simulator prints for each request:# Action Resource 1 s3:ListBucketarn:aws:s3:::hoc-site-ar-48212 s3:GetObjectarn:aws:s3:::hoc-site-ar-4821/index.html3 s3:GetObjectarn:aws:s3:::hoc-site-ar-4821/css/site.css4 s3:PutObjectarn:aws:s3:::hoc-site-ar-4821/index.html5 s3:DeleteObjectarn:aws:s3:::hoc-site-ar-4821/index.html6 s3:DeleteBucketarn:aws:s3:::hoc-site-ar-48217 s3:GetObjectarn:aws:s3:::some-other-bucket/index.html8 s3:ListBucketarn:aws:s3:::some-other-bucketCompare each decision with the policy’s intent from step 1. If any request your intent allows is not
allowed, or any request outside it isallowed, fix the policy and run all eight again. -
Break it on purpose. Change the resource of the statement that holds
s3:ListBucketto the/*object form, save, and re-run request 1. Write down the decision you get. Then put the resource back and re-run request 1 once more.
Time budget: 45 minutes
Output: keep hoc-read-policy.json, and add these lines to unit2-evidence.txt:
| Line | Rule for the value |
|---|---|
decisions: <value> |
eight values in request order, separated by commas, each one of allowed, explicitDeny, implicitDeny, copied from EvalDecision |
broken-request-1: <value> |
one of the same three words, copied from the run in step 4 |
policy-version: <value> |
the value of Version in your file |
Task 3 — Store it, look at it, delete it (the habit)
Scope: one customer managed policy, created and deleted. It is never attached to anyone.
-
Create the policy in your account, tagged for this course:
aws iam create-policy \ --policy-name hoc-read-site-bucket \ --policy-document file://hoc-read-policy.json \ --description "Read-only access to the hands-on-cloud site bucket" \ --tags Key=project,Value=hands-on-cloudCopy the
Arnfrom the output. -
In the console, open IAM → Policies, filter to Customer managed, and open
hoc-read-site-bucket. Read its JSON, its Tags tab and its list of attached entities. -
Delete it. The
delete-policyreference says a customer managed policy must first be detached from every identity and have only its default version; this one was never attached and has one version, so you can delete it directly:aws iam delete-policy --policy-arn <the Arn you copied>The command prints nothing when it succeeds.
-
Sign the CLI out:
aws logout. Then runaws sts get-caller-identityonce more and record the first line of what it prints.
Teardown checklist
Tick each line only after you have looked:
- IAM → Policies → Customer managed does not list
hoc-read-site-bucket. - IAM → Users lists
hoc-admin, and no user was created in this project. - No access key exists for
hoc-admin(IAM → Users → hoc-admin → Security credentials → Access keys is empty). -
aws logouthas been run, and you recorded whataws sts get-caller-identityprinted after it. -
hoc-read-policy.jsonis saved somewhere you can find it in Unit 3.
Time budget: 15 minutes
Output: add these lines to unit2-evidence.txt:
| Line | Rule for the value |
|---|---|
policy-arn: <value> |
the Arn from create-policy; it contains your 12-digit account ID and ends :policy/hoc-read-site-bucket |
policy-tag: <value> |
the tag shown on the policy’s Tags tab, written key=value |
policy-listed-after-delete: <value> |
yes or no: whether Customer managed policies list hoc-read-site-bucket after step 3 |
after-logout-first-line: <value> |
the first line aws sts get-caller-identity printed after aws logout, copied verbatim |
teardown-checklist: <value> |
the number of checklist lines above you ticked, out of 5 |
What this feeds
Unit 3 opens with aws login and aws sts get-caller-identity, then creates the bucket whose name you
chose above. hoc-read-policy.json is the identity-based half of that bucket’s access story; Unit 3
adds the resource-based half — a bucket policy — so that the public can read your website, and uses the
evaluation rules from this unit to explain why both halves together give the result they do.
Sources
Every AWS behaviour this project relies on comes from these pages, all fetched 2026-10-02:
- IAM is offered at no additional charge: https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html
- Creating an account and choosing its plan (recovery path): https://docs.aws.amazon.com/accounts/latest/reference/getting-started.html
- Assigning an MFA device to the root user (recovery path): https://docs.aws.amazon.com/IAM/latest/UserGuide/enable-virt-mfa-for-root.html
- Creating an IAM user with console access (recovery path): https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html and https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_sign-in.html
- Installing and updating the AWS CLI, including the install script and installers: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
aws login, its minimum CLI version, thelogin_sessionline andaws logout: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sign-in.htmlaws sts get-caller-identity: https://docs.aws.amazon.com/cli/latest/reference/sts/get-caller-identity.html- The policy simulator and
simulate-custom-policy: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_testing-policies.html and https://docs.aws.amazon.com/cli/latest/reference/iam/simulate-custom-policy.html - Reading a value from a file with
file://: https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-parameters-file.html - S3 resource ARNs for a bucket and its objects: https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-policies-s3.html
- Creating and deleting a customer managed policy: https://docs.aws.amazon.com/cli/latest/reference/iam/create-policy.html and https://docs.aws.amazon.com/cli/latest/reference/iam/delete-policy.html
- Tags on IAM resources: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_tags.html
Quiz
Online marking is not open yet. Work through the questions and check the written ones against the criteria printed with each question. The answer key is kept back for now.
Quiz — Unit 2: Who Can Do What: Identities and Permissions
Instructions: Ten questions in two parts, and both parts are scored.
- Questions 1–8 are multiple choice. Pick one option per question. They are marked by comparing your letter against the key.
- Questions 9–10 ask you to write an answer in an exact format. Question 9 prints the requests your policy is tested with, so you can run them yourself before you submit; question 10 states the format of its answer.
Work closed-book on questions 1–8 and 10. On question 9 you may run the policy simulator as often as you like; checking your own policy against the printed requests is part of the exercise. The answer key, which holds the marking rules, is held separately.
1. A request from an IAM user matches no statement in any policy that applies to it. What does AWS decide?
a) Allowed, because none of the applicable policies contains a statement that denies it b) Denied by an explicit deny, because AWS adds a hidden Deny statement for unmatched requests c) Denied by an implicit deny, because every request starts denied until a policy allows it d) Allowed for read-only actions, because only write actions need a matching Allow statement
2. One policy on a user allows s3:* on arn:aws:s3:::hoc-quiz-bucket/*. A policy on the user’s
group denies s3:DeleteObject on the same resource. The user tries to delete
hoc-quiz-bucket/a.txt. What happens?
a) It is denied, because an explicit deny overrides any allow from any policy
b) It is allowed, because a policy on the user outranks a policy on its group
c) It is allowed, because the broader s3:* statement is evaluated before a narrow one
d) It is denied only if the group policy was attached after the user’s own policy
3. You want a user to be able to list the objects in the bucket hoc-site-ar-4821. Which value
must the Resource of the s3:ListBucket statement match?
a) arn:aws:s3:::hoc-site-ar-4821/*
b) arn:aws:s3:ap-south-1::hoc-site-ar-4821
c) arn:aws:s3:::*/hoc-site-ar-4821
d) arn:aws:s3:::hoc-site-ar-4821
4. Why does AWS say every new policy should include "Version": "2012-10-17"?
a) A policy that leaves out the element is rejected when you try to attach it to an identity
b) Under the older version, policy variables like ${aws:username} are read as plain text
c) The value records the date you wrote the policy, and AWS evaluates newer policies first
d) Explicit deny exists only in that version, so older policies can never block a request
5. Which element would you expect to find in a role’s trust policy but not in an identity-based policy attached to a user?
a) Principal, which names who the statement is about
b) Effect, which says whether the statement allows or denies
c) Action, which lists the operations the statement covers
d) Version, which names the policy language the document uses
6. You have just run aws login, and the next command fails with an access-denied error. What is
the most useful command to run first?
a) aws configure, to paste in an access key that replaces the temporary credentials
b) aws logout --all, to clear every cached sign-in before you try the command again
c) aws sts get-caller-identity, to see which identity the CLI is acting as
d) aws iam create-policy, to grant the missing permission to whoever is signed in
7. In Custom mode, what does the IAM policy simulator do with the policy you paste into it?
a) It attaches the policy to your user for a moment and sends each test request to the service b) It evaluates it against your chosen requests without sending them, and saves nothing c) It saves the policy as a customer managed policy so that you can attach it after the test d) It sends each request to the service in a dry-run mode that rolls back any change it makes
8. A program you will run on an EC2 server needs to read objects from one bucket. Which approach matches AWS’s recommendation for credentials?
a) Create an access key for hoc-admin and copy it into a file on the server’s disk
b) Run aws login on the server as the root user so the program receives short-lived credentials
c) Create an IAM user for the server and store that user’s console password in a settings file
d) Give the server a role that allows the read, so it receives temporary credentials
Part 2 — Constructed response
9. Write an identity-based policy, as a single JSON document, that lets its holder list the
bucket hoc-quiz-bucket and read any object in it — and nothing else in the table below.
Your policy is tested by passing it to aws iam simulate-custom-policy once for each row below. Rows
in the left column should come back allowed; rows in the right column should not.
| Should be allowed | Should not be allowed |
|---|---|
s3:ListBucket on arn:aws:s3:::hoc-quiz-bucket |
s3:PutObject on arn:aws:s3:::hoc-quiz-bucket/index.html |
s3:GetObject on arn:aws:s3:::hoc-quiz-bucket/index.html |
s3:DeleteObject on arn:aws:s3:::hoc-quiz-bucket/index.html |
s3:GetObject on arn:aws:s3:::hoc-quiz-bucket/css/site.css |
s3:GetObject on arn:aws:s3:::other-bucket/index.html |
s3:ListBucket on arn:aws:s3:::other-bucket |
|
s3:DeleteBucket on arn:aws:s3:::hoc-quiz-bucket |
The document must also be valid JSON and carry "Version": "2012-10-17".
10. Here is a policy attached to a user, and four requests the user makes. For each request, in
order, write the simulator’s decision as exactly one of allowed, explicitDeny or implicitDeny,
separated by commas — for example allowed,allowed,allowed,allowed (that example is the format, not
the answer).
{
"Version": "2012-10-17",
"Statement": [
{ "Effect": "Allow", "Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::hoc-quiz-bucket/*" },
{ "Effect": "Deny", "Action": "s3:PutObject",
"Resource": "arn:aws:s3:::hoc-quiz-bucket/private/*" },
{ "Effect": "Allow", "Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::hoc-quiz-bucket" }
]
}
s3:PutObjectonarn:aws:s3:::hoc-quiz-bucket/private/a.txts3:GetObjectonarn:aws:s3:::hoc-quiz-bucket/private/a.txts3:DeleteObjectonarn:aws:s3:::hoc-quiz-bucket/a.txts3:ListBucketonarn:aws:s3:::hoc-quiz-bucket
Sources
All retrieved 2026-10-02:
- Policy evaluation logic (IAM): https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html
- Identify AWS resources with Amazon Resource Names (ARNs) (IAM): https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html
- Identity-based policy examples for Amazon S3: https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-policies-s3.html
- IAM JSON policy elements: Version: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_version.html
- IAM JSON policy element reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html
- Login for AWS local development using console credentials (AWS CLI): https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sign-in.html
- get-caller-identity (AWS CLI Command Reference): https://docs.aws.amazon.com/cli/latest/reference/sts/get-caller-identity.html
- IAM policy testing with the IAM policy simulator: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_testing-policies.html
- simulate-custom-policy (AWS CLI Command Reference): https://docs.aws.amazon.com/cli/latest/reference/iam/simulate-custom-policy.html
- IAM roles: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html
- Security best practices in IAM: https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html
TechEazy Consulting training material — not affiliated with or endorsed by Amazon Web Services (AWS).