AWS SAA-C03: Security, IAM, KMS & Governance — Study Guide
Part of the AWS SAA-C03 Complete Study Guide. Practice these concepts with verified answers in the AWS/Amazon exam hub, or take timed practice tests on ExamRoll.io.
Identity Foundations: Users, Roots, Groups, and Roles
Identity and Access Management is the control plane every workload passes through, and its governing principle is least privilege: grant only what is needed, for only as long as it is needed, and prefer identities that produce short-lived credentials over ones that hold static secrets.
The root user owns the account, holds unrestricted permissions, and cannot be constrained by IAM policies or SCPs. That makes it the single most sensitive credential in the environment, and it should be treated as break-glass. On a new account: enable a hardware or virtual MFA device on root, set a long unique password, remove any historical root access keys, and register alternate billing/operations/security contacts so recovery is possible. After initial setup — creating an IAM admin identity, configuring billing, and setting the account alias — root is not used again except for the narrow set of tasks AWS explicitly requires it for (closing the account, changing the account name, restoring deleted IAM permissions, enabling MFA Delete, and a handful of S3/CloudFront root-signed operations). Using root for daily work is wrong because it cannot be scoped by policy, it is hard to attribute in CloudTrail when shared, and a single compromise grants irrevocable control.
Human day-to-day access flows through IAM identities scoped by least-privilege policies. Attach managed policies to groups, not individual users: an Administrators group with AdministratorAccess attached, and named users placed into it, yields a single change point and avoids the anti-pattern of pasting identical policies onto every user. Scope resources with explicit ARNs rather than *.
Roles serve a different purpose entirely. They are assumed by principals — services, EC2 instances, Lambda functions, federated users, cross-account callers — and produce temporary STS credentials that rotate automatically. Because those credentials cannot leak in a Git commit and expire in minutes to hours rather than persisting until manually rotated, roles are the default identity for anything non-human.
Two Policies per Role: Permissions and Trust
Every role is governed by two independent documents, and forgetting either is a classic failure mode.
The permissions policy (identity-based) declares what the role can do once assumed. The trust policy (resource-based, attached to the role itself) declares who can assume it. Attaching AmazonS3ReadOnlyAccess to a role accomplishes nothing if no principal is allowed to call sts:AssumeRole on it, and conversely, a permissive trust policy without a permissions policy produces a role that can be assumed but does nothing useful.
A Lambda execution role shows the service-principal pattern — the service itself, not the account owner, is the caller:
AssumeRolePolicyDocument: # trust policy
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal: { Service: lambda.amazonaws.com }
Action: sts:AssumeRole
Policies: # permissions
- PolicyName: ReadOrders
PolicyDocument:
Statement:
- Effect: Allow
Action: dynamodb:GetItem
Resource: arn:aws:dynamodb:*:*:table/Orders
Workload Identity: Instance Profiles, Task Roles, IRSA, Roles Anywhere
Every credential that lives in a template, environment variable, or on a laptop is a future breach. The canonical AWS pattern replaces static access keys with short-lived, automatically rotated credentials delivered through roles.
For EC2, the delivery mechanism is the instance profile — a thin container that binds an IAM role to an instance so the Instance Metadata Service (IMDSv2) can vend temporary credentials to the SDK. The default credential provider chain finds them without configuration, so boto3.client('s3') just works and application code never sees a credential. IMDSv2 (HttpTokens: required) should be enforced to defeat SSRF-based credential exfiltration. Credentials rotate roughly every six hours, and revocation is a simple role edit.
AppRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal: { Service: ec2.amazonaws.com }
Action: sts:AssumeRole
Policies:
- PolicyName: S3DocAccess
PolicyDocument:
Statement:
- Effect: Allow
Action: [s3:GetObject, s3:PutObject]
Resource: arn:aws:s3:::docs-bucket/*
AppInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles: [!Ref AppRole]
For ECS the analogue is the task role; for Lambda it is the execution role; for EKS pods it is IRSA (IAM Roles for Service Accounts) or EKS Pod Identity. In every case AWS itself brokers credentials against a role and the workload never sees a long-lived secret.
Baking access keys into an AMI, user-data script, or .env file is wrong for three concrete reasons: keys never rotate automatically, they cannot be scoped to session context like a source VPC endpoint, and if the instance is compromised or an AMI is inadvertently shared, the credential leaks permanently.
For workloads outside AWS — on-prem servers, other clouds, CI runners — that need temporary AWS credentials without embedded keys, IAM Roles Anywhere uses X.509 certificates from a private CA (AWS Private CA or your own) as the trust anchor. The workload presents its client certificate and receives short-lived STS credentials:
aws_signing_helper credential-process \
--certificate /etc/pki/client.pem \
--private-key /etc/pki/client.key \
--trust-anchor-arn arn:aws:rolesanywhere:...:trust-anchor/... \
--profile-arn arn:aws:rolesanywhere:...:profile/... \
--role-arn arn:aws:iam::111122223333:role/OnPremWorkload
This closes the same anti-pattern that instance roles and Secrets Manager close inside AWS.
Human Access at Scale: Identity Center, SAML, Directory Service
Provisioning per-account IAM users at any scale is unmanageable. AWS IAM Identity Center (successor to AWS SSO) is the recommended front door for workforce access: a single directory that federates into every account in an Organization and issues temporary role-based sessions via permission sets — templated IAM roles mapped to IdP groups. Users authenticate once at the Identity Center portal, then assume permission sets into any assigned account.
Identity Center integrates with external IdPs (Okta, Entra ID/Azure AD, Google Workspace, ADFS) via SAML 2.0 and SCIM for automated joiner/mover/leaver flows, and with on-premises Active Directory through AWS Directory Service AD Connector (a proxy) or AWS Managed Microsoft AD (a full replica in AWS). For mobile or web apps that must call AWS from unauthenticated or third-party-authenticated users, Amazon Cognito exchanges the external identity for temporary STS credentials, again avoiding embedded long-lived keys.
Cross-Account Access
Cross-account access is expressed with roles, not shared users, and both sides must agree. The target account (B) creates a role whose trust policy names Account A (or a specific principal in it), and the caller in A must also have sts:AssumeRole permission targeting that role’s ARN. Either side alone is insufficient. This produces short-lived credentials and a clear CloudTrail audit trail in both accounts.
When a third party (a SaaS vendor) is the assuming principal, add an ExternalId condition to defeat the confused deputy problem, and consider requiring MFA:
{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::222222222222:root" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": { "sts:ExternalId": "a1b2c3-unique-token" },
"Bool": { "aws:MultiFactorAuthPresent": "true" }
}
}
For service-to-service cross-account invocations, resource policies do the work. To let an SNS topic in Account A invoke a Lambda in Account B:
aws lambda add-permission \
--function-name ProcessNotification \
--statement-id AllowSNSInvoke \
--action lambda:InvokeFunction \
--principal sns.amazonaws.com \
--source-arn arn:aws:sns:us-east-1:111111111111:my-topic
The --principal sns.amazonaws.com is the service principal (SNS itself invokes Lambda), and --source-arn scopes trust to a specific topic to prevent the confused deputy problem.
For cross-Organization S3 sharing, the naive approach — listing every account ARN in the bucket policy — does not scale and breaks whenever a new account is added. The correct pattern is aws:PrincipalOrgID:
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::reports-bucket/*",
"Condition": {
"StringEquals": { "aws:PrincipalOrgID": "o-abcd1234ef" }
}
}
Any principal in any account in that organization is allowed; anyone else is denied. Note that Principal: "*" without the condition would be a public bucket — the condition key is what constrains scope. The identity side still matters: users in member accounts also need s3:GetObject granted by their own IAM policy (unless they are account root), because cross-account access requires both sides to allow the call.
For S3 specifically, since 2023 the default Object Ownership setting Bucket owner enforced disables ACLs entirely, making bucket policies the sole authorization mechanism for the bucket. When objects were previously uploaded by other accounts, historical object ACLs or the bucket-owner-full-control canned ACL may still be in play.
Organizations and Service Control Policies
AWS Organizations aggregates accounts into a tree of OUs with a management account at the root. Service Control Policies are guardrails attached to the root, an OU, or an individual account. They apply to every IAM user and role in the account — including the account root — but not to the management account itself, which is why workloads should never run there.
The critical mental model: SCPs never grant permissions. They define the maximum set of actions permitted in an account. An action is only allowed if it is granted by an identity or resource policy and not blocked by any SCP in the account’s path. If a developer has AdministratorAccess but an SCP denies ec2:RunInstances outside ap-southeast-2, launching in us-east-1 fails. Conversely, an SCP allowing s3:* does nothing on its own — the user still needs an IAM policy granting s3:*. SCPs filter what IAM has already allowed; they are ceilings, not floors.
Typical SCP uses include region lockdown, forbidding disabling of CloudTrail or GuardDuty, forbidding KMS key deletion outside a break-glass role, and enforcing encryption. To force encrypted EBS at launch, combine two mechanisms: enable EBS encryption by default in the region (a per-region account setting so users don’t change scripts), plus an SCP as the auditable guardrail:
{
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:volume/*",
"Condition": { "Bool": { "ec2:Encrypted": "false" } }
}
Because SCPs apply to the entire account, they cannot be bypassed by a compromised administrator in a member account. Tag policies enforce standardized tag keys and case (CostCenter, not costcenter) so cost allocation and ABAC work reliably. Organizations also supports delegated administration: instead of running security services from the management account, delegate a member (“security” or “audit”) account as administrator for GuardDuty, Security Hub, IAM Access Analyzer, or Config — preserving separation of duties.
KMS: Keys, Key Policies, and Ownership Models
KMS distinguishes key material by ownership and control:
| Model | Key material | Rotation | Auditable | Use case |
|---|---|---|---|---|
| SSE-S3 / AWS-owned | AWS, hidden | Automatic, opaque | Not visible | Simple “encrypted at rest” |
AWS-managed CMK (aws/service) | AWS | Yearly automatic | Yes | Default, no control needs |
| Customer-managed CMK | AWS KMS, you own the policy | Optional yearly (must enable), configurable 90–2560 days | Yes | You need to disable, audit, scope, or share |
| Imported key material | You generate, import to KMS | Manual re-import; never auto | Yes | Regulatory mandate to originate keys |
| External Key Store (XKS) | Your on-prem HSM via XKS proxy | You control externally | Yes | Data sovereignty; key never leaves premises |
| SSE-C | Customer supplies per request | Manual | Limited | Client insists on holding material |
A CMK is governed by a key policy — a resource-based policy attached to the key. Unlike almost every other AWS resource, IAM policies alone cannot grant access to a KMS key unless the key policy first delegates to IAM:
{
"Sid": "EnableIAMPolicies",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:root" },
"Action": "kms:*",
"Resource": "*"
}
Without that statement, no IAM policy makes the key usable. Both the key policy and the caller’s IAM policy must allow the operation — this is the single most frequent encryption error. Granting kms:Decrypt in an IAM policy is necessary but not sufficient; if the key policy does not delegate to IAM or does not name the principal, decryption fails with AccessDenied even for an administrator.
For services that use KMS on your behalf (EBS, S3, RDS, Lambda), the calling role typically needs kms:GenerateDataKey, kms:Decrypt, and often kms:CreateGrant. For an EKS managed node group encrypting EBS volumes with a CMK, the Auto Scaling service-linked role must appear in the key policy with kms:CreateGrant, or instance launches silently fail.
Customer-managed CMK rotation requires explicit enabling — many practitioners incorrectly assume all KMS keys rotate automatically:
aws kms enable-key-rotation --key-id alias/my-cmk
aws kms get-key-rotation-status --key-id alias/my-cmk
Rotation preserves the same key ID and alias; the backing material changes but past ciphertext remains decryptable because KMS retains old material to decrypt existing ciphertexts while new writes use fresh material. Imported material never auto-rotates. KMS enforces a mandatory 7–30 day pending-deletion window; pair this with an EventBridge rule matching ScheduleKeyDeletion or DisableKey in CloudTrail and target an SNS topic for a serverless, poll-free alerting pattern:
{
"source": ["aws.kms"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": { "eventName": ["ScheduleKeyDeletion", "DisableKey"] }
}
External Key Stores extend the model when regulators require key material to physically reside in a customer-controlled HSM. KMS forwards cryptographic operations to an XKS proxy talking to the on-prem HSM; if the HSM is offline, decryption fails — availability becomes the customer’s responsibility.
Multi-Region Keys (MRKs) share the same key ID and material across Regions, so ciphertext produced in us-east-1 decrypts in eu-west-1 directly. This is the correct pattern for DynamoDB Global Tables, S3 Cross-Region Replication with SSE-KMS, and DR where a standby Region must read encrypted backups. Standard single-Region keys would require decrypt-then-reencrypt at replication time.
Cross-Account Encrypted Resource Sharing
Encrypted AMI and EBS snapshot sharing is one of the most common cross-account failure modes because it requires four coordinated actions: (1) use a customer-managed CMK — AWS-managed keys cannot be shared; (2) add the destination account as a principal in the key policy with kms:Decrypt, kms:DescribeKey, kms:CreateGrant, and kms:ReEncrypt*; (3) modify the AMI or snapshot’s launch/share permissions to include that account; and (4) ensure the IAM principal in the destination account also has those KMS actions. The sharing operation appears to succeed if you skip step 2, but the receiving account cannot decrypt. Assuming the AMI share alone is enough is the classic trap.
S3 Server-Side Encryption Modes
| Mode | Key owner | Rotation | CloudTrail audit | Cost |
|---|---|---|---|---|
| SSE-S3 (AES-256) | AWS-managed, hidden | Automatic, opaque | Not visible | No key cost |
SSE-KMS with aws/s3 | AWS | Yearly automatic | Yes | No key cost, API charges apply |
| SSE-KMS with customer CMK | Customer | Optional, must enable | Yes | $1/month per key + API |
| DSSE-KMS | Customer | Same as CMK | Yes | Higher; dual-layer for regulated workloads |
| SSE-C | Customer per request | Manual | Limited | No key cost |
| CSE-KMS / CSE-C | Customer, encrypts before upload | Manual | KMS calls only | Varies |
When a requirement specifies automatic annual rotation, CloudTrail auditability, and minimizing key cost, the answer is SSE-KMS with the AWS-managed aws/s3 key — it rotates yearly at no charge and every GenerateDataKey/Decrypt call is logged. SSE-S3 is cheaper but leaves no key-usage trail. A customer-managed CMK adds $1/month and only rotates if you enable rotation.
Confusing SSE-S3 and SSE-KMS is the classic PHI trap. SSE-S3 encrypts data but gives no key policy, no CloudTrail visibility, and no way for a compliance team to administer the key — so it fails any requirement mentioning “administer,” “control,” “audit,” or “revoke access to” the key. Conversely, choosing SSE-KMS when the requirement is only “encrypt at rest with minimal management” is over-engineering.
Enabling SSE-KMS does not by itself prevent unauthorized reads. If the bucket policy allows s3:GetObject and the key policy grants kms:Decrypt to the same principal, the object is readable. Encryption at rest defends against physical media compromise and adds a second authorization check via the key policy — it does not substitute for correctly scoped bucket policies, IAM policies, VPC endpoint policies, and aws:PrincipalOrgID conditions.
Enforcing Encryption and TLS on S3
Making a bucket “encrypted by default” is not enough — clients can omit or override the encryption header. Two guardrails must layer: default bucket encryption (fills in the header if the client omits one) and a deny-based bucket policy rejecting PutObject without the required header, plus a statement denying non-TLS access:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyUnEncryptedObjectUploads",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::phi-bucket/*",
"Condition": {
"StringNotEquals": { "s3:x-amz-server-side-encryption": "aws:kms" }
}
},
{
"Sid": "DenyInsecureTransport",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": ["arn:aws:s3:::phi-bucket", "arn:aws:s3:::phi-bucket/*"],
"Condition": { "Bool": { "aws:SecureTransport": "false" } }
}
]
}
The aws:SecureTransport condition forces HTTPS, satisfying “encrypted in transit.” Combined with SSE-KMS using a compliance-team-owned CMK, this is the canonical PHI storage pattern.
Encryption in Transit vs. at Rest
Encryption at rest (KMS-encrypted EBS, RDS storage, S3 objects) and encryption in transit (TLS on the wire) are independent controls addressing different threats — disk theft versus network interception. Enabling KMS on an RDS instance protects the underlying storage; it does nothing for a client-to-database session, which by default may be unencrypted. For RDS MySQL, in-transit protection requires downloading the RDS CA bundle, setting require_secure_transport=ON in the parameter group, and connecting clients with --ssl-ca=rds-combined-ca-bundle.pem. Treating “encryption at rest is on” as sufficient is a frequent audit failure.
Secrets Manager and Parameter Store
Static database passwords in config files, environment variables, or CloudFormation parameters are the leading credential-leak vector. AWS Secrets Manager stores secrets encrypted with KMS, exposes them through IAM-controlled GetSecretValue, and — critically — rotates them automatically via a Lambda rotation function. For RDS, Aurora, Redshift, and DocumentDB, AWS provides a managed rotation Lambda that connects to the database, generates a new password, updates both the secret and the DB user atomically, and supports single-user or multi-user strategies. For other systems, you author a Lambda implementing the four-step lifecycle: createSecret, setSecret, testSecret, finishSecret.
import boto3, json
secret = json.loads(
boto3.client('secretsmanager')
.get_secret_value(SecretId='prod/aurora/app')['SecretString'])
conn = pymysql.connect(host=secret['host'],
user=secret['username'],
password=secret['password'])
Applications cache the value briefly (using the AWS SDK caching library) and reconnect on auth failure. Rotation is invisible and no deployment is needed to change a password.
SSM Parameter Store SecureString is the alternative when rotation is not required and cost dominates:
| Feature | Secrets Manager | SSM Parameter Store |
|---|---|---|
| Automatic rotation | Yes; native for RDS/Aurora/Redshift/DocumentDB | No native rotation (Advanced tier can trigger EventBridge) |
| Cost | $0.40/secret/month + API | Standard is free; Advanced is paid |
| Size limit | 64 KB | 4 KB Standard, 8 KB Advanced |
| Cross-account sharing | Resource policies | Not natively shareable |
| Cross-region replication | Yes | No |
| Encryption | KMS required | KMS only for SecureString |
A SecureString parameter’s retriever needs both ssm:GetParameter and kms:Decrypt on the key. Forgetting the KMS permission is one of the most common misconfigurations — the IAM policy looks correct but the API call fails on decrypt.
On EC2, ECS, EKS, and Lambda, the code should assume an IAM role and call GetSecretValue or GetParameter; no long-lived credentials on disk. Embedding IAM user access keys directly in application code — even encrypted — violates least privilege and complicates rotation.
Audit and Forensic Tooling
CloudTrail records every AWS API call: who, what, when, from where. An organization trail enabled from the management account captures events across all accounts into a single S3 bucket, ideally in a locked-down security account with S3 Object Lock and MFA Delete. This provides an immutable forensic timeline — which principal deleted a volume, which role modified a security group, which access key called ec2:RunInstances at 03:17 UTC. Complement with CloudWatch Logs and alarms (root login, IAM policy changes), and AWS Config for point-in-time resource state and conformance packs. Prevent tampering with an SCP denying cloudtrail:StopLogging and cloudtrail:DeleteTrail.
MFA Delete on an S3 bucket forces the root user to present an MFA token to permanently delete an object version or disable versioning. It can only be enabled by root via the CLI and provides strong protection against ransomware and insider deletion.
Amazon Macie uses managed ML to discover PII, PHI, credentials, and financial data in S3, producing severity-ranked findings. It is a discovery tool, not an encryption tool.
Threat Detection: GuardDuty, Security Hub, Detective
Amazon GuardDuty continuously analyzes VPC Flow Logs, DNS logs, and CloudTrail management and data events, with dedicated protection plans for EKS audit logs, S3 data events, EBS malware scans, Lambda network activity, and RDS login events. GuardDuty RDS Protection surfaces anomalous or brute-force auth attempts against Aurora and RDS — behavior a security group cannot catch because the connection is legitimate at L4. Findings flow into EventBridge, Security Hub, and Detective dashboards.
Security groups operate at L3–L4 only. A group allowing 0.0.0.0/0 on 443 is doing its job when it forwards a SQL-injection payload — that is precisely what WAF exists to stop. Defense in depth means security groups plus WAF plus Shield plus GuardDuty, each covering a layer the others cannot see.
DDoS: Shield Standard and Advanced
AWS Shield Standard is automatic and free, defending every account against common L3/L4 attacks (SYN floods, reflection). It runs silently with no visibility, no custom mitigation, and no human intervention path.
AWS Shield Advanced ($3,000/month per organization plus data transfer) is required whenever the scenario mentions proactive engagement, dedicated response, cost protection against DDoS-induced scaling, or near-real-time attack visibility. It covers CloudFront, Global Accelerator, ALB, CLB, Route 53, and Elastic IPs, and provides 24/7 access to the Shield Response Team (SRT) — pre-authorized via an IAM role — to write WAF rules on your behalf during an active attack. When a design behind an ALB and Route 53 needs managed detection and human response, Shield Standard alone is insufficient; that is the recurring trap. Advanced also grants cost protection for scaling triggered by attacks. When “LEAST implementation effort” is mentioned and the architecture already includes Global Accelerator or an ALB, the answer is typically enable Shield Advanced and attach the AWS-managed WAF rule groups, not building custom Lambda@Edge or migrating CDN.
Application-Layer Protection: AWS WAF
AWS WAF attaches to CloudFront, Application Load Balancers, API Gateway, AppSync, App Runner, and Cognito user pools. It does not protect Network Load Balancers directly (put CloudFront in front). It inspects L7 traffic and applies rules for SQL injection, XSS, size constraints, geo-blocking, IP reputation, and rate limiting. AWS Managed Rules provide curated groups such as AWSManagedRulesCommonRuleSet and AWSManagedRulesSQLiRuleSet without writing regex.
Rate-based rules are the primary defense against HTTP floods and credential stuffing — they count requests per five-minute window per source IP (or per forwarded header) and block offenders automatically:
Rules:
- Name: RateLimitPerIP
Priority: 1
Statement:
RateBasedStatement:
Limit: 2000 # per 5-min window per IP
AggregateKeyType: IP
Action: { Block: {} }
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: RateLimitPerIP
SampledRequestsEnabled: true
WAF is not a DDoS service — that is Shield’s role. WAF complements resource policies (S3 bucket policies denying non-TLS, VPC endpoint policies limiting reachable buckets) and network controls (security groups, NACLs) — a misconfiguration at any single layer must not expose data.
Network Isolation: Security Groups, NACLs, Network Firewall
Inside a VPC, defense is layered:
- Security groups are stateful, apply to ENIs, are allow-only, and evaluate all rules together. Return traffic is automatically permitted, so ephemeral ports need not be opened explicitly.
- Network ACLs are stateless, apply to subnets, support both allow and deny, and evaluate in numeric order. Because they are stateless, if you allow inbound 443, you must also allow outbound ephemeral 1024–65535 for responses. Forgetting this drops all replies in subtle ways. Security groups do not have this problem.
- AWS Network Firewall provides deep packet inspection, Suricata-compatible IPS rules, and domain-based egress filtering, sitting between subnets and IGWs/TGWs for centralized inspection.
Assuming security groups alone suffice ignores subnet-level threats and blast-radius controls; assuming NACLs alone suffice ignores their statelessness and coarseness.
Trap Catalogue
Trust policy forgotten. A role’s permissions policy grants abilities; only the trust policy grants assumability. Both must open for cross-account or service-to-service access to work — the caller receives AccessDenied on sts:AssumeRole regardless of how permissive the identity policy is.
IAM policy without matching key policy. kms:Decrypt in IAM is necessary but not sufficient. The key policy must either name the principal or delegate to IAM with Principal: {"AWS": "arn:aws:iam::ACCOUNT:root"}. Encrypted AMI/snapshot sharing fails when only the AMI share is done and the key policy is not updated.
SCPs treated as grants. SCPs cap, never grant. An Allow s3:* SCP does nothing without a matching identity policy. Conversely, a permissive identity policy is bounded by any SCP Deny in the account’s path.
Assuming automatic KMS rotation. Customer-managed CMKs do not rotate until enabled; imported material never auto-rotates.
SSE-S3 chosen for compliance-controlled data. SSE-S3 has no key policy, no CloudTrail visibility, and no revocation path — it fails any requirement mentioning “administer,” “control,” “audit,” or “revoke” the key.
Encryption at rest treated as sufficient. At rest and in transit are independent. RDS with KMS still needs require_secure_transport=ON and client CA validation.
Bucket policy naming accounts individually. Doesn’t scale and breaks on org changes. Use aws:PrincipalOrgID.
Hardcoded access keys anywhere. In user data, .env files, CloudFormation parameters, Git — always wrong. Use instance profiles, task roles, execution roles, IRSA/Pod Identity, or Roles Anywhere.
Root user for daily work or attached policies. Root cannot be constrained by IAM or SCPs; adding a policy to root is meaningless. Any answer that does so is wrong on its face.
IAM users for cross-account access. IAM users cannot be assumed cross-account; create a role in the target account and let the source-account principal assume it.
NLB behind WAF. WAF does not attach to NLBs. Front the NLB with CloudFront if L7 filtering is needed.
NACL missing ephemeral outbound. Stateless NACLs need explicit return-path rules. Missing 1024–65535 outbound silently breaks all inbound 443 responses.
Shield Standard for managed engagement. Standard is passive with no SRT access; only Advanced satisfies “proactive managed engagement” or “cost protection.”
← Previous: Application Integration · All domains · Next: Management →
Practice Security 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 →