Amazon SCS-C02: Identity & Access Management — Study Guide

Part of the AWS Security Specialty SCS-C02 — Study Guide. Practice with verified answers in the Amazon exam hub, or take timed practice tests on ExamRoll.io.

Identities, Principals, and Policy Evaluation

IAM distinguishes between identities (users, groups, roles) and principals (the authenticated entity making a request). Users are long-lived with static credentials; roles have no credentials of their own and are assumed to yield short-lived STS tokens. Groups are containers for attaching policies to users — they are never principals and cannot be assumed.

Every API call passes through a deterministic evaluation chain: an explicit Deny anywhere wins, then SCPs at the organization level must allow, then permissions boundaries must allow, then session policies (if any) must allow, and finally at least one identity- or resource-based policy must contain an Allow. Missing any Allow layer results in an implicit deny. This is why layering matters: an identity policy granting s3:* is meaningless if an SCP denies s3:DeleteBucket or a permissions boundary omits S3 entirely.

Resource-based policies (S3 bucket policies, KMS key policies, SNS topic policies, Lambda function policies) can grant access directly to a principal without any identity policy on the caller’s side — within the same account. For cross-account access, both the identity policy in the source account and the resource policy in the target account must allow the action.

Roles, Trust Policies, and AssumeRole

A role has two policy documents: the trust policy (who may assume it) and one or more permissions policies (what they can do once assumed). The trust policy is a resource-based policy on the role itself, using the sts:AssumeRole action. Without a matching trust policy, AssumeRole fails with AccessDenied even if the caller has sts:AssumeRole in their identity policy.

For cross-account delegation, the trust policy names the trusted account or a specific role/user ARN in that account, and — critically for third-party access — enforces an ExternalId:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "AWS": "arn:aws:iam::111122223333:root" },
    "Action": "sts:AssumeRole",
    "Condition": {
      "StringEquals": { "sts:ExternalId": "unique-shared-secret-9271" }
    }
  }]
}

The ExternalId defends against the confused deputy problem: without it, a third-party SaaS provider assuming roles across many customer accounts could be tricked into acting on the wrong customer’s role. Omitting sts:ExternalId in the condition, or passing the wrong value during sts:AssumeRole, produces an AccessDenied on assume — a common misconfiguration when onboarding vendors like monitoring or CSPM tools.

For AWS services (Lambda, EC2, ECS tasks), the trust policy names a service principal, e.g. "Service": "lambda.amazonaws.com". A Lambda function needing S3 access should assume an execution role whose permissions policy grants s3:GetObject and s3:PutObject on the bucket; equivalently, an S3 bucket policy can name the function’s role ARN as principal. Either mechanism works alone within a single account.

Permissions Boundaries

A permissions boundary is an advanced control attached to a user or role that caps the maximum permissions that identity can ever have, regardless of what identity-based policies grant. The effective permissions are the intersection of the identity policy and the boundary. If a group policy grants ec2:* but the boundary only permits ec2:Describe*, the user can only describe.

Boundaries are commonly used for permission delegation: allow developers to create IAM roles for their applications, but require that every role they create carries a specific boundary. The IAM policy for the developer includes a condition like "iam:PermissionsBoundary": "arn:aws:iam::123456789012:policy/DevBoundary" on iam:CreateRole and iam:PutRolePolicy. This prevents privilege escalation while still enabling self-service.

A frequent misconception is that group membership or additional attached policies can “override” a boundary or SCP. They cannot — the boundary and SCP are ceilings, not floors.

MFA Enforcement Through Conditions

Two condition keys drive MFA policy: aws:MultiFactorAuthPresent (Boolean, true if the session was obtained using MFA) and aws:MultiFactorAuthAge (numeric, seconds since MFA was validated). Enforcing MFA for sensitive APIs and capping session lifetime looks like:

{
  "Effect": "Allow",
  "Action": ["rds:DeleteDBInstance", "kms:ScheduleKeyDeletion"],
  "Resource": "*",
  "Condition": {
    "Bool":            { "aws:MultiFactorAuthPresent": "true" },
    "NumericLessThan": { "aws:MultiFactorAuthAge": "7200" }
  }
}

Two hours is 7,200 seconds. Using BoolIfExists instead of Bool is subtly dangerous for service-principal calls that never carry the key — it evaluates to true and effectively bypasses the check for those callers, so prefer Bool when the intent is human-user enforcement.

Because CLI and SDK requests using long-term access keys do not carry MFA context, users must first call sts:GetSessionToken (with --serial-number and --token-code) or sts:AssumeRole with --serial-number/--token-code to obtain temporary credentials that include the MFA context. Those short-lived credentials then satisfy the MultiFactorAuthPresent condition:

