Chapter 2

Security for Developers

AWS Certified Developer – Associate (DVA-C02) Study GuideBased on the official DVA-C02 exam objectives

Picture this: it is 2:14 on a Tuesday morning, and Daniel, a backend developer at a food-delivery startup, wakes up to 47 text messages. His team's AWS bill — normally around $900 a month — hit $48,000 overnight. Someone found an IAM access key in a public GitHub repository, committed six weeks earlier by an intern who "just needed the tests to pass." The key belonged to an IAM user with AdministratorAccess. By sunrise, crypto-mining instances were running in nine regions under his company's account. Daniel's company survived — AWS support helped contain it — but the post-mortem was brutal. Every layer of the failure was a developer security mistake: a long-term access key where a role should have been used, a policy far broader than the job required, a secret sitting in source control instead of a secrets manager, and no one watching for the signs. This chapter is about never being Daniel. Security is 26% of the DVA-C02 exam — the second-largest domain — and it is tested the way developers actually encounter it: not as abstract policy theory, but as concrete choices in code and architecture. Which credential does this Lambda function use? How does the mobile app prove who it is? Where does the database password live? Who is allowed to call this API? The exam rewards one instinct above all: least privilege, delivered through the right mechanism. This chapter builds that instinct piece by piece.

IAM for Developers: Who Can Do What

Every AWS request answers two questions: who is making this request, and is that identity allowed to do this? As a developer, you live inside this system every day — your code assumes identities, your functions carry permissions, your APIs check callers. The developers who pass DVA-C02 think in identities the way plumbers think in pipes.

Users Are for People; Roles Are for Everything Else

An IAM user is a long-term identity with permanent credentials — a password, an access key pair, or both. Users are for humans: the developers, admins, and operators on your team. An IAM role is an identity with no permanent credentials. Instead, whoever assumes the role gets temporary credentials from the Security Token Service (STS) — valid for 15 minutes to 12 hours, then gone. Here is the rule the exam will test a dozen ways: your code should never use IAM user credentials. Lambda functions, EC2 instances, ECS tasks, and applications should all run as roles. An EC2 instance gets its role through an instance profile ; a Lambda function gets its role as its execution role ; an ECS task gets a task role . The AWS SDKs and CLI pick up role credentials automatically from the environment — no keys to store, rotate, or leak. Daniel's disaster happened because an IAM user's permanent key lived in a git repo. Roles make that entire failure category impossible: there is no key to steal. When you do need to hand credentials to something outside AWS — a mobile app, a CI/CD pipeline in another cloud — you still avoid long-term keys. STS issues temporary credentials on demand: AssumeRole for switching into a role you can access, AssumeRoleWithWebIdentity for federating with an external identity provider (a Cognito identity pool, or GitHub Actions via OIDC, so your pipelines need no stored AWS keys at all), and GetSessionToken for MFA-protected temporary credentials. The pattern is always the same: short-lived beats long-lived.

Exam tip

If a scenario describes code running on EC2, Lambda, or ECS that needs AWS access, the answer is an IAM role (instance profile, execution role, task role) — never an IAM user with access keys. "The application needs AWS credentials" is the exam waving a flag that says role.

Identity Policies vs. Resource Policies: Two Sides of the Door

Permissions in AWS come in two flavors, and confusing them is one of the exam's favorite traps. Identity-based policies attach to who is asking: IAM users, groups, and roles. They say "this identity may do these actions on these resources." Your Lambda execution role's policy is identity-based. Resource-based policies attach to what is being accessed: S3 bucket policies, SQS queue policies, SNS topic policies, Lambda function policies, KMS key policies, API Gateway resource policies. They say "these identities may do these actions on this resource." Why does the distinction matter? Two reasons the exam loves. First, not every service supports resource-based policies. S3, SQS, SNS, Lambda, and KMS do. DynamoDB does now too — since March 2024, DynamoDB supports resource-based policies for tables, indexes, and streams, which simplifies cross-account access (previously you had to use STS role assumption for cross-account DynamoDB access). The exam still tests the older pattern, so know both: a "DynamoDB resource policy" is a legitimate modern answer, while older materials may still call it wrong. Second, cross-account access requires resource-based policies (or STS role assumption). An identity-based policy in Account B cannot grant access to a bucket in Account A by itself — the bucket's resource policy in Account A must also allow it. For cross-account, both sides must say yes.

