Servisphere

Module 2 · SAA-C03

IAM and access management

Users, groups, roles, policies, how AWS evaluates permissions, temporary credentials via STS, multiple accounts with Organizations and IAM Identity Center.

  • DomainSecure architectures
  • 12 diagrams
  • 10 scenarios
  • 9 services

5-minute essentials

  1. By default every request is denied (implicit deny); you need at least one matching Allow, and an explicit Deny in any policy beats every Allow.Reading a permissions question: look for Deny first, then SCP, then resource / identity policy, permissions boundary, session policy.
  2. User = long-term identity (password, access key); role = an identity you "borrow" with temporary credentials from STS.AWS recommends roles and federation over long-term access keys; applications on EC2 / Lambda / ECS always use roles.
  3. EC2 gets permissions through an instance profile (a role attached to the instance); the SDK fetches temporary credentials from instance metadata automatically.The answer "store access keys in a config file on EC2" is always wrong.
  4. A role has a trust policy (who can assume it) and a permission policy (what it can do once assumed).To let account B into account A: create a role in A that trusts B; the person in B needs sts:AssumeRole permission on that role. For third parties, add an External ID.
  5. Resource-based policies (bucket policy, key policy, queue policy, etc.) have a Principal element and allow cross-account access without assuming a role.Cross-account with a resource policy: the caller keeps its own permissions; with a role: the caller switches to the role's permissions.
  6. An Organizations SCP sets a permission ceiling for users / roles in member accounts and grants nothing; it does not apply to the management account or service-linked roles."Prevent every account from turning off CloudTrail / using Regions outside an allowed list" → an SCP with Deny attached to an OU or the root.
  7. A permissions boundary sets a ceiling for one specific user / role; effective permissions = the intersection of the identity policy and the boundary.Let developers create roles themselves without escalating privileges: require new roles to have the boundary attached.
  8. IAM Identity Center: single sign-on to multiple accounts in Organizations, permissions assigned through permission sets, can connect to an external IdP (Entra ID, Okta, etc.).Employees use their company account to reach many AWS accounts: Identity Center is the modern answer, instead of creating IAM users in each account.
  9. A Cognito user pool is a user directory (sign-up, sign-in, MFA, social login); an identity pool exchanges that identity for temporary AWS credentials.A mobile / web app whose customers access S3 or DynamoDB directly: Cognito, not IAM users.
  10. Protect the root user: enable MFA, create no access keys, and use it only for the few tasks that require it.Daily work uses users / roles with least privilege; root is only for tasks like changing the support plan or closing the account.
  11. A role's temporary credentials last 1–12 hours depending on configuration; role chaining (assuming another role from a role) is limited to 1 hour.A session cut off after 1 hour even though 12 hours was set: usually caused by role chaining.
  12. IAM Access Analyzer finds resources shared outside the zone of trust (account / organization) and validates policies before you apply them."Find buckets, keys and roles that allow outside access" → Access Analyzer.
  13. Policy Conditions: aws:SourceIp, aws:MultiFactorAuthPresent, aws:RequestedRegion, aws:PrincipalOrgID, tags (ABAC), etc.Tag-based permissions (ABAC) need fewer policies as projects grow; aws:PrincipalOrgID shares with a whole organization without listing each account.

Diagrams

How AWS evaluates a request

How AWS evaluates a request1no2yes3yes4yes4yes4yes12no3RequestExplicit Deny?SCP / RCP allows?Identity / resourcepolicy allows?Boundary allows?Session policy?ALLOWDENY
An explicit Deny anywhere means immediate denial. After that each guardrail layer (SCP, boundary, session policy) must allow, and there must be at least one Allow from an identity or resource policy.

Step by step

  1. A Deny in any applicable policy → DENY immediately.
  2. The organization's SCP / RCP does not allow → DENY.
  3. No Allow from any identity or resource policy → DENY (implicit deny).
  4. The permissions boundary and session policy (if present) must also allow → ALLOW.

EC2 calls S3 with a role, no access key needed

EC2 calls S3 with a role, no access key neededVPCattached1get credentials2call API w/ temp creds3App on EC2Instance metadatatemp credentialsRole (instance profile)s3:GetObjectS3
The role is attached to EC2 via an instance profile. The SDK gets temporary credentials from instance metadata; AWS refreshes them before they expire.

Step by step

  1. The role is attached to EC2 via an instance profile; permissions live in the role's permission policy.
  2. The SDK reads temporary credentials from instance metadata automatically (IMDSv2).
  3. Calls S3 with temporary credentials; no long-term key exists on the instance.

A person in account B uses a role in account A