aws sts get-session-token \
  --serial-number arn:aws:iam::123456789012:mfa/alice \
  --token-code 123456 \
  --duration-seconds 7200

IAM Identity Center and Federation

IAM Identity Center (formerly AWS SSO) centralizes workforce access across an AWS Organization. Permission sets are templates that Identity Center materializes as IAM roles inside each target account when a user or group is assigned. Assignments bind three things: a principal (user or group from the Identity Center directory or an external IdP like Okta/Entra ID), a permission set, and one or more accounts.

Permission sets can carry AWS-managed policies, customer-managed policies (referenced by name so they must exist in each target account), inline policies, and a permissions boundary. When you edit a permission set, Identity Center re-provisions the underlying roles — you never edit those roles directly.

For SAML federation outside Identity Center, AWS validates the assertion’s signature against the IdP metadata registered on the IAM SAML provider object. When the IdP rotates its signing certificate, uploading the updated metadata XML is required; otherwise STS returns InvalidIdentityToken / Response Signature Invalid. Updating the metadata with aws iam update-saml-provider --saml-metadata-document file://metadata.xml --saml-provider-arn ... is the minimum-overhead fix — no need to recreate the provider or reconfigure trust relationships.

Root Account, Credential Reports, and Least Privilege

The root user has unremovable full access and must be treated as a break-glass identity: enable a hardware or virtual MFA device, delete any root access keys, do not use it for daily work, and store credentials offline. Use SCPs at the organization root or OU level to prevent even administrators in member accounts from disabling GuardDuty, deleting CloudTrail, or leaving specific regions. SCPs never grant permissions — they only filter what IAM in the member account can grant.

Least privilege is operationalized with tools rather than intuition. Generate the IAM credential report (aws iam generate-credential-report then get-credential-report) to find unused users, ageing access keys, and users without MFA. Use IAM Access Analyzer to identify resource policies exposing data cross-account and to generate right-sized policies from CloudTrail activity. Use last-accessed data (aws iam get-service-last-accessed-details) to prune unused service permissions from roles.

A final trap worth naming explicitly: assuming that adding an identity Allow is sufficient. If a KMS key policy does not name your role, an SCP denies the action, or a permissions boundary omits it, the call still fails. Always audit the full stack — SCP, boundary, identity policy, resource policy, and session policy — when troubleshooting AccessDenied.

Practical Problem: Use-Case Scenario

Scenario: Meridian Financial operates a three-account AWS Organization for management, production, and development workloads, with sensitive trading and customer data in the prod account. They currently have a mix of legacy long-lived IAM users, contractor accounts, and an Okta SAML identity provider, producing inconsistent access controls and scattered role configurations across accounts.

Challenge: A recent incident involved a contractor’s compromised credentials that assumed a cross-account role without MFA and performed excessive actions because there were no permission boundaries or centralized permission sets. Meridian needs to harden federation, role trust, and enforce MFA and least privilege across accounts.

Recommended Approach:

  1. Deploy AWS IAM Identity Center integrated with Okta SAML as the single federated identity plane and migrate all human users and contractors from long-lived IAM users into Identity Center-based accounts, disabling console/keys for legacy IAM users.
  2. Create centralized permission sets in IAM Identity Center that map to IAM roles in member accounts and implement IAM permission boundaries (defined as IAM policies) for all roles; deploy these boundaries and role templates across accounts using AWS CloudFormation StackSets.
  3. Update cross-account role trust policies to only allow sts:AssumeRole from the Identity Center principal ARNs and include conditions requiring MFA (e.g., aws:MultiFactorAuthPresent) and source account restrictions; require session tags to carry identity attributes.
  4. Enforce MFA at the IdP (Okta) and reflect enforcement in AWS by requiring MFA conditions on role sessions; deny creation of console access or new IAM users by applying Service Control Policies (SCPs) in AWS Organizations.
  5. Enable AWS CloudTrail, AWS Config, and IAM Access Analyzer for continuous monitoring and policy validation, and send findings to CloudWatch/GuardDuty for alerting and automated remediation workflows.

Rationale: Centralizing federation via IAM Identity Center, enforcing least privilege with permission sets and boundaries, requiring MFA in trust policies, and applying org-level SCPs plus monitoring aligns with AWS best practices to reduce blast radius, prevent privilege escalation, and provide auditability.

IAM Roles and Trust Policies: PassRole and AssumeRole

An IAM role has two distinct policy surfaces, and confusing them is the root cause of most cross-account authorization failures. The trust policy (the AssumeRolePolicyDocument) answers who can assume the role and under what conditions. The permissions policy answers what the role can do once assumed. Both must permit the action; the trust policy alone never grants access to S3, KMS, or anything else.