Policy Evaluation Logic: The Deny That Always Wins

When AWS evaluates a request, it walks a strict decision tree. Memorize this order, because the exam tests it relentlessly: 1. Default: implicit deny. Everything starts denied. 2. Check every applicable policy for an explicit deny. Identity policies, resource policies, permission boundaries, SCPs, session policies — an explicit Deny in any of them kills the request immediately. Deny always wins, no exceptions. 3. Check for an explicit allow. If any applicable policy explicitly allows the action, the request is allowed. 4. Otherwise: implicit deny. No allow anywhere means denied. Two consequences fall out. First, for same-account access, an allow in either the identity policy or the resource policy is enough. Second, for cross-account access, you need an allow on both sides — the caller's identity policy and the resource's policy — because the resource account must explicitly open its door. Permission boundaries deserve a special mention. A permission boundary is a policy that sets the maximum permissions an IAM user or role can ever have, no matter what other policies grant. Administrators use them to delegate safely: "you may create roles for your team, but no role you create can ever exceed this boundary." The effective permission is always the intersection of the boundary and the identity's policies. If the exam describes delegated administration with guardrails, think permission boundaries.

Exam tip

Evaluation order in one breath: implicit deny explicit deny anywhere kills it explicit allow anywhere (same account) saves it otherwise denied. Cross-account needs allows on both sides. Note: DynamoDB does support resource-based policies for tables, indexes, and streams (added March 2024) — older practice material calling them "always wrong" is outdated.

Exercise

Exercise 1. A Lambda function needs to read from a DynamoDB table and write objects to an S3 bucket. An S3 event notification must trigger the function when new objects arrive. Which permissions go where? Answer: Two different mechanisms. The function's execution role (identity-based policy) needs dynamodb:GetItem/Query on the table and s3:PutObject on the bucket — that is what the function is allowed to do. Separately, the function's resource-based policy (function policy) must allow lambda:InvokeFunction for the S3 service principal — that is who is allowed to invoke the function. Why not put everything in the execution role? Because the execution role controls the function's outbound permissions, not who may call it — S3 invoking Lambda is inbound and needs the resource policy (added via lambda:AddPermission). Why not use a bucket policy alone? A bucket policy could allow the function's role to access the bucket, but it cannot grant S3 permission to invoke Lambda — different direction, different policy.

KMS: Envelope Encryption and Key Control

Encryption is how you keep a stolen hard drive — or a leaked database dump — from becoming a breach. AWS Key Management Service (KMS) is the exam's encryption hub, and developers meet it everywhere: encrypted S3 objects, encrypted EBS volumes, encrypted database passwords.

Envelope Encryption: Keys Protecting Keys

KMS uses envelope encryption , and understanding it unlocks half the KMS questions. The idea: you never encrypt large data directly with your master key. Instead, you ask KMS for a data key (GenerateDataKey). KMS returns two copies: the data key in plaintext (which you use to encrypt your data locally, then discard from memory) and the same data key encrypted under your master key (which you store alongside the data). To decrypt, you send the encrypted data key back to KMS, which returns the plaintext key, which decrypts the data. Why the envelope? Master keys are precious — every use is logged in CloudTrail and subject to key policies. Data keys do the bulk work so the master key is touched rarely. The exam's phrasing: "the data is encrypted with a data key, which is itself encrypted with a customer managed key." If a question asks which KMS API generates the key used for local encryption, it is GenerateDataKey; if it asks which decrypts the envelope to recover it, Decrypt.

Key Types, Grants, and Rotation

KMS keys come in three flavors. AWS managed keys (named aws/service-name, like aws/s3) are created automatically, cannot be managed or deleted by you, and rotate automatically every year. Customer managed keys (CMKs) are yours: you control the key policy, enable/disable, schedule deletion, and choose whether to enable automatic annual rotation (recommended — rotation keeps old key material so previously encrypted data still decrypts). AWS owned keys are used transparently by services with no visibility to you. Two features the exam probes: grants and key policies . A grant is a way to delegate permission to use a key — say, letting an EC2 Auto Scaling service use your key to launch encrypted volumes — without editing the key policy. Grants are temporary-friendly and ideal for AWS services acting on your behalf. The key policy is the resource-based policy attached to the key itself; it is the only way to share a key across accounts, because KMS never allows cross-account use without an explicit key-policy allow.

