Designing Secure Access: IAM Best Practices, Roles, and AWS Organizations
Designing secure access to AWS resources means deciding who or what can call which AWS APIs, with which credentials, under which guardrails — and it is SAA-C03 Task 1.1. The task covers hardening root and IAM users, building an authorization model from users, groups, roles and policies, choosing roles and temporary STS credentials over long-lived keys, granting cross-account access with IAM roles or resource-based policies, federating a workforce through IAM Identity Center, and governing many accounts with AWS Organizations, SCPs, RCPs and AWS Control Tower. The questions are rarely about what IAM is — they hand you a working setup and ask which access design is most secure, needs the least operational overhead, or follows least privilege. By the end of this lesson you will be able to pick the right identity mechanism for any actor — a human, an application on or off AWS, another account, or a third-party SaaS — and the right guardrail layer for any organizational restriction, and explain why the alternatives lose.
On this page12 sections
- The hardening baseline: root users, MFA, and least privilege
- Designing a flexible authorization model: users, groups, roles, and policy types
- How IAM policy evaluation decides: explicit deny, allows, and boundaries
- Least privilege in practice: IAM Access Analyzer and last accessed data
- Roles and STS: temporary credentials beat access keys
- Role sessions: switching, chaining, source identity, and revocation
- Cross-account access: IAM roles vs resource-based policies
- Federation and IAM Identity Center: workforce access at scale
- Multi-account design: AWS Organizations, OUs, and SCPs
- AWS Control Tower: governed multi-account setup without the assembly
- Decision tables: the right access pattern and the right guardrail
- Worked scenarios: reasoning through Task 1.1 questions
- Choose between IAM roles, IAM users, IAM Roles Anywhere and IAM Identity Center for any actor that needs AWS access
- Design an authorization model from groups, roles and the right policy type (AWS managed, customer managed, inline)
- Design cross-account access and decide when an assumed role beats a resource-based policy
- Distinguish SCPs, RCPs, identity-based policies and permissions boundaries by what each can and cannot do
- Design a multi-account structure with AWS Organizations OUs, SCP and RCP guardrails, and AWS Control Tower controls
- Apply IAM policy evaluation logic and condition keys (MFA, Region, external ID, permissions boundary) to predict and enforce outcomes
- Harden root users, enforce MFA and tighten permissions toward least privilege with IAM Access Analyzer
The hardening baseline: root users, MFA, and least privilege
Every access design starts from the same baseline: harden the root user, require MFA for people, and grant only the permissions each identity needs. The root user of each account is hardened first: enable MFA on it, delete any root access keys, and stop using it for daily work — create a separate administrative identity (with its own MFA) for console and CLI administration. When a scenario mentions that administrators "sign in with the root user" or that "root access keys are embedded in a script," that detail is the vulnerability the question wants fixed, regardless of what else is going on.
Root exists for a short list of root-only tasks that no IAM policy can delegate, for example: changing the account's root email or password, closing the account, restoring permissions when the only IAM administrator has locked themselves out, and editing or deleting an S3 bucket policy (or SQS queue policy) that denies every principal. That last one matters in design questions: a bucket policy with an explicit deny for * also blocks every IAM administrator, and no larger IAM policy can out-allow it — only root can remove it.
Centralized root access for member accounts
In an AWS Organization, every member account historically had its own root password to vault and protect. Centralized root access management (an IAM feature, enabled from the management account or a delegated administrator with trusted access for IAM) lets you delete the root credentials of member accounts and stop new member accounts from getting them. When a root-only task is still needed — such as unlocking a bucket policy that denies everyone — an authorized principal in the management account or the delegated administrator account calls sts:AssumeRoot with a narrowly scoped task policy (for example S3UnlockBucketPolicy) and gets a short-lived root session in that one member account for that one task. That is stronger and far less work than keeping dozens of root passwords and MFA devices.
MFA: registered is not the same as enforced
For human IAM identities the baseline is MFA everywhere — but a registered MFA device only protects you if a policy requires it. The IAM password policy has no MFA setting; MFA is enforced through the global condition key aws:MultiFactorAuthPresent in the policy that authorizes the action:
- For role assumption, put the condition in the role's trust policy (allow
sts:AssumeRoleonly whenaws:MultiFactorAuthPresentis true). That is where "who may assume this role, and how" is decided. - For a "deny unless MFA" statement, use
BoolIfExists, notBool. Requests signed with a user's long-term access keys carry noaws:MultiFactorAuthPresentkey at all. WithBooland"false", a missing key does not match, so the deny never applies and the CLI call gets through;BoolIfExiststreats the missing key as a match and denies it. - For "recent MFA", use
aws:MultiFactorAuthAge, the number of seconds since the MFA sign-in, withNumericLessThan(for example 3600 for "within the last hour"). Present answers whether MFA happened; Age answers how long ago.
Least privilege and the shared responsibility line
Least privilege at Associate level is a design discipline: scope policies to the specific actions, resources and conditions a workload needs. An application that reads one DynamoDB table gets dynamodb:GetItem on that table's ARN, not dynamodb:* on *. Broad grants such as AdministratorAccess or wildcard resources are almost always the marker of a wrong answer when a tighter option exists; the tooling for getting there is covered below.
Under the shared responsibility model, AWS operates IAM, STS and Organizations as services, but every identity you create, every policy you write, MFA enforcement, offboarding leavers and every trust relationship are the customer's side of the line. The same holds for leaked credentials: if an access key is exposed publicly, AWS may notify you and attach an AWS managed quarantine policy that blocks some high-risk actions, but deactivating and deleting the key, giving the application credentials that are not in source code, and reviewing AWS CloudTrail for what the key did (and undoing it) remain your job. The quarantine policy is a safety net, not a remediation.
How IAM policy evaluation decides: explicit deny, allows, and boundaries
You cannot design layered access controls without an intuition for how AWS evaluates a request. The logic you need for the exam compresses to three rules. First, everything is implicitly denied by default — a request is only allowed if some applicable policy explicitly allows it. Second, an explicit deny overrides every allow, no matter where the allow lives. Third, when multiple guardrail layers apply — SCPs, permissions boundaries, session policies — the effective permissions are the intersection: an action must be allowed at every applicable layer to succeed.
Within a single account, identity-based policies (attached to users, groups, roles) and resource-based policies (attached to resources like S3 buckets, SQS queues, KMS keys, Lambda functions) are evaluated together as a union: an allow in either is enough, provided nothing denies it. This is why a bucket policy can grant access to a principal whose identity policy says nothing about S3 — and why an explicit deny in a bucket policy blocks even an account administrator. Across accounts the rule tightens: both sides must agree, which the next sections build on.
A permissions boundary is a managed policy attached to a user or role (never a group) that sets the maximum permissions that identity can have. Like an SCP, a boundary never grants anything — the effective permissions are the intersection of the boundary and the identity policies. A boundary also governs only what the identity's sessions can do; it does not decide who may assume a role. A requirement such as "only MFA-authenticated users may assume this role" belongs in the role's trust policy, not in its boundary.
The classic use case is delegated role creation: developers may create IAM roles for their applications, but cannot use that right to escalate their own privileges. A boundary only works if it is enforced, which takes three statements in the developers' policy:
- Allow
iam:CreateRole(and attaching policies) only with a condition thatiam:PermissionsBoundaryequals the ARN of the approved boundary policy — a role created without that boundary is denied. - Deny
iam:CreatePolicyVersion,iam:SetDefaultPolicyVersionandiam:DeletePolicyon the boundary policy's ARN, so developers cannot rewrite the cap itself. - Deny
iam:DeleteRolePermissionsBoundary(and changing a boundary to a different policy), so developers cannot take the boundary off a role after creating it.
Miss any of the three and the delegation leaks: a developer creates an unbounded role, edits the boundary policy to *, or detaches it.
On the exam, this section is the debugging toolkit. When a scenario says a user "has an allow policy but still gets access denied," hunt for the explicit deny — in an SCP, a boundary, or a resource policy. When it asks how to let teams self-serve IAM without risking escalation, the answer is permissions boundaries — enforced with the iam:PermissionsBoundary condition and protected against edits and removal. And when two options differ only in that one relies on "removing allows" and the other adds an explicit deny for a must-never-happen action, the explicit deny is the stronger, intended control.
Least privilege in practice: IAM Access Analyzer and last accessed data
You rarely know the exact permissions a workload needs on day one, so AWS gives you tools to start broader and tighten with evidence. The tools differ in whether they look backwards at what was used or forwards at what a policy would allow:
| Tool | What it does | Use it when |
|---|---|---|
| IAM Access Analyzer policy generation | Drafts a fine-grained policy from the API calls a user or role made, as recorded in CloudTrail | A role was launched with broad permissions and you want a least-privilege policy based on actual activity |
| IAM Access Analyzer unused access analyzer | Continuously reports unused roles, unused access keys and passwords, and unused permissions, for one account or the whole organization (zone of trust) | You need an ongoing, organization-wide view of over-permissioned identities |
| IAM last accessed information | Shows, per user, group, role or policy, which granted services (and for some services, actions) were last used and when | Trimming one identity's permissions to what it actually calls |
| IAM Access Analyzer external access analyzer | Finds resources (buckets, keys, roles and more) shared with principals outside your account or organization | Detecting unintended cross-account or public access |
| IAM Access Analyzer custom policy checks | Checks a policy before deployment: CheckAccessNotGranted (does it grant specific sensitive actions?), CheckNoNewAccess (does it grant more than a reference policy?) | Gating policies in a CI/CD pipeline so an over-broad policy fails the build |
Policy generation, unused access and last accessed data are all retrospective: they cannot stop a bad policy from shipping. Custom policy checks (along with Access Analyzer's policy validation) are the preventive step that runs before deployment. When a scenario asks for least privilege with the least effort, the managed analysis beats hand-reading CloudTrail logs every time.
Roles and STS: temporary credentials beat access keys
The single most reliable decision rule in Task 1.1: anything that can use an IAM role should use an IAM role, never long-lived access keys. A role is an identity with permissions but no permanent credentials. When a trusted principal assumes it, AWS STS issues temporary credentials — an access key, secret key, and session token — that expire automatically. There is nothing to rotate, nothing to leak into a Git repository, and nothing to revoke user-by-user after an incident. Access keys, by contrast, live until someone deletes them, and scenarios that mention keys "stored in application code," "in a configuration file," or "shared between developers" are describing the problem the correct answer eliminates.
The pattern you will see most is the EC2 instance role: attach a role to an instance via an instance profile, and applications on it retrieve automatically rotated temporary credentials from the instance metadata service. The same principle extends everywhere compute runs — Lambda execution roles, ECS task roles — so "application on AWS compute needs AWS API access" always resolves to a role, and any option that creates an IAM user with access keys for a workload is wrong.
Amazon ECS has two roles that are easy to confuse. The task execution role is used by the ECS agent and Fargate on your behalf — to pull container images from Amazon ECR and send logs to CloudWatch Logs. The task role (taskRoleArn in the task definition, trusting ecs-tasks.amazonaws.com) is the one your application code uses to call AWS services such as DynamoDB or S3. Adding application permissions to the execution role does not reach the code; set a task role and deploy a new task definition revision.
Workloads outside AWS — on-premises servers, other clouds — can avoid access keys too. IAM Roles Anywhere lets a workload that holds an X.509 certificate exchange it for temporary role credentials: the setup has three parts — a trust anchor (which certificate authority to trust: AWS Private CA or your own CA's certificate), an IAM role whose trust policy names the Roles Anywhere service principal, and a profile that says which roles a session may receive. On the machine, the AWS-provided credential helper signs the request with the certificate's private key and returns temporary credentials. It is the answer when servers outside AWS "must not store long-term access keys."
Role switching applies the same mechanism to humans. Instead of giving an administrator standing full access, you give them a modest daily identity plus permission to assume a privileged role when needed — via sts:AssumeRole, gated by the role's trust policy and optionally an MFA condition. Every assumption is a distinct, loggable event in CloudTrail, which gives you an audit story that standing permissions cannot match. Roles also power federation: AssumeRoleWithSAML signs in workforce users from an external identity provider, and AssumeRoleWithWebIdentity does the same for mobile and web app users authenticated by an OIDC provider — the mechanism underneath Amazon Cognito identity pools.
The exam probes this with "most secure" and "least overhead" constraints. Rotating access keys more often is never the best answer when a role can remove the keys entirely; the option that eliminates long-lived credentials beats every option that merely manages them better.
Role sessions: switching, chaining, source identity, and revocation
A role session lasts from one hour (the default) up to the role's maximum session duration, which you can set up to 12 hours — with one important exception. Role switching for humans means a user with a modest daily identity calls sts:AssumeRole (or switches role in the console) into a privileged role when needed. While the session lasts, the role's permissions replace the user's — they are not added together — so an action the user could do but the role cannot fails until the user switches back.
Role chaining
Role chaining is using one role session to assume another role. That includes assuming a role from an IAM Identity Center permission set session or from an EC2 instance role, because those credentials are themselves role sessions. A chained session is limited to one hour, whatever the target role's maximum session duration says, and a chained AssumeRole call that requests more than 3,600 seconds fails — it is not silently shortened. Long-running automation that chains must request 3,600 seconds or less and re-assume the role when the credentials expire.
Session name, session tags and source identity
Each assumption shows up in CloudTrail, but the caller chooses the role session name on every call, so it is a weak audit key. Source identity is the stronger one: set once — by the identity provider in the SourceIdentity SAML attribute, or on the first AssumeRole call — it cannot be changed for the rest of the session, persists through role chaining, and is logged in CloudTrail for every action. Roles that accept it must allow sts:SetSourceIdentity in their trust policy. Session tags, by contrast, pass attributes for attribute-based access control; they are not designed as an immutable record of who acted.
Revoking access to a role
Editing or deleting a role's trust policy stops new assumptions, but credentials already issued stay valid until they expire. To cut off sessions that are already running, use the role's revoke active sessions action: IAM attaches an inline policy that denies every action for credentials issued before that moment (an aws:TokenIssueTime condition). Do both when a trusted party must lose access immediately.
Cross-account access: IAM roles vs resource-based policies
When account A needs to reach a resource in account B, you have two mechanisms, and SAA-C03 loves to make you choose. Option one: account B creates a cross-account IAM role whose trust policy names account A (or a specific principal in it) as trusted; principals in A call sts:AssumeRole and operate in B with the role's permissions. Both sides must agree — B's trust policy admits the caller, and A must allow its principal to perform the assume call. Put the role in the account that owns the resources, and give each target account its own role for hub-and-spoke automation. Option two: account B attaches a resource-based policy directly to the resource — a bucket policy, SQS queue policy, KMS key policy, or Lambda function policy — granting account A's principal access to that resource.
The decision hinges on a nuance worth stating precisely. When you assume a role, you temporarily give up your original permissions and take on the role's permissions instead — you become a different principal. With a resource-based policy, you keep your own identity and permissions and simply gain access to the remote resource on top of them. That difference is decisive in the classic Lambda scenario: a function in account A must read a queue or bucket in account B and write results to resources in its own account, in the same invocation. If the function assumes a role in B, it loses access to account A's resources mid-flight. The clean answer is a resource-based policy in B granting the function's execution role access — the function keeps its home permissions and reaches across in one identity.
Next decision input: does the target service support resource-based policies at all? Many do — S3 buckets, SQS queues, SNS topics, KMS keys, Lambda functions, Secrets Manager secrets, ECR repositories, API Gateway APIs, EventBridge event buses, and DynamoDB tables and streams, among others. Many do not: there is no resource policy on an EC2 instance, an RDS database or a CloudFormation stack, so describing or managing them from another account requires a role in the target account. A role is also the better fit when the external party needs many actions across many resources rather than one resource.
A resource policy alone is not always enough when the data is encrypted. A secret in Secrets Manager encrypted with the AWS managed key aws/secretsmanager cannot be shared across accounts, because you cannot edit an AWS managed key's key policy. Cross-account secret access therefore needs two grants that each name the outside principal: the secret must be protected by a customer managed KMS key (whose key policy you control and can extend to the other account), and the secret itself needs a resource policy permitting retrieval. Either grant alone fails — the resource and the key must both say yes.
Third-party vendors and the external ID
When the external party is a third-party SaaS vendor (a monitoring or cost tool), the pattern is a cross-account role whose trust policy names the vendor's AWS account and requires an external ID through the sts:ExternalId condition key. It defends against the confused deputy: the vendor assumes roles for many customers from the same account, so a different customer could give the vendor your role ARN and trick it into acting on your account. The external ID ties each role to one customer relationship, but only if the vendor generates a unique value per customer and shows it during onboarding. A value the customer chooses, or a guessable one such as the customer's account ID, can be reused by another customer and defeats the defence.
The obvious alternatives fail for structural reasons. An IP-address condition cannot tell the vendor's customers apart, because every request — legitimate or confused — comes from the same vendor infrastructure. An MFA condition cannot work for a vendor's automated, unattended assume calls. And shared access keys are the anti-pattern the whole design exists to avoid.
Two trust-policy details that break things
When a trust policy names a specific role or user ARN, IAM stores that principal's unique principal ID, not the name. If the trusted role is deleted and recreated with the same name, the trust no longer matches — the policy shows an ID beginning with AROA instead of the ARN — until someone edits the trust policy, enters the ARN again and saves it. Separately, accounts that AWS Organizations creates come with OrganizationAccountAccessRole, which has AdministratorAccess and trusts the management account. It is an administrative break-in path, not a template for automation: pointing a pipeline in another account at it means editing its trust policy and giving that pipeline full administrator rights, so create a purpose-built, least-privilege role instead.
Federation and IAM Identity Center: workforce access at scale
Creating an IAM user per employee per account does not scale and does not survive an audit: credentials multiply, offboarding means chasing users across accounts, and nothing ties access back to the HR system. The design answer for human workforce access is federation — your people authenticate against one identity source, and AWS trusts that source to vouch for them, issuing temporary role credentials via STS rather than storing passwords in IAM.
AWS IAM Identity Center (the successor to AWS Single Sign-On) is the service the exam expects you to reach for. It provides a single sign-on portal across all accounts in an AWS Organization. You define permission sets (collections of policies that Identity Center provisions as roles in each target account) and create account assignments: one assignment is a user or group + a permission set + an account. Because assignments are per account, the same group can get different access in different accounts — for example a full developer permission set on development accounts and a read-only one on production accounts — without writing a separate policy per account. Employees get one credential, MFA in one place, and offboarding becomes a single disable at the identity source.
Identity Center has exactly one identity source, and choosing it is a common question:
| Identity source | What it is | Choose it when |
|---|---|---|
| Identity Center directory (default) | Users and groups created and stored in Identity Center | There is no corporate directory or IdP — still far better than IAM users per account |
| Active Directory via AD Connector | A directory gateway that proxies sign-in to your existing self-managed (for example on-premises) AD; no second directory to manage and passwords stay in AD (Identity Center syncs user and group identities from it) | An on-premises AD must stay the single source of truth and a VPC can reach the domain controllers |
| Active Directory via AWS Managed Microsoft AD | A real AD domain run by AWS Directory Service, connected to Identity Center; it can trust your on-premises AD | You want AD in AWS (or already run it there); with a trust, your on-premises users can sign in |
| External identity provider | Any SAML 2.0 IdP such as Okta or Microsoft Entra ID, with SCIM provisioning users and groups | The company already uses a cloud IdP |
The trap is choosing the default Identity Center directory when an existing directory already holds the workforce: that duplicates every user and makes offboarding a two-place job. "Use the existing on-premises AD and do not create a second directory" points to AD Connector.
You should also recognize the older building blocks, because scenarios and distractors still use them: SAML 2.0 federation directly to IAM lets an IdP call AssumeRoleWithSAML against a per-account IAM identity provider and role — workable, but you configure it account by account, which is exactly the overhead Identity Center removes. "When to federate a directory service" has a simple answer shape: the company already has AD or another corporate IdP, so you federate it — preferably through Identity Center — rather than recreate identities in AWS.
Keep one boundary crisp: Identity Center is for your workforce accessing AWS accounts and business applications. Customers of your consumer-facing web or mobile app are not workforce — they belong to Amazon Cognito, covered under Task 1.2. On the exam, "employees," "multiple accounts," and "existing Active Directory / corporate IdP" together mean IAM Identity Center; any answer minting IAM users at scale, or asking you to manage per-account SAML trust when Identity Center is on offer, is there to be eliminated on operational-overhead grounds. Consumer sign-up and social sign-in with temporary AWS credentials for the app is the Cognito pattern: a user pool for sign-in and an identity pool to exchange tokens for credentials.
Multi-account design: AWS Organizations, OUs, and SCPs
At Associate level, multiple accounts are the default architecture, not an edge case: separate accounts isolate workloads and blast radius, cap the impact of compromised credentials, and cleanly separate production from development and security tooling from application teams. AWS Organizations is the service that binds them — one management account creates the organization, member accounts join it, and you get consolidated billing and centralized policy control. Accounts are grouped into organizational units (OUs), which can nest, and you design OUs around policy needs (Production, Sandbox, Security) rather than org charts, because OUs are where guardrails attach.
Those guardrails are service control policies (SCPs), and their semantics are the most-tested fact in this section: an SCP never grants a permission — it only sets the maximum available permissions for the accounts it applies to. Think of it as a filter: a principal's effective permissions are the intersection of what its IAM policies allow and what the SCPs permit. Attaching an SCP full of allows to an account gives its users nothing until an IAM policy grants those actions. SCPs attached to an OU inherit down to every account and nested OU beneath it, which is what makes them guardrails: deny leaving the organization, deny disabling CloudTrail, deny regions you don't operate in — once, at the OU, for everything below.
Precision points the exam checks:
- SCPs do affect member accounts' root users, which is why "prevent even administrators in member accounts from doing X" resolves to an SCP. (Resource control policies, below, also restrict member root users on supported resources, and centralized root access can remove member root credentials altogether.)
- SCPs do not affect the management account at all — no SCP applies to it, root or otherwise. That is a reason to keep workloads out of the management account and a fact distractors invert.
- SCPs do not restrict service-linked roles. An SCP that denies
ec2:TerminateInstancesstops your users and roles, but EC2 Auto Scaling still terminates instances on scale-in, because it acts through its service-linked role. - SCPs follow your principals, wherever the resource lives. A member-account role that calls a bucket in a partner's account is still limited by its SCPs, and the partner's bucket policy cannot override them. That is how a data-perimeter SCP works: deny S3 actions unless
aws:ResourceOrgIDequals your organization ID, and your principals cannot write to buckets outside the organization. - The reverse is not true: an SCP attached only to the OU of the account that owns a resource does not restrict principals in other accounts that a resource policy lets in. Organization-wide guardrails must be attached where they cover every member account (the root or every relevant OU) — or, for resource-side protection, use an RCP.
Restricting Regions with an SCP
The standard Region guardrail is an SCP that denies requests when aws:RequestedRegion is not one of the approved Regions (StringNotEquals). Written as a plain deny on every action, it breaks global services such as IAM, CloudFront, Route 53, AWS Organizations and AWS Support, whose requests are handled in a single Region (us-east-1 for most of them). Write the deny with NotAction instead of Action: the statement then covers every action except the global ones you enumerate, so Regional services stay locked to the approved Regions while IAM, CloudFront and Route 53 keep working. Simply adding us-east-1 to the approved list is the wrong fix — it would also open that Region to Regional resources. If one role (a network team's role, say) needs to work in every Region, add an exception inside the conditions — ArnNotLike on aws:PrincipalARN matching that role — rather than exempting a whole account. An IAM policy cannot do this job, because account administrators can edit IAM; they cannot edit an SCP.
Resource control policies (RCPs)
SCPs fence in your principals. Resource control policies (AWS Organizations, November 2024) fence in your resources: they set the maximum permissions available on resources in member accounts — for a set of supported services that includes S3, STS, KMS, SQS and Secrets Manager — no matter who calls, including principals from outside the organization. Like SCPs, they never grant, do not apply to the management account, and do not restrict service-linked roles.
| SCP | RCP | |
|---|---|---|
| Limits | What principals in member accounts can do, on any resource | What can be done to resources in member accounts, by any principal |
| Stops a partner account reading your bucket? | No — the partner's principals are not governed by your SCPs | Yes — deny when aws:PrincipalOrgID is not your organization (with an exception for AWS service principals) |
| Stops your role writing to a partner's bucket? | Yes — e.g. with aws:ResourceOrgID | No — the partner's bucket is not your resource |
| Grants permissions? | Never | Never |
Scenario-wise, SCP questions wear a uniform: "ensure that no user in any account, including administrators, can …" — disable security tooling, use an unapproved region, delete audit resources. IAM policies can't do it (a member admin could edit them); an SCP on the right OU can. If the scenario is about who may reach your resources from outside the organization, the answer is an RCP. Conversely, if a question asks how to give a team access to something, an SCP is never the answer — it cannot grant.
AWS Control Tower: governed multi-account setup without the assembly
AWS Organizations gives you the raw machinery — accounts, OUs, SCPs — but wiring a well-architected multi-account environment out of it by hand means designing the OU layout, baselining logging and audit accounts, writing the guardrail SCPs, and building an account-creation pipeline yourself. AWS Control Tower packages that work: it sets up a landing zone, a pre-configured, best-practice multi-account environment built on top of Organizations, with a defined OU structure and dedicated accounts for log archive and audit out of the box.
Control Tower manages compliance through controls, historically called guardrails, with three behaviours you must be able to tell apart:
| Behaviour | When it acts | Implemented with |
|---|---|---|
| Preventive | Blocks a non-compliant API action when it is attempted | Mainly SCPs (some newer controls use RCPs or declarative policies) |
| Detective | Finds and reports non-compliant resources that already exist, without blocking anything | AWS Config rules |
| Proactive | Checks resources in a CloudFormation template before they are provisioned and fails non-compliant ones | AWS CloudFormation hooks |
"Stop it at the API," "find what is already wrong" and "catch it in the template before deployment" map to preventive, detective and proactive respectively — and a requirement covering both new and existing resources often needs a proactive and a detective control together. Control Tower also provides Account Factory, a standardized, self-service way (published as a product in AWS Service Catalog) to provision new accounts that arrive pre-enrolled in the guardrails and baseline configuration, replacing hand-built account setup.
The Organizations-versus-Control-Tower decision is about what the scenario emphasizes. If it needs a specific mechanism — consolidated billing, an SCP to restrict actions — Organizations vocabulary answers it directly. If it describes a company about to scale from a few accounts to many and asks for a governed multi-account environment with the least effort to set up and operate, or mentions provisioning new accounts that are compliant from day one, Control Tower is the answer: it is the managed, opinionated layer, and hand-rolling the same governance with raw Organizations is the higher-overhead distractor. Control Tower uses Organizations underneath, so the two are complementary, not competing — a nuance that eliminates answer options framing them as either/or.
Expect Control Tower questions to be recognition-level: match "landing zone," "Account Factory," and preventive, detective and proactive controls to their definitions, and pick Control Tower whenever governed account vending at scale is the requirement.
Decision tables: the right access pattern and the right guardrail
Most Task 1.1 questions reduce to one of two lookups: who needs access, and through what mechanism? — or — what restriction is needed, and at which layer? Internalize these two tables and the majority of scenarios become pattern-matching.
| Who needs access | Correct mechanism | Why it wins |
|---|---|---|
| Human workforce (employees, many accounts, existing IdP or AD) | IAM Identity Center with permission sets, federated to the corporate identity source | One credential per person, central MFA and offboarding, temporary role credentials in every account — no per-account IAM users to manage |
| Application on EC2 / Lambda / ECS | IAM role attached to the compute (instance profile, execution role, task role) | STS-issued temporary credentials, auto-rotated; no keys in code or config to leak or rotate |
| Principal in another AWS account (broad or multi-service access) | Cross-account IAM role in the target account; caller uses sts:AssumeRole | Both accounts must consent (trust policy + caller's IAM policy); every assumption is auditable in CloudTrail |
| Principal in another account needing one resource while keeping its own permissions | Resource-based policy on the target resource (bucket, queue, key, function) | Caller keeps its home-account identity and permissions — the cross-account Lambda pattern |
| Third-party SaaS vendor | Cross-account role with an external ID condition in the trust policy | External ID defeats the confused-deputy attack; no credentials are ever handed to the vendor |
| Workload outside AWS (on-premises server, other cloud) | IAM Roles Anywhere with a trust anchor for your certificate authority | X.509 certificate exchanged for temporary role credentials — no stored access keys |
| Consumer users of your web/mobile app | Amazon Cognito (not IAM, not Identity Center) | Customer identity is application-facing — workforce tools are the wrong layer |
The second lookup separates the policy layers that restrict, grant, or cap permissions:
| SCP | RCP | Identity-based IAM policy | Permissions boundary | |
|---|---|---|---|---|
| Attaches to | Organization root, OU, or account | Organization root, OU, or account | User, group, or role | A single user or role (not a group) |
| Can grant permissions? | Never — only limits the maximum | Never — only limits the maximum | Yes — the only layer here that grants | Never — only caps the maximum |
| Affects root users? | Yes, in member accounts (never the management account) | Yes, on supported resources in member accounts | No — root is not governed by IAM policies | No — applies to IAM identities only |
| Scope of effect | Every principal in the affected accounts (not service-linked roles) | Supported resources in the affected accounts, whoever calls | Only the attached identity | Only the attached identity |
| Typical exam trigger | "No one in any account, including admins, may …" | "No one outside the organization may access our buckets/keys …" | "Grant the team access to …" | "Let developers create roles without escalating privileges" |
Effective permissions are always the intersection of the applicable layers, with any explicit deny winning outright. When answer options mix these layers, ask two questions: does this option need to grant (then only an IAM policy can), and does it need to bind people who could otherwise change the rules (then it must be an SCP or RCP, set above their account).
Worked scenarios: reasoning through Task 1.1 questions
Scenario 1. A company runs 40 AWS accounts in AWS Organizations. Security requires that no one in any development account — including account administrators — can disable AWS CloudTrail or create resources outside eu-west-1. What is the most effective way to enforce this?
Reasoning: The requirement is a restriction that must bind administrators. An IAM policy in each account fails immediately: member-account admins have iam:* and can edit or detach whatever you deploy. A permissions boundary fails for the same reason at a different layer — it applies per identity, and admins control identities. The phrase "including administrators" plus "any account" is the SCP signature. One guardrail policy on the OU can carry two deny statements: one blocking the CloudTrail stop-and-delete actions, and a Region statement keyed on aws:RequestedRegion that is scoped with NotAction so global services are left out of it. It inherits to every account in the OU, constrains even member-account root users, and no principal inside those accounts can lift it — because SCPs are managed from the organization, above the accounts they govern.
Scenario 2. An application running on EC2 instances in account A must read objects from an S3 bucket in account B, and write the processed output to a DynamoDB table in its own account. The company wants the least complex solution with no long-lived credentials. What do you recommend?
Reasoning: "No long-lived credentials" removes every option involving IAM users or access keys, so the instances need an instance role in account A — that part is fixed. The interesting choice is how the role reaches account B's bucket. If it assumes a role in account B, it takes on that role's permissions and temporarily loses its own — including the DynamoDB write access in account A — forcing awkward credential juggling inside one processing flow. The cleaner design: account B attaches a bucket policy granting s3:GetObject to account A's instance role, and the role's own identity policy carries the S3 read and DynamoDB write permissions. One identity, both sides of the job, nothing to rotate. This is the resource-based-policy-over-role rule earning its keep.
Scenario 3. A third-party cost-optimization SaaS needs read access to billing and usage data across a company's accounts. The vendor asks each customer to "create an IAM user and send us the access keys." What should the architect do instead?
Reasoning: Shipping access keys to an external party is the anti-pattern the question exists to punish — keys are long-lived, unauditable in the vendor's hands, and revocation is manual. The correct design: create a cross-account IAM role with a read-only, least-privilege policy, set its trust policy to the vendor's AWS account, and require the vendor-generated, customer-unique external ID in the trust condition (sts:ExternalId) so another customer of the vendor cannot induce it to assume your role — the confused-deputy defense. The vendor assumes the role with STS and receives only temporary credentials; you can stop new assumptions at any moment by editing one trust policy, and revoke sessions already issued with the role's revoke-active-sessions action.
Tip. SAA-C03 tests this task with constraint-driven scenarios: a working architecture plus a requirement such as most secure, least operational overhead, or least privilege, where several options technically function and one best fits. Classic shapes include the organization-wide restriction that must bind administrators (SCP, including Region restriction on aws:RequestedRegion with global services exempted), keeping outsiders away from your resources (RCP), the application holding access keys (replace with a role, or IAM Roles Anywhere off AWS), the cross-account choice (role vs resource policy), the third-party vendor (role plus external ID), the workforce-at-scale question (IAM Identity Center with the right identity source), MFA enforcement with condition keys, delegated role creation with enforced permissions boundaries, and least-privilege tooling (IAM Access Analyzer). Recurring misconceptions to watch for: treating an SCP as a grant, assuming SCPs reach the management account or service-linked roles, rotating long-term keys instead of eliminating them, forgetting how a missing MFA key evaluates in a deny, overlooking the one-hour role-chaining cap, and trusting an external ID the vendor does not control. When two options both work, the one that removes long-lived credentials or centralizes the control above the affected accounts usually wins.
- SCPs and RCPs never grant permissions — they cap the maximum; effective access is the intersection of SCPs, RCPs, boundaries, and IAM policies, and an explicit deny always wins.
- SCPs bind your principals (including member root users) wherever the resource lives, but never the management account or service-linked roles; RCPs bind your resources against any caller, including outsiders.
- Harden root (MFA, no keys), remove member root credentials centrally and use AssumeRoot for root-only tasks; enforce MFA with aws:MultiFactorAuthPresent (BoolIfExists for deny-unless-MFA) or aws:MultiFactorAuthAge.
- Anything running on AWS compute gets an IAM role (ECS application code uses the task role); workloads outside AWS use IAM Roles Anywhere — never stored access keys.
- Role switching replaces your permissions for the session; role chaining is capped at one hour; source identity is the immutable audit key; revoke active sessions to cut off issued credentials.
- Cross-account: assume a role for broad access or services without resource policies (EC2, RDS); use a resource-based policy when the caller must keep its own permissions.
- Third-party vendor access = cross-account role + a vendor-generated, per-customer external ID checked with sts:ExternalId — never shared access keys.
- Workforce across many accounts = IAM Identity Center (permission sets + account assignments) using the existing directory as identity source (AD Connector for on-premises AD); app customers = Cognito.
- Permissions boundaries cap delegated roles only when enforced: require iam:PermissionsBoundary on role creation and deny editing or removing the boundary.
- Control Tower = managed landing zone on Organizations: preventive controls block API actions (mainly SCPs), detective controls are Config rules, proactive controls are CloudFormation hooks; Account Factory vends governed accounts.
Frequently asked questions
What is the difference between an SCP and an IAM policy?
An IAM policy grants permissions to a specific user, group, or role — it is the only layer that can actually allow an action. A service control policy (SCP) is an AWS Organizations guardrail attached to an OU or account that sets the maximum permissions available inside; it can never grant anything. A principal's effective permissions are the intersection: an action must be allowed by an IAM policy and permitted by every applicable SCP. SCPs also constrain member-account root users, which IAM policies cannot, but SCPs have no effect on the organization's management account.
When should I use a cross-account IAM role vs a resource-based policy?
Use a resource-based policy (bucket policy, queue policy, key policy) when the caller needs access to one specific resource while keeping its own identity and permissions — for example, a Lambda function that reads a bucket in another account and writes to tables in its own account in the same invocation. Use a cross-account IAM role when the caller needs broader access across many resources or services in the target account, or when the target service does not support resource-based policies. Remember: assuming a role temporarily replaces your permissions; a resource policy adds access on top of them.
What is an external ID in AWS and when do I need one?
An external ID is a value that a role's trust policy requires, through the sts:ExternalId condition key, in every AssumeRole call. You need one whenever you grant a third party — typically a SaaS vendor that serves many customers from one AWS account — access to your account through a cross-account role. It prevents the confused-deputy problem, where a different customer of that vendor gives the vendor your role ARN and tricks it into acting on your account. The value only protects you if the vendor creates it and keeps it distinct per customer relationship; a value the customer picks, or a guessable one like an account ID, can be reused by another customer and defeats the defence. IP-address or MFA conditions cannot replace it, because all of the vendor's requests come from the same infrastructure and are automated.
Should I use IAM users or IAM Identity Center for employees?
IAM Identity Center, almost always. IAM users carry long-lived passwords and access keys that you must rotate, monitor, and delete per account — for a workforce across multiple accounts, that operational load and offboarding risk make them the wrong tool. Identity Center gives every employee single sign-on into all organization accounts through permission sets and account assignments backed by temporary role credentials. Its identity source can be its own directory (when there is no corporate directory), an existing Active Directory through AD Connector or AWS Managed Microsoft AD, or an external SAML IdP such as Okta or Microsoft Entra ID. IAM users remain acceptable only for narrow edge cases, such as a legacy tool that genuinely cannot use roles or federation.
Do SCPs apply to the AWS Organizations management account?
No. SCPs have no effect whatsoever on the management account — not on its IAM users, its roles, or its root user. They apply only to member accounts, where they constrain every IAM user and role and the member account's root user, though not service-linked roles. This is precisely why AWS recommends keeping workloads and day-to-day activity out of the management account: it is the one account your organization-wide guardrails cannot reach. Resource control policies (RCPs) likewise do not apply to the management account.
How does AWS decide whether a request is allowed when multiple policies apply?
Evaluation starts from implicit deny: nothing is allowed until a policy explicitly allows it. An explicit deny anywhere — identity policy, resource policy, SCP, RCP, permissions boundary — overrides all allows and ends the evaluation. Within one account, identity-based and resource-based policies work as a union: an allow in either is sufficient. Guardrail layers work as an intersection: the action must also be permitted by every applicable SCP and RCP and by the permissions boundary if one is attached. Across accounts, both the caller's identity policy and the target's resource policy (or role trust) must allow it. So the practical checklist is: any explicit deny? Denied. Allowed by IAM or resource policy, and inside every guardrail? Allowed.
What is the difference between AWS Organizations and AWS Control Tower?
AWS Organizations is the foundational service: it groups accounts under a management account, arranges them into OUs, applies SCPs, and consolidates billing. AWS Control Tower is a managed governance layer built on top of Organizations: it sets up a best-practice landing zone with log archive and audit accounts, enforces preventive controls (mainly SCPs), detective controls (AWS Config rules) and proactive controls (CloudFormation hooks), and provisions new, pre-governed accounts through Account Factory. Choose Organizations vocabulary when a question needs a specific mechanism like an SCP; choose Control Tower when it asks for a governed multi-account environment with minimal setup and ongoing effort.
What is the difference between an SCP and a resource control policy (RCP)?
Both are AWS Organizations guardrails that never grant permissions and never apply to the management account. A service control policy (SCP) limits what the IAM users, roles and root users of member accounts can do, on any resource, including resources in other accounts. A resource control policy (RCP) limits what can be done to supported resources in member accounts — such as S3 buckets, KMS keys, SQS queues and Secrets Manager secrets — by any principal, including principals outside your organization. To stop outsiders reaching your data, use an RCP (for example, deny when aws:PrincipalOrgID is not your organization); to stop your own principals sending data out, use an SCP (for example, with aws:ResourceOrgID).
Source
This lesson covers the "Design Secure Architectures" domain of the official SAA-C03 exam guide. Vendors revise their guides — check the source for the current version.
- AWS Certified Solutions Architect – Associate (SAA-C03) exam guide — Amazon Web Services
Sign up free to mark lessons complete, bookmark topics and track your exam readiness.