When a principal calls sts:AssumeRole, STS evaluates the target role’s trust policy against the calling identity plus the session context (source IP, MFA state, session tags, external ID). The calling principal must also have an identity-based Allow for sts:AssumeRole on that role ARN. This dual requirement is what makes role assumption safe across account boundaries.

A canonical cross-account trust policy that requires MFA and an external ID looks like this:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "AWS": "arn:aws:iam::111122223333:root" },
    "Action": "sts:AssumeRole",
    "Condition": {
      "Bool": { "aws:MultiFactorAuthPresent": "true" },
      "NumericLessThan": { "aws:MultiFactorAuthAge": "3600" },
      "StringEquals": { "sts:ExternalId": "unique-partner-id-8842" }
    }
  }]
}

The aws:MultiFactorAuthPresent key is only meaningful in the trust policy of an assumable role, because MFA context is established at the STS call, not on downstream service calls. Adding MFA conditions to the S3 bucket policy or to the role’s permissions policy is a common mistake: the assumed-role session usually does not carry aws:MultiFactorAuthPresent=true even if the original human authenticated with MFA, so those conditions silently deny everything. Enforce MFA at assumption time; use aws:MultiFactorAuthAge to force re-authentication for long-lived sessions.

PassRole is the second gate that trips exam scenarios. When you tell a service like CloudFormation, EC2, Lambda, or CodeBuild to run as a role, the calling identity must have `iam:PassRole

Practical Problem: Use-Case Scenario

Scenario: Meridian Financial runs a multi-account AWS Organization with separate accounts for production, development, and CI/CD tooling; they use centralized IAM roles for cross-account deployments and third-party CI agents that assume roles to perform infrastructure changes. Identity boundaries are enforced by role trust policies and some teams use long-lived instance profiles and Lambda functions that are granted iam:PassRole to attach roles to instances or tasks.

Challenge: A recent audit found an overly-broad iam:PassRole permission allowed a CI/CD principal to pass an Administrator role to an EC2 instance profile, and an attacker exploited an AssumeRole trust to obtain excessive privileges across accounts.

Recommended Approach:

  1. Use AWS CloudTrail and Amazon EventBridge to identify recent iam:PassRole and sts:AssumeRole API calls, and run queries in CloudTrail Lake or Athena to list which principals passed which Role ARNs and when.
  2. Run IAM Access Analyzer (for IAM) across accounts to discover resource-based trust policy exposures and list roles that are assumable from outside the Organization or by external principals.
  3. Replace wide iam:PassRole policies with least-privilege IAM policies that specify exact Role ARNs in Resource, and add condition keys such as aws:PassedToService or aws:PrincipalOrgID to limit who and what can receive the role.
  4. Harden role trust policies to require conditions—use aws:PrincipalOrgID, sts:ExternalId for third parties, require aws:SourceIdentity and enforce maximum session durations—to prevent broad AssumeRole by unknown principals.
  5. Configure Amazon EventBridge rules to detect iam:PassRole and AssumeRole anomalies, send alerts to Amazon SNS and create automated Lambda playbooks to revoke or remediate overly-broad policies, and record findings in AWS Security Hub and AWS Config for continuous compliance.

Rationale: This approach enforces the principle of least privilege and defense-in-depth by tightening PassRole targets and trust policies, while enabling detection and automated remediation through logging and monitoring—aligned with AWS best practices for IAM and federation.


All domains · Threat Detection

Practice these questions → · Timed practice on ExamRoll.io →

Pass the whole exam — not just this question

You found this answer. Get every verified question and explanation in one place, and save hours of prep. Free to start.

Pass your exam →

Browse Amazon →

Related guides

All-in-one access

One subscription. Every exam.

Every plan unlocks unlimited answer search, practice tests, AI explanations, and the full resource library — in 20+ languages.

Monthly
24.87
Just €0.83/day
Everything included:
  • Unlimited answer search
  • Unlimited practice tests
  • AI-powered explanations
  • Full resource library
  • 20+ languages
  • Weekly content updates
  • Rewards & referrals
  • Priority support
Start free trial

No credit card required*

Best value
12 months
179.87
Just €0.49/daySave 40%
Everything included:
  • Unlimited answer search
  • Unlimited practice tests
  • AI-powered explanations
  • Full resource library
  • 20+ languages
  • Weekly content updates
  • Rewards & referrals
  • Priority support
Start free trial

No credit card required*

✓ Free plan included · ✓ Cancel anytime · ✓ All plans unlock the full product