Exam tip

"Share an encrypted S3 object / EBS snapshot with another account" means two things must happen: the resource policy (bucket policy / snapshot permission) allows the account, AND the KMS key policy allows the account to use the key. Miss the key policy and the share silently fails — the exam's classic double-requirement trap.

Exercise

Exercise 2. Your application encrypts files with SSE-KMS using a customer managed key, then shares them with a partner's AWS account by adding the partner to the bucket policy. The partner gets AccessDenied on download. What is missing? Answer: The KMS key policy must also grant the partner account kms:Decrypt (and usually kms:DescribeKey). S3 checks the bucket policy and says yes; then it asks KMS to decrypt the data key, KMS checks the key policy, finds no allow for the partner, and denies. Why not fix it with an IAM policy in the partner account? Because KMS cross-account access requires the key policy's explicit allow — the caller's identity policy alone is never sufficient for KMS. Why not switch to SSE-S3? That would work (AWS managed keys need no key policy edits), but it abandons the customer managed key the requirement presumably chose for control/audit reasons.

Encryption at Rest and in Transit: The Developer's Checklist

At rest , every storage service encrypts by default now — but the type of encryption is the developer's choice and the exam's question: • S3: SSE-S3 (AES-256, AWS managed keys, no key management), SSE-KMS (your KMS key, CloudTrail audit trail of every decrypt, extra cost per request), SSE-C (you provide the key with each request — AWS never stores it), DSSE-KMS (dual-layer for the paranoid). Set a default encryption on the bucket so nothing lands unencrypted. Enforce TLS-only access with a bucket policy condition on aws:SecureTransport. • EBS and EFS: encrypted with KMS; EBS encryption by default can be enabled account-wide. • DynamoDB: encrypted at rest by default with an AWS owned key; optionally switch to a customer managed KMS key for control. • SQS and SNS: server-side encryption with KMS (SqsManagedSse or your CMK). Note the trap: when SQS uses SSE-KMS, any service writing to the queue (like S3 event notifications or CloudWatch) needs kms:Decrypt/GenerateDataKey permission too — encrypted queues break producers whose roles lack KMS rights. • RDS: KMS encryption at rest, set at creation. In transit , it is TLS everywhere: API Gateway, ALB, CloudFront, and service endpoints all speak HTTPS. Your code's job is to require it — bucket policies denying non-TLS, API Gateway with TLS 1.2 minimum, no HTTP listeners left open "for testing."

Exam tip

SSE-KMS vs SSE-S3 in one line: choose KMS when you need an audit trail of who decrypted what (CloudTrail logs every KMS call) or customer control of the key; choose SSE-S3 when you just want encryption with zero management. The exam phrases the KMS need as "must audit data access" or "must control key rotation."

Secrets Manager vs. Parameter Store: Where Secrets Live

Daniel's leaked key was in a git repo. The exam wants it in one of two places, and choosing correctly is a recurring question. AWS Secrets Manager is the purpose-built secrets service. Its killer feature is automatic rotation : you attach a Lambda rotation function and Secrets Manager rotates database credentials, API keys, and OAuth tokens on a schedule, with built-in support for RDS, Redshift, and DocumentDB. It supports resource-based policies (so cross-account secret sharing works), replicates secrets across regions, and notifies on rotation via EventBridge. It costs $0.40 per secret per month — the exam occasionally uses cost to steer you away from it for thousands of non-rotating values. Systems Manager Parameter Store holds configuration as parameters in hierarchies (/prod/payments/db-password). SecureString parameters are encrypted with KMS. The Standard tier is free for the first 10,000 parameters. But: no native automatic rotation — you build rotation yourself — and no resource-based policies (cross-account sharing is harder). The decision rule the exam tests: needs automatic rotation or cross-account sharing -> Secrets Manager. Plain config or non-rotating secrets at scale -> Parameter Store. And both beat environment variables for anything sensitive — though Lambda environment variables are encrypted at rest, anyone with lambda:GetFunction can read them in plaintext in the console, so they are not a secrets store.