A person in account B uses a role in account AUser in account BSTSRole in account AS3 in account A1. AssumeRole (role ARN, External ID if any)2. Does the trust policy allow account B?3. Temporary role credentials4. Call API with the role's permissions
Two halves are needed: the role's trust policy in A trusts account B, and the person in B has sts:AssumeRole permission on that role.

Permissions boundary: effective permissions are the intersection

Permissions boundary: effective permissions are the intersectionIdentity policy allowsPermissions boundary allowsiam:CreateUseridentity only: blockeds3:GetObjectboth: allowedec2:TerminateInstancesboundary only: none
The identity policy grants, the boundary sets the ceiling. An action is allowed only when it is in both.

An SCP sets the ceiling for a whole OU

An SCP sets the ceiling for a whole OUOrganization11inherits22Management accountSCP not appliedRootProd OUSCP: Deny non-ap-*Dev OUApp accountData accountSandbox
An SCP attached at the root / OU is inherited by every account below. The management account is not restricted by SCPs.

Step by step

  1. Accounts are placed in OUs; SCPs are attached at the root or an OU.
  2. Every account in the Prod OU inherits the SCP: no one (even that account's root user) can use Regions outside the list.

IAM Identity Center: one sign-in, many accounts

IAM Identity Center: one sign-in, many accountsOrganizationsign in1SAML / SCIM1222EmployeeCorporate IdPEntra ID / OktaIAM Identity Centerpermission setProdReadOnlyDevPowerUserLogAudit
Users / groups come from the corporate IdP. A permission set assigned to a group on each account becomes a role in that account.

Step by step

  1. Employees sign in with their corporate account; groups sync to Identity Center (SCIM).
  2. Each group has a different permission set per account; when someone leaves, disable them in the IdP.

SAML 2.0 federation into the console

SAML 2.0 federation into the consoleEmployeeIdP (AD FS)Sign-in / STSAWS Console1. Sign in with corporate account2. SAML assertion (group → role)3. AssumeRoleWithSAML4. Temporary credentials5. Enter console with the role's permissions
No IAM users for employees: AD authenticates, AWS issues temporary credentials per the role mapped from the group.

Cognito: app customers access S3

Cognito: app customers access S3Mobile appUser poolIdentity poolS31. Sign in (password / Google / MFA)2. ID token (JWT)3. Exchange token for AWS credentials4. Temporary role credentials5. PUT to own prefix
The user pool handles sign-in; the identity pool exchanges the token for temporary role credentials, with a policy restricted by user ID.

IAM Access Analyzer finds external access

IAM Access Analyzer finds external accessZone of trust (organization)11reads policy1bucket policy allows2external access2Access AnalyzerBucketKMS keyRoleExternal accountFinding
The zone of trust is an account or a whole organization. Any policy that lets a principal outside that zone in becomes a finding.

Step by step

  1. Access Analyzer analyzes the policies of buckets, keys, roles, queues, etc.
  2. A bucket policy granting an account outside the organization → generates a finding to review and fix.

ABAC: tag-based permissions, one policy for all projects

ABAC: tag-based permissions, one policy for all projectsattach1attach1allowed (tag match)2denied2allowed2add instance3One shared policyResourceTag = PrincipalTagHeart team roleproject = heartStar team roleproject = starEC2 Heartproject = heartEC2 Starproject = starNew EC2project = heart
One shared policy allows an action when the principal's tag matches the resource's tag (aws:PrincipalTag vs aws:ResourceTag). Add a new instance with the right tag and it is covered immediately, with no policy edits as in role-based access control (RBAC).

Step by step

  1. Both roles share one policy; the condition compares the role's project tag with the resource's project tag.
  2. The Heart role can act only on resources with project = heart; Star's instances are denied.
  3. Create a new instance tagged project = heart: the Heart team has access immediately, nobody edits a policy.

Sign in to RDS with IAM, no password

Sign in to RDS with IAM, no passwordApp on EC2IAMRDS (MySQL / PostgreSQL)1. Get role temp credentials (instance profile)2. Temp credentials3. Sign token locally (SigV4), lasts 15 min4. TLS connection, token instead of password5. Verify rds-db:connect permission6. Open connection; token expiry won't cut open sessions
The SDK signs the auth token with Signature V4 from the role's credentials; it lasts 15 minutes and is used only when opening a connection. The connection must use SSL/TLS. Supports MariaDB, MySQL, PostgreSQL.

Choosing how to grant AWS access

Choosing how to grant AWS accessCode on AWS1App users2Employees3Other account4Yes3No3Who (or what) needs access?IAM roleCognitoMultiple accounts inOrganizations?Cross-account roleIAM Identity CenterSAML 2.0 + STS
The first question is always: who (or what) needs access. Do not create long-term access keys for code running on AWS, and do not create IAM users for each of an application's customers.

Step by step

  1. EC2, Lambda, ECS: attach a role (instance profile, execution role, task role); never embed access keys in code.
  2. Customers of a web / mobile app: Cognito user pool for sign-in, identity pool to exchange for temporary AWS credentials.
  3. Employees: for many accounts use IAM Identity Center (single sign-on); for one account with a corporate IdP use SAML 2.0 federation via STS.
  4. Another AWS account or a partner: a role with a trust policy for that account; for third parties add an External ID.

Quick comparisons

Policy types

TypeAttached toGrants permissions?Use when
Identity-basedUser, group, roleYesGrant permissions to identities in the account
Resource-basedBucket, key, queue, topic, role (trust), etc.Yes (including cross-account)Let a principal in another account into a resource
Permissions boundaryUser, roleNo, only sets a ceilingDelegate role creation without privilege escalation
SCP (Organizations)Root, OU, accountNo, only sets a ceilingGuardrail for a whole account / OU
RCP (Organizations)Root, OU, accountNo, only sets a ceilingGuardrail on resources in the organization
Session policyAssume-role / federation sessionNo, only sets a ceilingNarrow permissions for a single session

Cross-account access

Assume roleResource-based policy
How it worksThe caller switches to the permissions of a role in the target accountThe resource itself grants access to a principal in another account
Permissions in the home accountSet aside during the sessionKept (e.g. copying from bucket A to bucket B in one operation)
Supported servicesAll servicesOnly services with resource policies (S3, SQS, SNS, KMS, Lambda, etc.)
Third partyAdd an External ID to prevent the confused deputy problemUse the aws:SourceAccount / SourceArn conditions

Identity by audience

WhoUseNotes
Employees, multiple accountsIAM Identity Center (+ corporate IdP)Permission set → role in each account
Employees, one account, with ADSAML 2.0 federation → AssumeRoleWithSAMLOr Identity Center connected to AD
Applications on EC2 / ECS / LambdaRole (instance profile, task role, execution role)Never store access keys
Customers of a web / mobile appCognito user pool + identity poolSocial login, MFA
Servers outside AWSIAM Roles Anywhere (X.509 certificates)Replaces long-term access keys
Emergency situationsBreak-glass IAM user with MFALock down tightly, monitor

Organizations and Control Tower

OrganizationsControl Tower
What it isGroups accounts into an OU tree, consolidated billing, SCP / RCPBuilds a multi-account landing zone following best practices
GuardrailsYou write your own SCPsBuilt-in controls (preventive = SCP, detective = Config)
Use whenYou need flexible controlYou need to stand up a standards-compliant multi-account environment quickly

Exam scenarios

1An application on EC2 needs to read an S3 bucket.

Show answer

Right: A role with s3:GetObject on the bucket, attached to EC2 via an instance profile
The SDK fetches temporary credentials from metadata; AWS rotates them automatically.

Wrong: Create an IAM user and store the access key in a config file on the instance
Long-term keys leak easily and you must rotate them yourself.

Wrong: A bucket policy allowing every principal
Opens the bucket to the whole world.

2A user has the AdministratorAccess policy but still cannot turn off CloudTrail in a member account.

Show answer

Right: An SCP denies cloudtrail:StopLogging at the OU / root
An SCP sets the ceiling for every user and role (including root) of member accounts; Deny beats every Allow.

Wrong: Missing the cloudtrail:StopLogging permission
AdministratorAccess already includes it; the permission is blocked at a higher layer.

3An auditing firm (third party) needs to read resources in your account.

Show answer

Right: A role their account assumes, with a trust policy requiring an External ID
Temporary credentials that can be revoked; the External ID prevents the confused deputy problem.

Wrong: Create an IAM user and send them the access key
Long-term keys end up outside your control.

4Let developers create Lambda roles themselves but not roles with more privileges than their own.

Show answer

Right: Permissions boundary: allow iam:CreateRole only when the new role has the specified boundary attached
The new role's effective permissions never exceed the boundary.

Wrong: Just tell developers not to attach AdministratorAccess
Nothing prevents it.

Wrong: SCP
An SCP applies to the whole account and does not distinguish who created a role.

5500 employees sign in with Microsoft Entra ID accounts to reach 40 AWS accounts.

Show answer

Right: IAM Identity Center connected to Entra ID, assigning permission sets to groups per account
Single sign-on, group-based permissions; when someone leaves, disabling them in the IdP removes access.

Wrong: Create an IAM user for each person in each account
20,000 users, unmanageable, plus long-term keys.

6A mobile app lets users sign in with Google and upload photos to their own folder in S3.

Show answer

Right: Cognito user pool (Google sign-in) + identity pool issuing a temporary role; policy restricts the prefix by user ID
Each person gets temporary permissions only on their own folder.

Wrong: Embed an access key in the app
Anyone who unpacks the app can get the key.

7You need to know which buckets, KMS keys and roles allow access from accounts outside the organization.

Show answer

Right: IAM Access Analyzer with the organization as the zone of trust
Analyzes policies automatically and reports a finding for each outside access path.

Wrong: Read each policy manually
Cannot keep up with many resources and is easy to miss something.

8Share a bucket with every account in the organization, including accounts created later.

Show answer

Right: A bucket policy with the aws:PrincipalOrgID condition equal to the organization ID
New accounts in the organization get access automatically; outside accounts do not.

Wrong: List each account ID in the bucket policy
You must edit the policy every time there is a new account.

9A script assumes role A, then from A assumes role B with DurationSeconds of 4 hours, and fails.

Show answer

Right: Role chaining limits the session to a maximum of 1 hour
For a longer session: assume B directly with the original identity.

Wrong: Role B has a max session duration of 1 hour
Possible, but here the reason is certainly role chaining.

10MFA must be required to delete objects in an important bucket.

Show answer

Right: A policy that Denies s3:DeleteObject when aws:MultiFactorAuthPresent is not true (and consider MFA Delete when versioning is enabled)
The MFA condition applies to exactly the action to protect.

Wrong: Only enable MFA for console sign-in
It does not bind individual API operations.

Quick picks

What do you use to grant / limit permissions?

When you needUse
An application on EC2 / Lambda / ECS needs to call AWSRole (instance profile, execution role, task role) · see diagram
A person in another account needs accessRole + trust policy (third party: External ID) · see diagram
Let another account use a resourceResource-based policy (bucket / key / queue policy) · see diagram
Forbid an action for a whole account / OUSCP · see diagram
Limit the permission ceiling of one user / rolePermissions boundary · see diagram
Employees sign in once to many accountsIAM Identity Center · see diagram
Sign in with corporate AD to one accountSAML 2.0 federation · see diagram
Customers of a web / mobile appCognito user pool + identity pool · see diagram
Find resources shared externallyIAM Access Analyzer · see diagram
Understand why a request was deniedFollow the policy evaluation order · see diagram

Common pitfalls

  • Storing access keys on EC2 or in code instead of using a role.
  • Thinking an SCP grants permissions: an SCP only sets a ceiling; you still need an identity policy.
  • Thinking an SCP can restrict the management account: it does not apply to the management account.
  • Forgetting that an explicit Deny beats every Allow, even AdministratorAccess.
  • Letting a third party assume a role without an External ID.
  • Using root for daily work, or creating access keys for root.
  • Using IAM users for an application's customers (that is Cognito's job).
  • Mixing up a user pool (sign-in) with an identity pool (exchange for AWS credentials).
  • Listing each account in a bucket policy instead of using aws:PrincipalOrgID.
  • Thinking a permissions boundary grants extra permissions.
  • Forgetting that role chaining limits the session to 1 hour.

