Identity & Access Management
IAM, Identity Center, permission boundaries, and least privilege principles
ACTIVE PRACTICE Β· 15 practice questions
Make this lesson stick.
Test what you can recall and learn from the feedback. Come back to the lesson whenever you need an explanation.
Sign in to practice βGive the right identity just enough access
An application can reach S3 over the network and still receive AccessDenied. A developer can sign in successfully and still be unable to deploy. Authentication establishes an identity; authorization decides whether a particular request is permitted. Network reachability is a separate requirement.
In this lesson, a team gives an EC2 worker access to a DynamoDB table and a developer access to a deployment task. You will read policies, distinguish roles from their sessions, diagnose an MFA condition, and test both intended access and intended denials. AWS details were checked 14 September 2026. This is architectural practice, not a versioned certification syllabus.
1. Start with the identity and the session
For workforce access, normally use federation and temporary credentials, with centralized account access through IAM Identity Center where appropriate. A common Identity Center setup assigns users/groups permission sets that provision roles in target accounts. An Identity Center user or group is not the same object as an IAM user or IAM group. For workloads, prefer supported role-based temporary credentials. Current IAM guidance, permission sets
| IAM concept | What persists, and how it is used |
|---|---|
| User | An account identity that can have a password or long-term access keys. Creation does not automatically create either credential. Use when a specific need cannot use the preferred federation/role path. |
| Group | A collection of IAM users for permission management. It has no credentials, cannot contain roles or other groups, and cannot be a requesting principal. A user can belong to multiple groups. |
| Role | An identity with a trust policy and permissions. The role can persist until deleted; an assumed role session gets expiring credentials. A role is not itself a short-lived object. |
| Policy | Rules about actions, resources, principals or request context, depending on policy type. A policy is not an identity. |
IAM users and roles can receive identity-based policies. Policies attached to an IAM group contribute to its users' permissions. Managed policies are reusable policy objects; inline policies belong to one identity. AWS-managed policies can be broader than a particular job requires. Policies and permissions
For command recognition, this creates only an IAM user:
aws iam create-user --user-name alice-lab
It does not create a password, access keys or useful permissions. It is a legacy/lab concept to recognize, not the default onboarding instruction for every teammate. Protect any root credentials, use MFA, and reserve root access for tasks that specifically require it; routine billing administration can be delegated. CreateUser, root-user guidance
Temporary AWS credentials contain an access key ID, secret access key and session token, plus an expiration. Long-term IAM user access keys contain the ID and secret, without that session token. SDK credential providers can obtain and refresh role credentials; environment variables or another configured provider can take precedence. Never infer the active identity just from the presence of an attached role. Credential resolution
Try it: a role is created on Monday and assumed twice on Tuesday. Does it need to be recreated for Wednesday? Check: no. The role persists; each session has its own lifetime. Temporary credentials can still be stolen, and a compromised running workload may obtain fresh credentials. Expiration is not incident containment by itself.
2. Read the policy as a request filter
Ask which action, which resource, and under which conditions. Effect is Allow or Deny; Action identifies operations; Resource identifies their targets; an optional Condition tests request context. Version: "2012-10-17" selects the policy language version, not the policy's creation date. Policy elements
Suppose a job lists keys in a general-purpose bucket, then reads and writes its objects. It does not need deletion. The example uses the standard aws partition:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListThisBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::project-assets-example"
},
{
"Sid": "ReadWriteThisBucketObjects",
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::project-assets-example/*"
}
]
}
The bucket ARN and object ARN are different. s3:ListBucket lists keys and uses the bucket ARN; s3:GetObject reads an object and uses an object ARN. /* selects all object keys in that bucket; a single exact key or a narrower prefix can be used instead. Listing all buckets is a separate account-level action. This policy grants no delete action and no RDS action, but another applicable policy may grant them. A missing Allow in this one document is not a universal Deny. S3 actions and resources
An identity-based policy is attached to the identity, so it does not contain a Principal element. A resource-based policy, such as an S3 bucket policy, identifies its principal explicitly. For example, this statement could grant an existing role read access through a bucket policy:
{
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::123456789012:role/AssetReader"},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::project-assets-example/*"
}
This is a statement fragment, not a complete policy document. A role's trust policy is also resource-based: its resource is the role, and it identifies who may assume it. Identity versus resource policies
Evaluate all applicable controls
For ordinary IAM users and roles, the starting point is implicit denial. An applicable explicit Deny overrides an Allow. Whether an Allow is sufficient depends on the policy types, principal type, account relationship and service involved.
Identity/resource grants interact with limits such as permissions boundaries, session policies, organization service control policies (SCPs), resource control policies (RCPs), and endpoint policies where applicable. Restrictive controls do not independently grant the missing permission. Same-account resource-based grants have principal-specific evaluation rules; do not treat every policy as either a simple union or a simple intersection. Evaluation logic
For a simplified identity-only exercise with no additional grants or restrictions:
| Statements applying to the request | Result |
|---|---|
| No Allow | Implicit denial |
| Allow only | Allowed |
| Allow and explicit Deny | Explicit denial |
Action: "*", Resource: "*" is dangerously broad. It does not put an IAM identity above the root user or bypass explicit denials, organization restrictions or root-only operations.
3. Attach a role to EC2 through an instance profile
Our worker needs only GetItem and PutItem on one existing DynamoDB table. Save the following EC2 trust policy as ec2-trust.json if you later use the lab commands:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}
Save this permissions policy as worker-data.json, replacing the example account, Region and table name with your lab resources:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["dynamodb:GetItem", "dynamodb:PutItem"],
"Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/UserData"
}]
}
These are configuration fragments requiring an authenticated AWS CLI, suitable administrative permissions, unused role/profile names, and an existing EC2 instance in the specified Region with no current profile association. $LAB_INSTANCE_ID is a shell variable containing that real instance ID:
aws iam create-role --role-name WorkerDataRole \
--assume-role-policy-document file://ec2-trust.json
aws iam put-role-policy --role-name WorkerDataRole \
--policy-name WorkerDataAccess --policy-document file://worker-data.json
aws iam create-instance-profile --instance-profile-name WorkerDataProfile
aws iam add-role-to-instance-profile \
--instance-profile-name WorkerDataProfile --role-name WorkerDataRole
aws ec2 associate-iam-instance-profile --region us-east-1 \
--instance-id "$LAB_INSTANCE_ID" \
--iam-instance-profile Name=WorkerDataProfile
The profile and role names intentionally differ. Creating a role alone does not create a same-named instance profile when using these CLI operations. Allow for IAM propagation; if association reports a newly created profile is not yet visible, verify the profile/role and retry after propagation. The caller needs the applicable EC2 permissions and iam:PassRole for this role. An existing association needs the appropriate replacement operation. Instance profiles, PassRole
The trust policy permits EC2 to assume the role. The permissions policy permits the two table operations. An SDK using the instance-role provider obtains temporary credentials; it still needs a network path to DynamoDB. iam:PassRole authorizes handing a role to a service; it is not the same as calling sts:AssumeRole to become a role session.
4. Cross-account access needs both sides
Suppose an existing deployment role in account B (222222222222) needs to assume ProdDeploymentRole in account A (111111111111). Account A's trust statement can name that specific source role:
{
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::222222222222:role/DeploymentCaller"},
"Action": "sts:AssumeRole"
}
Account B must also authorize its caller to perform sts:AssumeRole on the target role ARN. After assumption, the target role's permissions and applicable session/organization restrictions determine the session's access. Merely possessing a role ARN is not authorization. An account principal ending in :root in a trust policy delegates to that account; it does not mean βonly that account's root user.β Cross-account roles
External ID is a different concern. A third-party provider serving many customers can be confused into acting for the wrong customer. A trust-policy condition on sts:ExternalId, using a unique customer identifier generated by the provider, helps bind the assumption to the intended customer. It is not a password or secret, and is not a replacement for a restricted trusted principal. Do not add it to every internal cross-account example and call the problem solved. External ID and confused deputies
AssumeRole returns temporary credentials; requested duration and the role's configured maximum matter. The API permits a requested duration starting at 900 seconds and up to the role's maximum (at most 12 hours). Role chaining has a one-hour session limit. Calling assume-role does not automatically install its returned credentials into subsequent CLI commands; use a configured role profile or handle the credential set securely. AssumeRole
5. Make the MFA condition match the promise
MFA combines factors; a password plus another password is not two-factor authentication. For IAM/root sign-in, supported options include passkeys/security keys and supported authenticator devices. AWS no longer supports enabling SMS MFA; migrate any existing SMS MFA assignments to supported alternatives. Prefer phishing-resistant MFA where supported, and configure federated authentication at the appropriate identity-provider/Identity Center boundary. IAM MFA
An IAM user enabling MFA does not make every request signed with that user's long-term access key MFA-authenticated. The aws:MultiFactorAuthPresent context key is not present in every credential flow, including many federation scenarios. It is not a universal detector of an identity provider's MFA event. MFA condition-key behavior
Consider an IAM-user policy exercise: describe instances without this MFA restriction, but require an MFA-authenticated session to stop one lab instance. Assume no other policies alter the result:
{
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Action": "ec2:DescribeInstances", "Resource": "*"},
{
"Effect": "Allow", "Action": "ec2:StopInstances",
"Resource": "arn:aws:ec2:us-east-1:123456789012:instance/i-0123456789abcdef0"
},
{
"Effect": "Deny", "Action": "ec2:StopInstances",
"Resource": "arn:aws:ec2:us-east-1:123456789012:instance/i-0123456789abcdef0",
"Condition": {"BoolIfExists": {"aws:MultiFactorAuthPresent": "false"}}
}
]
}
For stopping that instance, this Deny matches when the key is false or absent, and does not match when it is true. The Describe action is outside the Deny's action scope. A Deny does not grant anything; the separate Allow statements do that.
| MFA context | DescribeInstances | Stop the named instance |
|---|---|---|
true |
Allowed in this exercise | Allowed in this exercise |
false |
Allowed in this exercise | Explicitly denied |
| Key absent | Allowed in this exercise | Explicitly denied |
If the Deny used Action: "*" and Resource: "*", it would also block these read requests when the condition matches. An unconditional read Allow would not override it. Such a blanket policy can block credential/bootstrap operations too; do not paste it into a federation setup as a universal MFA solution.
6. Verify the job, including indirect privileges
Suppose the developer only updates code for an existing OrderHandler function. A starting grant is lambda:UpdateFunctionCode on that function ARN, with lambda:GetFunction if inspection is needed. Creating functions or changing their execution role is a different job; if required, scope the additional actions and iam:PassRole carefully. Do not grant lambda:* simply because the job mentions Lambda. Lambda permissions
No RDS API permission does not mean no database access. Someone who can replace a function's code can run code with that function's execution role, accessible secrets and network access. RDS database connections can also use database credentials rather than an rds:* API action. To exclude database access, review the execution role, secret access, database authentication, network path and which functions the developer can change. A broad role passed to a service can become an indirect privilege path.
Validate the policy syntax and findings with IAM Access Analyzer; simulate relevant actions, resources and contexts; then test allowed and denied cases safely in an isolated environment. Simulator outcomes can differ from live behavior and do not demonstrate network connectivity or application safety. Policy validation, simulator limitations
Review logs with CloudTrail, the activity-auditing service, rather than treating IAM itself as an all-purpose access log. Event history covers recent management events; data-event logging and longer retention need the appropriate configuration and may incur charges. IAM is provided at no additional charge, but that does not make associated logging, analysis features or resources free. CloudTrail event history, IAM pricing
When long-term keys remain necessary, inventory their use, update them when needed under your security policy, test replacements, and remove unused keys. A fixed βrotate every 90 daysβ instruction is not a universal AWS requirement. For a suspected leak, respond promptly; do not wait for the next rotation date. Remove lab-only user/profile/role resources after practice, checking their dependencies first.
Apply it: for one real task, write the caller identity, target action/ARN, credential source, applicable restrictions and an allowed/denied test pair. Then ask what the caller could do indirectly through the code or roles it controls. That is more informative than deciding whether a policy merely looks restrictive.