Exam tip

"Database password must rotate every 30 days" Secrets Manager, full stop. "Store 5,000 application config values cheaply" Parameter Store Standard (free tier). If an option says Parameter Store with automatic rotation, it is wrong — that is Secrets Manager's job.

Exercise

Exercise 3. Your Lambda function needs a third-party API key. The key never changes. The team wants the cheapest secure storage, and the function runs 10 million times a month. Where do you put the key, and how does the function read it? Answer: Parameter Store SecureString (Standard tier, free). The function reads it at startup with ssm:GetParameter (decrypting with the KMS key), ideally caching it outside the handler so it is fetched once per execution environment, not per invocation. Why not Secrets Manager? It would work, but $0.40/month per secret plus $0.05 per 10,000 API calls adds cost for a never-rotating key — the requirement says cheapest. Why not a Lambda environment variable? Anyone with read access to the function configuration sees the key in plaintext in the console, and it cannot be shared or versioned — it fails the "secure" requirement. Why not hardcode it? It lands in the deployment package, visible to anyone with S3/code access and forever in version history.

Cognito: Authentication vs. Authorization for Your Users

Amazon Cognito confuses everyone exactly once. It has two halves with similar names and opposite jobs. Learn the split and the exam's Cognito questions become free points. User pools handle authentication — sign-up, sign-in, MFA, password policies, email/phone verification, and a hosted UI you can drop into your app. When a user signs in, the user pool returns JWT tokens : an ID token (who the user is), an access token (what the user may do in your app), and a refresh token (opaque, used to get new tokens). Lambda triggers let you customize flows (pre-sign-up validation, post-confirmation actions). Note carefully: user pool tokens are not AWS credentials. They prove identity to your application, not to AWS services. Identity pools (federated identities) handle authorization against AWS . They take an identity — from your user pool, from Google/Facebook/Apple login, from SAML, or even unauthenticated guest access — and exchange it for temporary AWS credentials via STS. Your mobile app then calls DynamoDB or S3 directly with those credentials, scoped by the IAM roles attached to the identity pool (one role for authenticated users, optionally a different, weaker role for guests). The exam's favorite Cognito trap is swapping the two: "use an identity pool to add MFA to sign-in" (wrong — MFA is a user pool feature) or "use a user pool to give the app S3 access" (wrong — user pools issue no AWS credentials; you need the identity pool in front of STS).

API Gateway Authorization: Guarding the Front Door

Your API is a door; authorization decides who walks through. API Gateway offers four mechanisms, and the exam tests which fits: • IAM authorization: callers sign requests with SigV4 (like any AWS API call). Best for internal APIs consumed by your own services, EC2 instances, or CLI users — anything that already holds AWS credentials. No good for browser or mobile users. • Cognito user pool authorizer: API Gateway validates the JWT from your user pool itself — no code needed. Best for mobile/web apps whose users sign in through Cognito. • Lambda authorizer (custom authorizer): your own Lambda function implements any logic — validate a custom header token, check a database, call an external IdP — and returns an IAM policy allowing or denying the request. Comes in TOKEN (single header) and REQUEST (multiple inputs) flavors, and results are cacheable by token to avoid re-invoking on every call. Best when auth logic is bespoke. • Resource policies on the API itself: IP whitelisting, VPC/VPCE-only private APIs. And the exam's beloved trap: API keys are not authorization. API keys plus usage plans control throttling and quotas per client — they identify which client is calling for metering, but anyone holding the key gets in. If a question asks how to secure an API and offers "API key," it is wrong unless the real answer is about rate limiting.

Exam tip

Match the caller to the authorizer: AWS-native callers (services, SDKs) IAM; Cognito-signed-in app users Cognito user pool authorizer; weird/custom schemes (legacy tokens, header checks) Lambda authorizer. And any answer claiming API keys authorize access is a trap — they throttle, not authenticate.

Exercise