Services in this module

Numbers that change (checked against AWS docs)

  • Defaults: 20 managed policies per role (max 25), 10 per user (max 20), 10 per group; 1,000 roles per account (max 10,000). checked 2026-10-16 ↗
  • A managed policy is at most 6,144 characters; total inline policy size: user 2,048, group 5,120, role 10,240 characters (excluding whitespace). checked 2026-10-16 ↗
  • A role session ranges from 15 minutes up to 12 hours depending on max session duration; the default is 1 hour if unspecified. checked 2026-10-16 ↗
  • Role chaining limits the session to a maximum of 1 hour, regardless of the role's max session duration. checked 2026-10-16 ↗
  • Evaluation order: explicit Deny → RCP → SCP → resource-based → identity-based → permissions boundary → session policy; an explicit Deny beats every Allow. checked 2026-10-16 ↗
  • SCPs grant no permissions, do not apply to users / roles of the management account or to service-linked roles; they do apply to the root user of member accounts. checked 2026-10-16 ↗
  • An SCP is at most 10,240 characters; at most 10 SCPs attached directly to the root, each OU and each account; OUs nest up to 5 levels. checked 2026-10-16 ↗
  • Organizations allows at most 10 accounts by default (can be raised via Service Quotas). checked 2026-10-16 ↗
  • ABAC: one policy allows an action when the principal's tag matches the resource's tag; adding new resources needs no policy change. checked 2026-10-19 ↗
  • RDS IAM database authentication: a token signed with Signature V4 that lasts 15 minutes, for MariaDB, MySQL, PostgreSQL; the connection is encrypted with SSL/TLS. checked 2026-10-19 ↗
Practice this module →