Exercise 4. A single-page web app lets users sign in with email and password, then calls your API Gateway REST API. Unauthenticated visitors must get read-only access to public endpoints. Which Cognito and API Gateway setup? Answer: A user pool for sign-in (with MFA optional), federated into an identity pool configured with two roles: an authenticated role and an unauthenticated (guest) role limited to read-only actions. API Gateway uses a Cognito user pool authorizer on the private endpoints (validates the JWT) and leaves public endpoints open or lightly throttled. Why not IAM authorization? Browser users hold no AWS credentials — SigV4 signing in a SPA is impractical. Why not a Lambda authorizer? It would work but reinvents what the user pool authorizer does natively — JWT validation with zero code. Why skip the identity pool? Then the app could authenticate users but never obtain temporary AWS credentials for direct service calls.

SNS Message Filtering: One Topic, Many Audiences

Picture a food-delivery app that publishes every order event to a single SNS topic: new orders, cancellations, driver assignments, refunds. The kitchen display only cares about new orders. The refunds service only cares about refunds. Without filtering, every subscriber gets every message and wastes effort discarding the irrelevant ones — or worse, you end up creating a separate topic per event type and drowning in topic sprawl. Message filtering solves this with filter policies . Each subscription gets a filter policy — a JSON document matching on message attributes (not the message body). When a publisher sends a message, it attaches attributes like eventType: "refund" or region: "us-east-1". SNS evaluates each subscription's filter policy against those attributes and delivers the message only to matching subscribers. One topic, many audiences, each receiving exactly what it needs. The exam tests the mechanics: filter policies support exact string matching, anything-but matching, prefix matching, numeric comparisons, and exists checks. They apply per-subscription, so two SQS queues subscribed to the same topic can each receive a different slice of the traffic. And the classic trap — filtering works on message attributes , never on the message body. If a question says a filter policy inspects the JSON payload, that is wrong; attributes must be set explicitly at publish time.

Exam tip

"Different subscribers need different subsets of messages from one topic" SNS filter policies on message attributes. Remember: attributes, not body — and each subscription carries its own policy.

Lambda Permissions: Execution Role vs. Resource Policy

Lambda has two permission directions, and the exam separates students who see them from those who blur them: • The execution role (identity-based) controls what the function can do outbound: write CloudWatch Logs, read DynamoDB, publish to SNS. Every function needs logs:CreateLogGroup/CreateLogStream/PutLogEvents or it runs blind. This is the role you pass at CreateFunction. • The resource-based policy (function policy) controls what can invoke the function inbound: S3 event notifications, SNS topics, API Gateway, EventBridge rules, or another AWS account. You manage it with lambda:AddPermission / RemovePermission. When you wire an S3 trigger in the console, AWS adds this permission silently — when you do it in CloudFormation or Terraform, you must add it, and the exam knows beginners forget. The mental model: execution role = the function's badge for leaving the building; resource policy = the guest list at the function's door.

Never Hardcode Credentials: The Rule Behind Every Question

Pulling the chapter together: the exam's security questions are variations on one principle — credentials must be short-lived, least-privilege, and never embedded in code. The mechanisms, fastest to slowest to recall: • Code on AWS needs AWS access -> IAM role (execution role, task role, instance profile), never an IAM user key. • Code needs a secret -> Secrets Manager (rotating) or Parameter Store SecureString (static), never environment variables for true secrets, never source control, never the deployment package. • A human or pipeline outside AWS needs access -> STS temporary credentials (AssumeRole, OIDC federation), never a long-lived access key. • The SDK finds credentials through the provider chain : explicit config -> environment variables -> shared credentials file -> container/instance metadata. If a question asks why the SDK used the wrong credentials, walk the chain top-down.

Exam tip

When a scenario's "current design" includes an access key in code, in an env var, or in a repo, the correct answer almost always removes it — the only question is what replaces it: role for AWS access, Secrets Manager/Parameter Store for secrets, STS for external parties. Spot the hardcoded credential and you have half the answer before reading the options.

End-of-Chapter Test

1. An application runs on an EC2-hosted server fleet. The application needs to read objects from an S3 bucket. The security team forbids long-term credentials on the servers. What should the developer implement? A) Attach an IAM role to the EC2 instances via an instance profile and grant the role S3 read permissions B) Embed the S3 bucket's access credentials in the application source code C) Make the S3 bucket public so no credentials are needed D) Create an IAM user with programmatic access and store its access key in the application's config file

2. A developer needs to grant a Lambda function in Account A permission to publish to an SNS topic in Account B) The topic already has a resource-based policy allowing Account A's function role. The publish calls still fail with AccessDenied. What is the most likely missing piece? A) The SNS topic needs a KMS key policy update B) The Lambda execution role's identity-based policy must also allow sns:Publish on the topic C) The SNS topic must be converted to a FIFO topic D) The Lambda function needs a VPC configuration

3. A company encrypts sensitive files in S3 with SSE-KMS using a customer managed key. Auditors require a record of every decryption event showing which IAM principal accessed which object. Which feature satisfies this? A) VPC Flow Logs B) S3 server access logging C) AWS CloudTrail logging of KMS API calls D) S3 Inventory reports

4. An application stores 8,000 non-rotating configuration values. The team wants the cheapest secure option with KMS encryption. What should they use? A) Lambda environment variables B) A DynamoDB table with client-side encryption C) Secrets Manager with one secret per value D) Parameter Store Standard tier with SecureString parameters

5. A mobile app lets users sign in with their email addresses and must also let the app write user profile photos directly to S3. Which Cognito configuration achieves this? A) A user pool for sign-in federated into an identity pool that vends temporary AWS credentials scoped to the user's photo prefix B) An identity pool alone, using guest access for all users C) A user pool with a Lambda trigger that attaches an IAM user access key to each user D) A user pool with MFA, using the ID token to call S3 directly

6. A REST API built on API Gateway serves a partner's backend servers. The partner's servers already hold IAM credentials for their AWS account, and all traffic is server-to-server. Which authorization approach is simplest and most appropriate? A) A Cognito user pool authorizer B) IAM authorization with SigV4-signed requests C) API keys distributed to the partner D) A Lambda authorizer that checks a static bearer token

7. An S3 bucket is configured to send event notifications to an SQS queue, and the queue uses SSE-KMS with a customer managed key. Notifications are failing to arrive. What is the most likely cause? A) Event notifications do not support encrypted queues B) The SQS queue must be changed to a FIFO queue C) The S3 service principal lacks kms:GenerateDataKey permission on the KMS key D) The bucket policy is missing s3:GetObject

8. A developer's CI/CD pipeline runs on a third-party hosted service and needs to deploy to AWS. The security team forbids storing long-term AWS credentials in the pipeline configuration. What should the developer implement? A) Store the access key in the pipeline's encrypted variables B) Give the pipeline the root account's MFA device C) Create an IAM user and rotate its access key weekly via a Lambda function D) Configure OIDC federation so the pipeline assumes an IAM role via AssumeRoleWithWebIdentity, receiving short-lived credentials per run

9. A company uses a customer managed KMS key to encrypt EBS volumes. An Auto Scaling group needs to launch instances with encrypted volumes, but the security team does not want to modify the key policy. Which KMS feature allows this delegation? A) A KMS grant to the Auto Scaling service principal B) An IAM policy on the Auto Scaling service role C) Enabling automatic key rotation on the customer managed key D) Creating an alias for the KMS key

10. A developer is reviewing an API Gateway REST API that uses API keys distributed to partners. The security team asks whether the API is properly secured. What is the correct assessment? A) Yes — API keys authenticate each partner's requests B) Yes — as long as the keys are rotated every 90 days C) No — API keys identify callers for throttling and quotas but do not authorize access; a real authorizer (IAM, Cognito, or Lambda) is needed D) No — API keys must be replaced with OAuth tokens issued by the partners

11. A Lambda function needs to encrypt small pieces of user data before storing them in DynamoDB. The developer wants to avoid calling KMS for every single encryption operation while keeping the master key usage auditable. Which approach fits? A) Call KMS Encrypt directly on each data item with the customer managed key B) Use envelope encryption: call GenerateDataKey once, encrypt data locally with the plaintext data key, and store the encrypted data key alongside the data C) Store the data unencrypted and rely on DynamoDB's default encryption D) Generate a random AES key in code and embed it in the function's environment variables

Answer Key

1. A — An instance profile gives each EC2 instance temporary credentials via its IAM role automatically; the SDK picks them up with no stored keys. Why not D? An IAM user's access key is exactly the long-term credential the requirement forbids — config files get copied, backed up, and leaked. Why not B? Source code is the worst credential store: it ships to every clone and lives forever in git history. Why not C? Public buckets expose the data to the entire internet — the opposite of the security requirement. 2. B — Cross-account access needs allows on both sides: the SNS resource policy in Account B opens the door, but the caller's identity-based policy in Account A must also permit sns:Publish. One side alone is never enough across accounts. Why not A? KMS only matters if the topic is encrypted with a customer managed key — nothing in the scenario says it is. Why not C? FIFO vs standard affects ordering and deduplication, not permissions. Why not D? VPC configuration affects network reachability, not IAM authorization. 3. C — Every KMS decrypt is a CloudTrail-logged API call recording the caller identity, key, and timestamp — a complete audit trail of who decrypted what. Why not A? VPC Flow Logs capture network traffic, nothing about data access. Why not B? S3 access logs record requests but not the cryptographic identity behind KMS envelope decryption. Why not D? Inventory reports list objects and metadata, not access events. 4. D — Parameter Store Standard tier is free for the first 10,000 parameters and SecureString gives KMS encryption; 8,000 static values fit perfectly and cost nothing. Why not A? Environment variables are visible in plaintext to anyone with function read access and cannot be centrally managed. Why not B? It works technically but means building your own encryption, access control, and hierarchy — reinventing Parameter Store at higher effort. Why not C? Secrets Manager at $0.40/secret/month × 8,000 = $3,200/month for values that never rotate — wildly wasteful. 5. A — The user pool authenticates (proves who the user is); the identity pool exchanges that identity for temporary AWS credentials scoped by IAM role to the user's own S3 prefix. Why not B? Guest access gives every user the same unauthenticated role with no identity — you cannot scope photos per user. Why not C? Minting IAM users per app user is an anti-pattern: unmanageable at scale and long-term keys again. Why not D? ID tokens are JWTs for your application — they are not AWS credentials and S3 will not accept them. 6. B — Server-to-server callers with existing IAM credentials can sign requests with SigV4 natively — no tokens to manage, no extra infrastructure. Why not A? Cognito user pools serve human sign-in flows, not backend servers holding IAM credentials. Why not C? API keys identify callers for throttling/quotas; they do not authorize — anyone with the key is "authorized." Why not D? A Lambda authorizer adds latency, cost, and code for a problem SigV4 already solves. 7. C — With SSE-KMS on the queue, S3 (the producer) must be able to call kms:GenerateDataKey to encrypt each message; without that grant on the key policy or the producer's role, delivery fails. Why not A? Encrypted queues fully support event notifications — the failure is the missing KMS grant, not a feature gap. Why not B? FIFO affects ordering, not encryption or delivery permissions. Why not D? s3:GetObject governs reading objects, not sending event notifications. 8. D — OIDC federation (AssumeRoleWithWebIdentity) lets the external pipeline prove its identity to AWS and receive temporary credentials per run — no stored secrets at all. Why not A? Encrypted variables are still long-term credentials, visible to pipeline admins and exfiltrated with one misconfigured export. Why not B? Sharing root MFA breaks every AWS security rule at once — root must never be used for workloads. Why not C? Weekly rotation still leaves a long-term key sitting in the pipeline config between rotations — and in every backup of it. 9. A — Grants delegate key usage to AWS services acting on your behalf without editing the key policy — the standard pattern for Auto Scaling with encrypted volumes. Why not B? The service's IAM policy alone is insufficient; KMS checks the key policy or a grant for permission. Why not C? Rotation replaces key material annually; it does not delegate usage permission. Why not D? An alias is just a friendly name for the key — it grants no permissions. 10. C — API keys meter and throttle; they do not authenticate. Anyone holding the key is treated as authorized. Why not A? This is the exam's classic trap — API keys are not an authorization mechanism. Why not B? Rotation improves hygiene but does not turn a metering key into authentication. Why not D? The fix is adding a proper authorizer on the API Gateway side, not changing what the partners issue. 11. B — Envelope encryption is KMS's designed pattern — the data key does bulk work locally while the master key is touched rarely (each use logged in CloudTrail). Why not A? Calling KMS per item adds latency and cost, and hammers the master key unnecessarily. Why not C? Default encryption protects at rest but gives the application no field-level control or per-item audit. Why not D? Hardcoded keys in environment variables are visible in plaintext and unmanageable — the exact anti-pattern the exam punishes.

Answer key