SaveMyCert
Log in
5 of 5 free questions left today·for 30 a day
DVA-C02 practice

DVA-C02 sample questions — 25 answered and explained

25 DVA-C02 sample questions written to the official AWS Certified Developer – Associate exam guide, grouped by exam domain and weighted like the real exam. Each shows the correct answer, why every other option is wrong, and the lesson that teaches it. None of them repeat the examples on the other DVA-C02 practice pages.

On this page
25
answers included
Full bank
260
on the practice page
Domains
4
weighted like the exam
Free, no account
5/day
a free account allows 30 a day

Domain 1: Development with AWS Services

32% of the DVA-C02 exam, so 8 of the 25 questions on this page.

Question 1Development with AWS Services

An application calls a third-party shipping-rate API. During an extended outage of that API, every request tied up a thread for the full timeout before failing, exhausting the application's thread pool and degrading unrelated features. Timeouts and retries with backoff are already in place. Which pattern should the developer add?

Choose one.

  • a
    Raise the timeout on calls to the shipping-rate API.

    A longer timeout holds each thread even longer against a dead dependency, making the exhaustion worse.

  • b
    Increase the number of retry attempts with backoff.

    During a full outage every retry also fails after waiting; more attempts mean more threads waiting longer, not fewer.

  • c
    Enlarge the application's thread pool and add more instances.

    Extra capacity postpones the exhaustion but threads are still consumed waiting on a dependency that is known to be down.

  • d
    Implement a circuit breaker that opens after consecutive failures so calls fail fast or serve a fallback until trial calls succeed. Correct

    An open circuit stops sending calls to the dead dependency — requests fail fast or get a fallback instead of holding threads, and trial calls after a cooling period detect recovery.

The concept

The circuit breaker pattern: stop calling a failing dependency, fail fast or serve a fallback, and probe for recovery after a cooling-off period.

Why that’s the answer

Timeouts and backoff retries handle transient errors, but during an extended outage they still let every request wait out its timeout, which is what exhausted the thread pool. A circuit breaker adds the missing behavior: after a threshold of consecutive failures the circuit opens and subsequent calls fail immediately (or return a fallback such as cached rates), so threads are freed instantly; after a cooling period, a few trial calls test recovery before the circuit closes. Raising the timeout or the retry count increases the time threads spend waiting on a dead dependency. Adding capacity only delays exhaustion while wasting resources. This is exactly the resilience skill DVA-C02 v2.1 added for third-party integrations, whose availability and rate limits you do not control.

How to reason it out
  1. Note that transient-error tooling (timeouts, backoff retries) is already in place and the failure is an extended outage.
  2. Identify the damage mechanism: threads held for the full timeout on every doomed call.
  3. Apply a circuit breaker: open after consecutive failures, fail fast or serve a fallback while open.
  4. After a cooling-off period, let trial calls test the dependency before closing the circuit.

Exam tip: Timeouts and retries handle transient errors; an extended third-party outage needs a circuit breaker that fails fast instead of tying up threads.

Application Development Patterns on AWS: Architecture, APIs and Messaging — the lesson that teaches this.

Question 2Development with AWS Services

A developer must expose a legacy HTTP backend through Amazon API Gateway. Clients send a modern JSON payload, but the backend expects a differently structured JSON document, and neither the clients nor the backend can be modified. How should the developer implement the transformation?

Choose one.

  • a
    Create an HTTP API with a proxy integration to the backend.

    HTTP APIs are built around proxy integrations and do not support mapping templates, so the request would pass through unchanged.

  • b
    Attach a request validator with a JSON Schema model for the backend's expected format.

    Request validators reject invalid requests with a 400; they validate payloads but never transform them.

  • c
    Create a REST API with a non-proxy integration and attach a mapping template written in VTL to the integration request. Correct

    Mapping templates on non-proxy REST API integrations reshape the client payload into what the backend expects — no code changes on either side.

  • d
    Customize a gateway response to rewrite the request body.

    Gateway responses customize the errors API Gateway itself generates (such as a 403 from an authorizer); they do not transform request payloads.

The concept

Request and response transformation in API Gateway lives in mapping templates — a REST API feature attached to non-proxy (custom) integrations.

Why that’s the answer

When neither side of an integration can change, the gateway must reshape the payload, and that is exactly what mapping templates do: written in Velocity Template Language and attached to the integration request (or response), they convert the client's JSON into the structure the legacy backend expects. This requires a REST API with a non-proxy integration — with a proxy integration API Gateway passes the request straight through, and HTTP APIs support only proxy-style behavior with no mapping templates at all. Request validators are the enforcement feature: they reject malformed requests but cannot rewrite them. Gateway responses only customize errors that API Gateway itself generates. When an exam stem mentions transforming payloads at the gateway, it is describing a REST API.

How to reason it out
  1. Establish the constraint: payload must be reshaped and neither client nor backend can change, so the gateway must transform.
  2. Recall that transformation is done by mapping templates in VTL, attached to non-proxy integrations.
  3. Recall the API-type rule: mapping templates are REST API features; HTTP APIs are proxy-only and cheaper but cannot transform.
  4. Eliminate validators (validate, not transform) and gateway responses (customize API Gateway's own errors).

Exam tip: Payload transformation at the gateway = REST API + non-proxy integration + VTL mapping template; HTTP APIs and proxy integrations pass requests through unchanged.

Application Development Patterns on AWS: Architecture, APIs and Messaging — the lesson that teaches this.

Question 3Development with AWS Services

A Lambda-backed REST API in Amazon API Gateway receives many requests that are missing required fields. The Lambda function rejects them, but every malformed request still invokes — and bills — the function. The team wants invalid requests rejected before they reach the backend, with the LEAST ongoing maintenance. What should the developer configure?

Choose one.

  • a
    Add validation logic at the top of the Lambda handler so requests fail faster.

    The function is still invoked and billed for every malformed request; the goal is to reject them at the gateway.

  • b
    Configure a request validator with required parameters and a JSON Schema model for the body. Correct

    Request validators reject invalid requests with a 400 before they ever reach — or bill — the backend, declaratively and without extra code.

  • c
    Attach an AWS WAF web ACL to the API stage.

    WAF filters web-exploit traffic patterns; it is not designed to enforce a JSON Schema of required fields on the request body.

  • d
    Create a usage plan with API keys to control the malformed requests.

    Usage plans manage throttling and quotas per API key; they cannot inspect or validate request structure.

The concept

Enforcing validation rules at the gateway: API Gateway request validators check required parameters and JSON Schema models before invoking the backend.

Why that’s the answer

Request validators are the REST API feature built for exactly this: declare which query strings and headers are required and attach a JSON Schema model for the body, and API Gateway rejects invalid requests with a 400 before the integration runs — so the Lambda function is neither invoked nor billed for them. Moving validation earlier inside the handler changes nothing about invocation cost. WAF operates on attack patterns and traffic filtering, not on schema conformance of legitimate-but-malformed API requests. Usage plans meter and throttle keyed clients; they have no view into payload validity. The declarative model also satisfies the least-maintenance qualifier: the schema lives in API configuration rather than code.

How to reason it out
  1. Identify the cost problem: malformed requests are invoking the backend before being rejected.
  2. Recall that REST APIs can validate at the gateway with request validators.
  3. Attach required-parameter checks and a JSON Schema model so invalid requests get a 400 before the integration.
  4. Eliminate in-handler validation (still billed), WAF (exploit filtering), and usage plans (throttling and quotas).

Exam tip: Use API Gateway request validators (required parameters + JSON Schema models) to reject malformed requests with a 400 before they invoke or bill the backend.

Application Development Patterns on AWS: Architecture, APIs and Messaging — the lesson that teaches this.

Question 4Development with AWS Services

A REST API in Amazon API Gateway uses a non-proxy integration with a legacy backend that always returns HTTP 200, embedding an error string such as "ITEM_NOT_FOUND" in the body when a resource is missing. The backend cannot be changed, and clients must receive a proper 404 status code. What should the developer configure?

Choose one.

  • a
    Customize the gateway response for the 404 status.

    Gateway responses customize errors API Gateway itself generates; they never fire for a 200 returned by the backend.

  • b
    Attach a mapping template to the integration request that rewrites the status code.

    Integration-request templates transform the incoming payload on its way to the backend; they run before the backend responds and cannot set the response status.

  • c
    Define an integration response whose selection pattern matches the backend's error string and maps it to a 404 method response. Correct

    Integration responses match patterns (such as a regex over the error message) in the backend response and map them to the method response status the client should see.

  • d
    Migrate the API to an HTTP API and add a 404 route.

    HTTP APIs use proxy integrations that pass the backend response through; status-code overrides are a REST API feature, and a route does not remap backend statuses.

The concept

Overriding status codes in API Gateway: integration responses map patterns in the backend response to the method response status the client receives.

Why that’s the answer

Status-code overriding is configured in integration responses on a REST API: a selection pattern — for example a regex matching "ITEM_NOT_FOUND" — is evaluated against the backend response, and matches are mapped to the desired method response status, turning the backend's misleading 200 into a clean 404 with no backend change. Gateway responses are the wrong layer: they customize responses that API Gateway itself generates, such as the body and headers of a 403 from a failed authorizer, and are never triggered by a successful backend response. An integration-request mapping template runs in the request direction, before any response exists. HTTP APIs cannot help because they are proxy-only: the backend's status flows through untouched.

How to reason it out
  1. Recognize the requirement: remap a backend response (200 + error string) to a different client-facing status.
  2. Recall that this is the job of integration responses with selection patterns on a REST API.
  3. Configure a pattern matching the error string and map it to a 404 method response.
  4. Distinguish gateway responses (API Gateway's own errors) and note HTTP APIs pass backend statuses through unchanged.

Exam tip: To turn a backend error string into a proper HTTP status, use a REST API integration response selection pattern; gateway responses only customize API Gateway's own errors.

Application Development Patterns on AWS: Architecture, APIs and Messaging — the lesson that teaches this.

Question 5Development with AWS Services

An operations dashboard uses an AWS SDK list API to display all of a team's resources, but users report that only the first portion of resources ever appears. The response includes a NextToken value that the current code ignores. What should the developer do?

Choose one.

  • a
    Increase the SDK client's HTTP timeout so the full list can be returned in one call.

    The response is paginated by design, not truncated by a timeout — no timeout setting makes the service return every result in a single call.

  • b
    Use an SDK waiter to poll the API until all resources are returned.

    Waiters poll a resource until it reaches a target state (for example, active); they have nothing to do with paging through list results.

  • c
    Enable the SDK's adaptive retry mode on the client.

    Retry modes handle throttling and 5xx errors; a successful paginated response is not an error, so retries never fetch the remaining pages.

  • d
    Use the SDK's built-in paginator to iterate through pages until no continuation token remains. Correct

    List APIs return one page plus a continuation token; the SDK paginator handles the token loop so the application receives every page of results.

The concept

SDK pagination: list and query APIs return one page plus a continuation token, and the caller must loop — ideally with the SDK's built-in paginators.

Why that’s the answer

Seeing only the first batch of results while ignoring a NextToken is the textbook symptom of missing pagination. List APIs return a bounded page of results and a continuation token pointing at the rest; the SDK's paginators encapsulate the loop — request, read token, request again — until no token remains, which is more robust than a hand-rolled loop. Timeouts are irrelevant because pagination is by design, not a slow response. Waiters solve a different problem: polling until a resource reaches a target state, with backoff built in. Retry modes govern transient errors like throttling; a paginated 200 response is a success, so no retry behavior will ever surface page two.

How to reason it out
  1. Spot the symptom: only the first batch of results, with an unused NextToken in the response.
  2. Recall that list APIs are paginated: one page per call plus a continuation token.
  3. Use the SDK's built-in paginator to loop until the token is absent.
  4. Distinguish the other SDK features: waiters poll for resource state, retry modes handle transient errors.

Exam tip: An application that only ever sees the first page of results is ignoring the continuation token — use the SDK's paginators, not bigger timeouts or retries.

Application Development Patterns on AWS: Architecture, APIs and Messaging — the lesson that teaches this.

Question 6Development with AWS Services

Three separate applications consume the same Kinesis data stream. As volume grew, all three began falling behind and seeing read throttling, because they share each shard's 2 MB per second of read throughput. The team needs every application to have dedicated read throughput per shard with low-latency delivery. What should the developer do?

Choose one.

  • a
    Have each application poll less frequently with larger GetRecords batches.

    Slower polling adds latency and the applications still share the same 2 MB per second per shard — the contention is unchanged.

  • b
    Replace the stream with an SQS queue that all three applications poll.

    A queue deletes each message after one consuming application processes it, so three applications cannot independently read the same records, and per-shard ordering and replay are lost.

  • c
    Register each application as an enhanced fan-out consumer of the stream. Correct

    Enhanced fan-out gives each registered consumer its own dedicated 2 MB per second per shard with push delivery, removing the contention between the three applications.

  • d
    Split the stream's shards to increase total capacity.

    More shards raise aggregate throughput, but the three consumers still share each shard's standard 2 MB per second read pipe — dedicated per-consumer throughput requires enhanced fan-out.

The concept

Kinesis enhanced fan-out: each registered consumer gets a dedicated 2 MB per second per shard with push delivery, instead of sharing the standard read throughput.

Why that’s the answer

The bottleneck is stated precisely: multiple consumer applications competing for a shard's shared 2 MB per second of read throughput. Enhanced fan-out is the purpose-built fix — each registered consumer receives its own dedicated 2 MB per second per shard, delivered by push, so consumers stop throttling each other and latency drops. Splitting shards multiplies capacity and cost but leaves all consumers still sharing each individual shard's standard read pipe, so contention per shard persists. Switching to SQS breaks the requirements at a deeper level: messages are deleted once processed by one consuming application, so multiple independent readers of the same data — a defining Kinesis capability, along with replayable retention — are lost. Slower polling with bigger batches just trades throughput for latency without addressing the shared limit.

How to reason it out
  1. Identify the constraint: consumers share each shard's 2 MB per second standard read throughput.
  2. Note the requirement: dedicated throughput per consumer with low latency.
  3. Map this to enhanced fan-out: dedicated 2 MB per second per shard per registered consumer, push delivery.
  4. Reject resharding (consumers still share each shard's pipe) and SQS (one consuming application per queue, no replay).

Exam tip: When multiple Kinesis consumers contend for a shard's shared read throughput, register them as enhanced fan-out consumers for dedicated 2 MB per second per shard each.

Application Development Patterns on AWS: Architecture, APIs and Messaging — the lesson that teaches this.

Question 7Development with AWS Services

An IoT platform ingests telemetry from thousands of sensors. All readings from any single sensor must be processed strictly in the order they were produced, while the platform scales ingestion across sensors. Which design meets these requirements?

Choose one.

  • a
    Write readings to a Kinesis data stream using the sensor ID as the partition key. Correct

    The partition key is hashed to select a shard and ordering is guaranteed within a shard, so all of one sensor's readings stay in order while thousands of sensors spread across shards.

  • b
    Send readings to an SQS standard queue and process them with a fleet of consumers.

    Standard queues do not guarantee ordering, and messages are deleted after processing, so ordered per-sensor processing cannot be assured.

  • c
    Publish readings to an SNS topic with a Lambda subscriber per sensor type.

    SNS push delivery carries no ordering guarantee across deliveries, so readings from one sensor can be processed out of order.

  • d
    Write readings to a Kinesis data stream using a random value as the partition key.

    A random key spreads load well, but one sensor's readings land on different shards — and ordering is only guaranteed within a single shard.

The concept

Kinesis ordering semantics: the partition key selects the shard, and record order is guaranteed only within a shard — so the key must group the records that need ordering.

Why that’s the answer

Using the sensor ID as the partition key hashes all of one sensor's readings to the same shard, where Kinesis preserves their order, while thousands of distinct sensor IDs give the high cardinality that spreads load across shards for scale. A random partition key achieves the load spreading but destroys the requirement: one sensor's readings scatter across shards, and there is no cross-shard ordering. SQS standard queues provide best-effort ordering only, and SNS makes no ordering promise across its push deliveries. This is also why partition key choice is a design decision: the key must be exactly the identity that needs ordered processing, with enough distinct values to avoid a hot shard.

How to reason it out
  1. State the ordering unit: per sensor, not global.
  2. Recall that Kinesis guarantees order only within a shard, and the partition key chooses the shard.
  3. Set the partition key to the sensor ID so each sensor's readings share a shard and stay ordered.
  4. Check scale: thousands of sensor IDs are high-cardinality, spreading load evenly across shards.

Exam tip: To order records per entity in Kinesis, make the entity ID the partition key — ordering holds only within a shard, and the key decides the shard.

Application Development Patterns on AWS: Architecture, APIs and Messaging — the lesson that teaches this.

Question 8Development with AWS Services

An order service publishes order-created events to an Amazon EventBridge custom event bus. The fraud team needs only orders whose total exceeds 1000 routed to their review queue, while all other orders continue to standard processing. The developers must not add filtering code to any service. What should the developer configure?

Choose one.

  • a
    Subscribe the fraud queue to an SNS topic with a filter policy on the order total.

    The events flow through EventBridge, not SNS — and SNS filter policies primarily match message attributes, whereas this filter is on a value inside the event body.

  • b
    Insert a Lambda function between the bus and the fraud queue to inspect each event's total.

    This works but adds exactly the filtering code the requirement forbids — EventBridge can express the condition declaratively in a rule.

  • c
    Create an EventBridge rule whose event pattern uses numeric matching on the order total, with the fraud team's SQS queue as the target. Correct

    EventBridge rule patterns support numeric-range matching over any field in the event body, so routing high-value orders becomes configuration instead of code.

  • d
    Create a second event bus and have the order service publish high-value orders to it.

    This pushes the routing decision back into the producer's code — the exact coupling that content-based rules exist to remove.

The concept

EventBridge content filtering: rule event patterns can match exact values, prefixes, numeric ranges, and field existence over any field in the event body, moving routing logic into configuration.

Why that’s the answer

EventBridge rules are where content filtering lives: an event pattern with numeric matching on the order total routes only qualifying events to the fraud queue, while other rules carry the rest to standard processing — no service changes, no filtering code. The SNS option fails twice: the architecture already uses EventBridge, and SNS filter policies primarily match message attributes rather than arbitrary fields inside the payload body. A filtering Lambda works mechanically but violates the no-code constraint and adds a component to run and monitor. Publishing conditionally to a second bus moves the business rule into the producer, re-coupling it to a consumer's needs. This declarative routing on event content is precisely why EventBridge is chosen over SNS when routing depends on the payload.

How to reason it out
  1. Note the routing condition depends on a value inside the event body (order total above a threshold).
  2. Recall that EventBridge rule patterns support content filtering, including numeric ranges, on any body field.
  3. Create a rule with a numeric-match pattern targeting the fraud SQS queue; let other rules handle the rest.
  4. Reject answers that reintroduce code (Lambda filter, conditional publishing) or the wrong service (SNS attribute filtering).

Exam tip: Routing that depends on event content is an EventBridge rule pattern — including numeric-range matches — not consumer code or SNS attribute filters.

Application Development Patterns on AWS: Architecture, APIs and Messaging — the lesson that teaches this.

Domain 2: Security

26% of the DVA-C02 exam, so 7 of the 25 questions on this page.

Question 9Security

A microservice must call an internal REST API in Amazon API Gateway that is configured with AWS IAM authorization. What must the calling service do for its requests to be accepted?

Choose one.

  • a
    Include a valid API key in the x-api-key header.

    API keys identify clients for usage plans and throttling; they are not an authentication mechanism and do not satisfy IAM authorization.

  • b
    Attach a Cognito ID token to the Authorization header.

    Cognito JWTs are validated by Cognito or JWT authorizers; an IAM-authorized method expects a SigV4-signed request, not a bearer token.

  • c
    Sign each request with SigV4 using its IAM role's credentials, with the role granted execute-api:Invoke on the API. Correct

    IAM authorization requires callers to be AWS principals: requests must carry a valid SigV4 signature and the signing identity must hold execute-api:Invoke permission.

  • d
    Be registered in the API's usage plan.

    Usage plans meter and throttle known clients; membership in one proves no identity and grants no authorization.

The concept

API Gateway's IAM authorization authenticates callers as AWS principals: each request is signed with Signature Version 4 using the caller's credentials, and the caller must be allowed the execute-api:Invoke action on the API.

Why that’s the answer

Both halves are required — the SigV4 signature proves who is calling, and execute-api:Invoke permission on the caller's role authorizes the call. This is the natural fit for service-to-service traffic because every service already holds role credentials. API keys and usage plans are metering features, a recurring exam trap: they never authenticate. A Cognito token targets a different authorizer type and is simply not evaluated by an IAM-authorized method.

How to reason it out
  1. Grant the calling service's execution role execute-api:Invoke on the target API's ARN.
  2. Use the SDK or a signing library so requests are SigV4-signed with the role's temporary credentials.
  3. Include the session token header, since role credentials are temporary.
  4. API Gateway verifies the signature and evaluates IAM policy before invoking the backend.

Exam tip: IAM-authorized APIs need SigV4-signed requests from a principal holding execute-api:Invoke — API keys and usage plans are never authentication.

Authentication and Authorization on AWS: Cognito, IAM, and STS — the lesson that teaches this.

Question 10Security

An Amazon SQS queue in account A must receive messages from an application in account B. The developer wants to grant this access WITHOUT requiring the application to assume a role in account A. What should the developer configure?

Choose one.

  • a
    A resource-based queue policy in account A allowing the account B principal to call sqs:SendMessage, plus an identity-based policy in account B allowing the same action on the queue's ARN. Correct

    Resource-based policies grant cross-account access without role assumption, and across accounts both sides must allow: the queue policy grants the external principal and that principal's own policy grants the action.

  • b
    An identity-based policy in account A that names the account B application role as a principal.

    Identity-based policies have no Principal element and attach only to identities in their own account — they cannot grant access to another account's principals.

  • c
    An IAM user in account A whose access keys are shared with the application in account B.

    Sharing long-term access keys across accounts is the credential anti-pattern the role and resource-policy mechanisms exist to eliminate.

  • d
    Nothing can be configured — cross-account SQS access is only possible through sts:AssumeRole.

    Resource-based policies exist precisely to enable cross-account access without assuming a role; SQS queue policies support this directly.

The concept

Resource-based policies attach to the resource itself, carry a Principal element, and are the mechanism for granting another account access without creating a role to assume — but cross-account access requires both sides to allow.

Why that’s the answer

The queue policy in account A names the account B principal and allows sqs:SendMessage; account B must separately allow its application the same action on the queue's ARN — miss either side and the request is denied. An identity-based policy in account A cannot help because such policies name no principal and only govern account A's own identities. Shared access keys are always wrong. And role assumption is one valid cross-account pattern, but not the only one — the stem explicitly rules it out.

How to reason it out
  1. Attach a queue policy in account A with account B's principal and sqs:SendMessage on the queue.
  2. In account B, grant the application's role sqs:SendMessage on the queue's ARN.
  3. Verify no explicit deny exists on either side.
  4. The application sends messages directly with its own account B credentials.

Exam tip: Cross-account without AssumeRole = a resource-based policy on the resource plus an identity-based allow in the caller's account — both sides must say yes.

Authentication and Authorization on AWS: Cognito, IAM, and STS — the lesson that teaches this.

Question 11Security

An IAM user's identity-based policy allows s3:GetObject on a bucket's objects, but the bucket policy contains an explicit Deny for that user. What is the result when the user calls GetObject?

Choose one.

  • a
    The request is allowed because identity-based policies take precedence over bucket policies.

    No such precedence exists — identity-based and resource-based policies are evaluated together, and a deny in either wins.

  • b
    The result depends on which policy IAM evaluates first.

    Evaluation is not order-dependent; all applicable policies are considered together and the deny controls the outcome.

  • c
    The request is denied — an explicit deny overrides every allow. Correct

    Policy evaluation gives explicit deny absolute precedence: a deny in any applicable policy overrides all allows from any source.

  • d
    The request is allowed because, within one account, a single allow is sufficient.

    The single-allow rule applies only in the absence of an explicit deny — a deny anywhere still blocks the request.

The concept

IAM policy evaluation starts from an implicit deny, grants access on an explicit allow, and gives explicit deny absolute precedence over every allow, wherever each appears.

Why that’s the answer

The bucket policy's explicit Deny controls the outcome regardless of the identity policy's allow — this single rule resolves the question. There is no ranking between identity-based and resource-based policies and no first-evaluated-wins behavior; all applicable policies are combined. Within one account an allow from either policy family does normally suffice, but only when no explicit deny applies — which is exactly the condition violated here.

How to reason it out
  1. Gather all applicable policies: the user's identity-based policy and the bucket policy.
  2. Check for explicit denies first — the bucket policy has one for this user.
  3. Explicit deny overrides the identity policy's allow, so the request fails.
  4. Remove or scope the deny statement if the access should be permitted.

Exam tip: Explicit deny beats every allow — check for denies before reasoning about any allow.

Authentication and Authorization on AWS: Cognito, IAM, and STS — the lesson that teaches this.

Question 12Security

A security team wants reusable permissions policies that are scoped to only the specific actions and resource ARNs each workload needs, can be versioned, and can be attached to many application roles. Which policy type should the team use?

Choose one.

  • a
    Customer managed policies Correct

    Customer managed policies are authored by you, support versioning, and attach to many principals — the least-privilege workhorse.

  • b
    AWS managed policies

    AWS maintains these for convenience and they tend to be broad; you cannot edit them down to specific resource ARNs.

  • c
    Inline policies

    An inline policy is embedded in a single principal and deleted with it — it cannot be reused or attached across many roles.

  • d
    Service control policies

    SCPs are organization-level guardrails that set maximum permissions; they never grant access to anything.

The concept

IAM policies come in three packages — AWS managed (maintained by AWS, broad), customer managed (you author, version, and reuse), and inline (bound to one principal) — with service control policies operating separately as organizational guardrails.

Why that’s the answer

Every stated requirement — precise scoping to actions and ARNs, versioning, reuse across many roles — describes customer managed policies. AWS managed policies cannot be edited and are deliberately broad, making tight least privilege impossible. Inline policies pin permissions to one principal, defeating reuse. SCPs are the trap for readers skimming for "managed": they constrain what identities in an organization may ever do but grant nothing.

How to reason it out
  1. Author a policy with specific Action entries and resource ARNs instead of wildcards.
  2. Create it as a customer managed policy so it has its own ARN and version history.
  3. Attach it to every application role that needs exactly those permissions.
  4. Update centrally by publishing a new policy version; all attached roles inherit it.

Exam tip: Customer managed policies are the tool for reusable, versioned, least-privilege permissions; AWS managed are broad, inline are single-principal, SCPs never grant.

Authentication and Authorization on AWS: Cognito, IAM, and STS — the lesson that teaches this.

Question 13Security

All users of a REST API authenticate through an Amazon Cognito user pool. The team wants API Gateway to reject requests with missing or invalid tokens while building and operating the LEAST custom code. Which authorizer should the team configure?

Choose one.

  • a
    A Lambda authorizer that validates the user pool tokens

    It works, but the team must write, run, patch, and monitor an authorizer function to duplicate validation API Gateway can do natively.

  • b
    A Cognito user pool authorizer Correct

    The Cognito authorizer natively validates the token's signature, expiry, and issuer against the user pool — zero authorization code to write or operate.

  • c
    AWS IAM authorization

    IAM authorization expects SigV4-signed requests from AWS principals; the app's users hold Cognito JWTs, not AWS credentials.

  • d
    API keys with a usage plan

    API keys meter and throttle known clients; they do not authenticate users and cannot reject invalid identity tokens.

The concept

API Gateway offers three protection mechanisms — Cognito authorizers for user pool JWTs, Lambda authorizers for custom logic, and IAM authorization for SigV4-signed AWS callers — and the right one follows from who the caller is and what they carry.

Why that’s the answer

The callers carry Cognito user pool JWTs, so the built-in Cognito authorizer validates signature, expiry, and issuer with nothing to build — the least-code answer by construction. A Lambda authorizer is for tokens Cognito validation cannot handle (third-party, legacy, custom schemes); here it would be redundant operational burden. IAM authorization does not fit users holding JWTs. API keys are the recurring non-answer: metering, never authentication.

How to reason it out
  1. Identify what callers present: JWTs issued by a Cognito user pool.
  2. Create a Cognito authorizer on the API referencing that user pool.
  3. Attach the authorizer to the API methods and require it.
  4. Have clients send the appropriate token; invalid or missing tokens are rejected before the backend runs.

Exam tip: User pool JWTs → Cognito authorizer (no code); custom token schemes → Lambda authorizer; AWS principals → IAM authorization.

Authentication and Authorization on AWS: Cognito, IAM, and STS — the lesson that teaches this.

Question 14Security

A REST API uses a Lambda authorizer that checks each caller's token against a permissions database. An administrator removes a user's record from that database, but the user can still invoke the API successfully for several minutes afterward. What is the MOST likely cause?

Choose one.

  • a
    API Gateway caches the authorizer's policy result, five minutes by default, so recent decisions are reused without re-invoking the function. Correct

    Authorizer results are cached per token so the function does not run on every request — a revoked user keeps access until the cached allow expires.

  • b
    The Lambda authorizer runs asynchronously, so denials take effect on a delay.

    Authorizers run synchronously in the request path; API Gateway waits for the decision before invoking the backend.

  • c
    API Gateway skips the authorizer while the caller's token has not yet expired.

    API Gateway never skips a configured authorizer based on token lifetime; the authorizer (or its cached result) is consulted for every request.

  • d
    The permissions database takes up to 15 minutes to replicate deletions.

    Nothing in the scenario suggests replication lag, and the characteristic several-minute window matches the authorizer cache default.

The concept

A Lambda authorizer returns a policy decision that API Gateway caches — five minutes by default, configurable — so authorization logic does not execute on every request.

Why that’s the answer

The user's earlier request produced an allow that API Gateway cached; until the cache entry expires, the authorizer function never sees the revocation. That is exactly the observed behavior: access persists for a few minutes, then stops. Authorizers are synchronous, so option b is wrong; API Gateway never bypasses an authorizer because a token is unexpired; and a 15-minute database replication delay is invented — the several-minute window is the signature of the 300-second default cache.

How to reason it out
  1. Recognize the symptom: revoked permissions still working briefly points to result caching.
  2. Recall the Lambda authorizer cache TTL — 300 seconds by default.
  3. Shorten or disable the cache TTL if revocation must take effect faster, trading off latency and cost.
  4. Balance the cache TTL against how quickly revocations must propagate.

Exam tip: Lambda authorizer decisions are cached (default five minutes) — revocations lag until the cached allow expires.

Authentication and Authorization on AWS: Cognito, IAM, and STS — the lesson that teaches this.

Question 15Security

A team plans to protect a new public REST API in API Gateway by requiring an API key on every request and nothing else. What should a security reviewer point out?

Choose one.

  • a
    API keys are sufficient as long as they are rotated regularly.

    Rotation does not change what a key is — a client identifier for metering, not proof of identity.

  • b
    API keys work only with private APIs, so the API must be made private first.

    API keys work with public APIs; the flaw is what they are for, not where they work.

  • c
    API keys are secure because API Gateway encrypts them in transit.

    TLS protects the key on the wire but a key is still just a shared static string, not an authentication mechanism.

  • d
    API keys identify clients for usage plans and throttling but do not authenticate anyone — an authorizer (Cognito, Lambda, or IAM) is still required. Correct

    Keys meter and throttle known clients; they prove no identity, so the API remains effectively unauthenticated without an authorizer.

The concept

API keys in API Gateway exist for usage plans: identifying known clients to meter and throttle them. They are not an authentication or authorization mechanism.

Why that’s the answer

An API "secured" only by API keys has no authentication at all — anyone holding the static string passes, and keys are routinely embedded in clients where they leak. Real protection comes from an authorizer matched to the caller: Cognito for user pool JWTs, Lambda for custom schemes, IAM for SigV4-signed AWS principals. Rotation, making the API private, and transit encryption all miss the category error: a metering identifier cannot become an identity proof.

How to reason it out
  1. Classify the mechanism: API keys belong to usage plans (metering and throttling).
  2. Note what is missing: no identity verification of the caller.
  3. Add an authorizer suited to the callers — Cognito, Lambda, or IAM.
  4. Keep API keys, if desired, purely for per-client quotas alongside the authorizer.

Exam tip: API keys meter and throttle — any design using them as the security mechanism is a distractor.

Authentication and Authorization on AWS: Cognito, IAM, and STS — the lesson that teaches this.

Domain 3: Deployment

24% of the DVA-C02 exam, so 6 of the 25 questions on this page.

Question 16Deployment

An organization wants its npm builds to consume only approved package versions, keep working even if a package is removed from the public registry, and publish private internal packages for other teams. Which AWS service meets these requirements with the LEAST operational overhead?

Choose one.

  • a
    Amazon S3 with bucket versioning

    S3 stores objects but speaks no package-manager protocol — npm clients cannot resolve, install, or publish packages against a plain bucket.

  • b
    Amazon ECR with tag immutability enabled

    ECR is a registry for container images, not npm packages; tag immutability protects image tags, not library versions.

  • c
    A self-managed npm registry running on Amazon EC2

    A self-hosted registry can meet the requirements but demands patching, scaling, and backups — far from the least operational overhead.

  • d
    AWS CodeArtifact Correct

    CodeArtifact is a managed package repository for npm, PyPI, Maven, and NuGet that proxies public registries through upstream connections, caches pulled packages, and hosts private internal packages.

The concept

AWS CodeArtifact is the managed repository for package dependencies — npm, PyPI, Maven, and NuGet — with upstream connections that proxy and cache public registries and support for publishing private packages.

Why that’s the answer

CodeArtifact answers all three requirements natively: builds pull only from the organization's repository (controlling approved versions), cached upstream packages survive removal from the public registry, and teams can publish internal packages privately — all without servers to run. S3 cannot speak the npm protocol, ECR handles container images rather than language packages, and running a registry on EC2 is the opposite of low operational overhead.

How to reason it out
  1. Create a CodeArtifact domain and repository with an upstream connection to the public npm registry.
  2. Point build tooling at the CodeArtifact repository endpoint instead of the public registry.
  3. Let CodeArtifact cache every upstream package the builds pull, insulating them from upstream removals.
  4. Publish internal packages to the same repository so teams consume approved, private versions.

Exam tip: When a question describes a private npm/PyPI/Maven registry or controlling which package versions builds use, the answer is CodeArtifact — not S3 or ECR.

Preparing Application Artifacts for AWS Deployment — the lesson that teaches this.

Question 17Deployment

A Lambda function performing CPU-intensive image processing frequently times out. CloudWatch metrics show its memory usage stays far below the allocated 512 MB. What should the developer do to give the function more CPU?

Choose one.

  • a
    Set a dedicated vCPU count in the function's configuration

    Lambda has no separate CPU setting; CPU allocation is derived entirely from the configured memory.

  • b
    Increase the function's memory allocation, because CPU scales proportionally with memory Correct

    Lambda has a single sizing dial — memory — and CPU scales with it, reaching the equivalent of one vCPU at 1,769 MB; raising memory is how you buy CPU even when memory usage is low.

  • c
    Attach additional Lambda layers to spread the processing load

    Layers distribute shared dependencies across functions; they provide no additional compute capacity.

  • d
    Define container-level cpu units in the function's task definition

    Task definitions with container-level cpu settings belong to Amazon ECS; Lambda functions have no task definition.

The concept

Lambda's only sizing knob is memory (128 MB to 10,240 MB), and CPU scales proportionally with it — at 1,769 MB a function receives the equivalent of one vCPU.

Why that’s the answer

A CPU-bound function that times out is fixed by raising memory, even when measured memory usage is low, because that is the only way to allocate more CPU. There is no independent vCPU setting to configure. Layers carry shared dependencies and add zero compute. Container-level cpu settings live in ECS task definitions, a different service's resource model entirely.

How to reason it out
  1. Confirm from metrics and timeouts that the function is CPU-bound rather than memory-bound.
  2. Increase the memory allocation, which proportionally increases the CPU the function receives.
  3. Measure duration at several memory settings to find the point where added CPU stops shortening runs.
  4. Settle on the memory setting that balances duration against GB-second cost.

Exam tip: Lambda CPU comes only from the memory dial — fix a CPU-bound function by raising memory, even if memory usage looks low.

Preparing Application Artifacts for AWS Deployment — the lesson that teaches this.

Question 18Deployment

A CPU-bound Lambda function configured at 1,024 MB runs for about 8 seconds per invocation. Tests show that doubling the memory sharply reduces the duration. A manager objects that doubling memory will double the bill. What should the developer explain about Lambda pricing?

Choose one.

  • a
    Lambda charges a flat rate per invocation regardless of memory or duration

    Per-request charges exist, but compute cost is billed on GB-seconds — memory and duration both matter.

  • b
    Changing the memory setting requires rebuilding and republishing the deployment artifact

    Memory is function configuration, not part of the artifact — it changes without any rebuild.

  • c
    CPU is metered and billed separately from memory, so duration is unaffected by the memory setting

    Lambda has no separate CPU meter; CPU is allocated in proportion to memory, which is exactly why more memory shortens CPU-bound durations.

  • d
    Lambda bills on GB-seconds, so extra memory can lower total cost when the added CPU shortens duration enough — the team should measure duration at several memory settings Correct

    Cost is memory multiplied by duration; if doubling memory more than halves the duration of a CPU-bound function, the invocation costs less while also running faster.

The concept

Lambda compute is billed on GB-seconds — allocated memory multiplied by execution duration — and because CPU scales with memory, right-sizing is a measurement exercise, not a guess.

Why that’s the answer

For a CPU-bound function, more memory means more CPU and a shorter duration; whenever the duration reduction outpaces the memory increase, the GB-second cost falls even though the per-second rate rises. The flat-rate claim ignores the GB-second compute charge. Memory is configuration, so no artifact rebuild is involved. And there is no separate CPU billing dial — CPU rides on memory, which is the very mechanism that shortens the runs.

How to reason it out
  1. Record the current duration and GB-second cost at 1,024 MB.
  2. Test the function at several higher memory settings and record each duration.
  3. Compute GB-seconds (memory times duration) for each setting and compare costs.
  4. Choose the setting with the best cost-performance balance rather than assuming more memory always costs more.

Exam tip: Because Lambda bills GB-seconds and CPU scales with memory, raising memory on a CPU-bound function can cut both duration and cost — measure, don't assume.

Preparing Application Artifacts for AWS Deployment — the lesson that teaches this.

Question 19Deployment

An Amazon ECS task on Fargate runs an application container and a logging sidecar container. Under load, the sidecar occasionally consumes so much memory that the application container is starved. The task-level memory is already sized correctly. How should the developer constrain the sidecar?

Choose one.

  • a
    Increase the task-level memory setting further

    Raising the shared envelope gives the runaway sidecar more room to grow; without a per-container cap it can still starve the application container.

  • b
    Set a container-level memory hard limit on the sidecar within the task's overall envelope Correct

    Container-level memory is a hard limit — the sidecar is killed if it exceeds it — which caps the sidecar and protects the application container's share of the task envelope.

  • c
    Set only a memoryReservation value on the sidecar

    memoryReservation is a soft guarantee for scheduling, not a ceiling — the sidecar can still consume beyond it and starve its neighbor.

  • d
    Raise the sidecar container's cpu shares so it finishes its work faster

    cpu shares govern processor time, not memory consumption; more CPU does not stop the sidecar from over-allocating memory.

The concept

ECS separates task-level settings — the total cpu/memory envelope for all containers, required on Fargate — from container-level settings, where memory is a hard limit and memoryReservation is a soft guarantee.

Why that’s the answer

A multi-container task divides its envelope with container-level settings, and a hard memory limit on the sidecar is the mechanism that actually stops it from starving the application container — exceed the limit and the sidecar is killed rather than its neighbor. Enlarging the task envelope just feeds the runaway container. memoryReservation alone cannot cap consumption because it is only a soft guarantee. cpu shares are a processor-time control unrelated to memory pressure.

How to reason it out
  1. Keep the task-level memory as the total envelope for both containers.
  2. Add a container-level memory hard limit to the sidecar sized just above its normal peak.
  3. Optionally set memoryReservation on the application container as its scheduling guarantee.
  4. Load-test and confirm the sidecar is capped while the application container stays healthy.

Exam tip: In a multi-container ECS task, divide the task envelope with container-level limits — a hard memory limit is what stops one container from starving another.

Preparing Application Artifacts for AWS Deployment — the lesson that teaches this.

Question 20Deployment

A release process rebuilds an application from source separately for dev, staging, and production. Integration tests pass in staging, yet production incidents keep tracing back to code differences between the staging build and the production build. Which change makes the promotion process trustworthy?

Choose one.

  • a
    Run the full integration test suite against production after each deployment

    Testing in production detects problems after users are exposed; it does not remove the root cause, which is that production runs a different, never-tested build.

  • b
    Rebuild in every environment but schedule all three builds to run within the same hour

    Even near-simultaneous rebuilds can resolve differently and are still three distinct artifacts — closeness in time is not sameness of bytes.

  • c
    Bake each environment's configuration values into its build so behavior is fixed at compile time

    Baking config into the package forces per-environment rebuilds — the exact anti-pattern causing the drift — and couples configuration changes to redeployments.

  • d
    Build the artifact once, store it in an artifact store, and promote that same artifact through every environment with environment-specific configuration injected at deploy time Correct

    Promoting one build guarantees the bytes verified in staging are the bytes production runs; only the injected configuration differs per environment.

The concept

The build-once, promote-everywhere principle: verify one artifact in dev and staging, then promote that same artifact to production, with per-environment values injected via environment variables, Parameter Store, or AWS AppConfig.

Why that’s the answer

Rebuilding per environment means production runs a build that never went through staging — different dependency resolution, different bytes — so passing staging tests proves nothing about production. Building once and promoting the identical artifact removes that gap entirely. Testing in production is detection, not prevention. Synchronized rebuilds are still separate builds. Baking configuration into the artifact institutionalizes the per-environment rebuild that caused the problem.

How to reason it out
  1. Build the artifact once in CI and publish it to the artifact store (S3 for zips, ECR for images).
  2. Deploy that stored artifact to dev, then staging, referencing it by key, tag, or digest.
  3. Inject per-environment values at deploy time via parameters, environment variables, or Parameter Store paths.
  4. Promote the identical artifact to production once staging verification passes.

Exam tip: Build one artifact and promote it unchanged — rebuilding per environment ships untested bytes to production.

Preparing Application Artifacts for AWS Deployment — the lesson that teaches this.

Question 21Deployment

An application deployed to dev, staging, and production needs per-environment database endpoints and an encrypted third-party API key, all readable at startup and none baked into the deployment package. Which approach fits these requirements?

Choose one.

  • a
    Hardcode each environment's values in the source and build a separate package per environment

    This bakes configuration into the artifact and forces per-environment rebuilds, so production runs a build that staging never tested.

  • b
    Store the values in SSM Parameter Store under hierarchical per-environment paths such as /myapp/prod/, using a SecureString parameter for the API key, and read them at application startup Correct

    Parameter Store centralizes per-environment values in hierarchies, encrypts SecureStrings with AWS KMS, and lets the same artifact read its environment's values at startup.

  • c
    Commit a .env file per environment, including the API key, to the Git repository

    Secrets never belong in the repository — anyone with read access to Git gains the API key, and rotation requires a commit.

  • d
    Write all values, including the API key in plaintext, directly into the template committed to Git

    Values committed in the template land in version control and are visible to anyone who can read the repo; an encrypted SecureString keeps the key out of Git and under KMS.

The concept

Configuration lives outside the artifact: SSM Parameter Store organizes per-environment values in hierarchical paths (for example /myapp/dev/ versus /myapp/prod/) and encrypts sensitive values as SecureString parameters via AWS KMS.

Why that’s the answer

Hierarchical parameters give each environment its own value set, SecureString satisfies the encryption requirement for the API key, and reading at startup means one artifact serves every environment. Hardcoding per environment reintroduces per-environment builds. Committing .env files or plaintext template values puts a secret into Git, which is exactly where secrets must never live.

How to reason it out
  1. Create parameters under per-environment prefixes such as /myapp/dev/db-endpoint and /myapp/prod/db-endpoint.
  2. Store the API key as a SecureString parameter encrypted with AWS KMS.
  3. Grant the application's execution role permission to read its environment's parameter path.
  4. Have the application read the parameters at startup (or on a refresh interval), keyed by an environment name it receives at deploy time.

Exam tip: Per-environment values belong in Parameter Store hierarchies — with SecureString for secrets — never in the package or the repository.

Preparing Application Artifacts for AWS Deployment — the lesson that teaches this.

Domain 4: Troubleshooting and Optimization

18% of the DVA-C02 exam, so 4 of the 25 questions on this page.

Question 22Troubleshooting and Optimization

During traffic peaks, an application's logs show intermittent ProvisionedThroughputExceededException errors from a DynamoDB table, but the vast majority of requests still succeed. Which statement correctly describes how these errors should be handled?

Choose one.

  • a
    The AWS SDK already retries them with exponential backoff and jitter; the durable fix is capacity or partition-key design, not hand-written retry loops Correct

    Throttling exceptions are transient and retryable, and every AWS SDK retries them with backoff by default — the lasting remedy is more throughput, on-demand mode, or a better-distributed partition key.

  • b
    They indicate an IAM policy is denying the writes and the role's permissions must be fixed

    Permission problems raise AccessDenied-style errors; ProvisionedThroughputExceededException is purely a capacity signal.

  • c
    They must never be retried because the request's condition expression evaluated to false

    That describes ConditionalCheckFailedException; throttling errors are exactly the class of error that is safe and expected to retry.

  • d
    The application should immediately retry in a tight loop with no delay until the write succeeds

    Retrying without backoff amplifies the overload that caused the throttling and can make the incident worse.

The concept

ThrottlingException and its DynamoDB-specific cousin ProvisionedThroughputExceededException mean the caller is exceeding allowed throughput. They are transient and retryable, and AWS SDKs apply exponential backoff with jitter automatically.

Why that’s the answer

Because the SDK already handles the immediate retry correctly, the developer's job is the durable fix: raise provisioned throughput, switch the table to on-demand, or redesign a hot partition key. Option b confuses throttling with authorization, option c confuses it with a failed condition check (a deterministic error), and option d — tight retries without delay — pours more load onto an already-throttled resource.

How to reason it out
  1. Recognize the exception name as a capacity signal, not a defect or permission issue.
  2. Confirm the SDK's default retry behavior is intact rather than adding custom retry loops.
  3. Check table metrics for throttled requests and identify whether one hot partition key is responsible.
  4. Apply the durable fix: more provisioned capacity, on-demand mode, or a higher-cardinality key design.

Exam tip: Throttling errors are retryable and the SDK already backs off — your job is the capacity or key-design fix.

Root Cause Analysis on AWS: Reading Logs, Metrics, and Error Codes — the lesson that teaches this.

Question 23Troubleshooting and Optimization

An order service uses optimistic locking: every DynamoDB UpdateItem call includes a condition expression requiring version = :expectedVersion. Under concurrent traffic the logs show ConditionalCheckFailedException on some updates. What should the application code do when this exception occurs?

Choose one.

  • a
    Re-read the item to get its current state, reconcile the change, and decide whether to reapply the write with the fresh version Correct

    The exception means another writer updated the item first; only application logic that re-reads and reconciles can decide whether and how the write should still happen.

  • b
    Retry the identical request with exponential backoff until it succeeds

    The condition is deterministic — the stored version no longer matches — so the identical request will fail identically no matter how many times it is retried.

  • c
    Switch the table to on-demand capacity mode to absorb the concurrent writes

    This is not a capacity problem; the write was evaluated and rejected by the developer's own condition expression, which capacity changes do not affect.

  • d
    Grant the execution role additional dynamodb:UpdateItem permissions

    Permissions are not involved — a denied action would raise an AccessDenied-style error, not a failed condition check.

The concept

ConditionalCheckFailedException is DynamoDB reporting that a write's condition expression evaluated to false. It is not an outage and not a transient error — it is the developer's own guard doing its job, commonly during optimistic locking.

Why that’s the answer

With optimistic locking, the exception means a concurrent writer won the race and the item's version moved on. The correct response lives in application logic: re-read, reconcile against current state, and reapply only if still valid. Blind retries (b) fail identically because the condition is deterministic; capacity changes (c) are irrelevant because the service evaluated the write and rejected it by design; and permissions (d) would surface as AccessDenied, not a condition failure.

How to reason it out
  1. Catch ConditionalCheckFailedException specifically rather than treating it as a generic failure.
  2. Re-read the item to obtain its current version and attributes.
  3. Reconcile: decide whether the intended change still makes sense against the new state.
  4. If it does, reapply the update with the fresh expected version; if not, surface the conflict.

Exam tip: A failed condition check is a business signal, not an error to retry — re-read, reconcile, then decide.

Root Cause Analysis on AWS: Reading Logs, Metrics, and Error Codes — the lesson that teaches this.

Question 24Troubleshooting and Optimization

A newly deployed Lambda function fails on every invocation with an AccessDeniedException when writing objects to an S3 bucket, and retries fail identically. What should the developer do first?

Choose one.

  • a
    Configure additional SDK retries with longer backoff and jitter

    Retries help transient errors like throttling; a denied call stays denied until a policy changes, so more retries only delay the same failure.

  • b
    Read the error message and review the function's execution role policy and the bucket policy for the denied action Correct

    AccessDenied errors are deterministic policy refusals; the message names the principal and denied action, pointing straight at the policy in the chain that must change.

  • c
    Increase the function's memory allocation and timeout

    Resource settings affect performance and duration; they have no influence on whether IAM authorizes an action.

  • d
    Enable X-Ray active tracing to locate the slow downstream call

    Tracing locates latency and errors across hops, but the failing hop and cause are already known — a policy is denying the S3 write.

The concept

AccessDenied and AccessDeniedException mean some policy in the authorization chain — the caller's identity policy, a resource policy, a KMS key policy, or a permissions boundary — refuses the action. They are never capacity or performance problems.

Why that’s the answer

The failure being identical on every attempt is the tell for a deterministic authorization denial: the fix is in policy, and the error message itself names the principal and denied action to guide the search. Retries (a) address transient faults only, resource tuning (c) is orthogonal to authorization, and tracing (d) answers a "where" question that is already answered.

How to reason it out
  1. Read the full error message to identify the denied action and the principal.
  2. Check the execution role's identity policy for the required S3 permissions on the right resource ARN.
  3. Check the bucket policy — and the KMS key policy if the bucket uses SSE-KMS — for explicit or implicit denies.
  4. Fix the responsible policy and re-invoke to confirm.

Exam tip: AccessDenied is a policy problem: fix IAM or the resource policy — retrying a denied call changes nothing.

Root Cause Analysis on AWS: Reading Logs, Metrics, and Error Codes — the lesson that teaches this.

Question 25Troubleshooting and Optimization

A high-volume Lambda function must record a custom failure-count metric per payment provider. The team requires that publishing the metric adds no request latency and cannot be throttled by a metrics API quota. How should the metric be published?

Choose one.

  • a
    Call PutMetricData once per invocation from inside the handler

    PutMetricData is a synchronous API call that adds latency to every request and is subject to API quotas — exactly the two constraints the team ruled out.

  • b
    Write CloudWatch embedded metric format (EMF) log lines whose _aws block declares the metric, and let CloudWatch extract it asynchronously Correct

    EMF publishes metrics through the existing logging path — no synchronous API call in the hot path, no PutMetricData quota to hit, and the request context stays queryable alongside each datapoint.

  • c
    Write the counts to a DynamoDB table and graph them from there later

    Data in DynamoDB is not a CloudWatch metric — it cannot be graphed on CloudWatch dashboards or alarmed on without extra machinery, and it adds a database write to the hot path.

  • d
    Buffer datapoints in memory and have a scheduled Lambda function flush them with PutMetricData every minute

    Lambda execution environments are ephemeral and share nothing, so in-memory buffers are unreliable, and the flusher still depends on the throttle-prone synchronous API.

The concept

CloudWatch embedded metric format (EMF) is a JSON log convention: a log line's _aws metadata block declares the namespace, dimensions, and metric fields, and CloudWatch extracts real metrics from the log stream asynchronously.

Why that’s the answer

EMF satisfies both constraints by design — publication rides the existing logging path, so there is no synchronous call to add latency and no PutMetricData quota in play, and the per-provider dimension is just a field in the JSON. Option a violates both constraints directly. Option c produces data that is not a CloudWatch metric at all. Option d relies on state that ephemeral execution environments cannot reliably hold and still funnels through the synchronous API.

How to reason it out
  1. Structure a log line with an _aws block declaring the namespace, a PaymentProvider dimension, and the failure-count metric field.
  2. Print that line to standard output from the function — on Lambda that is all publication takes.
  3. Verify the metric appears in CloudWatch and graph or alarm on it per dimension value.
  4. Use Logs Insights on the same events when a metric spike needs the underlying request context.

Exam tip: "Custom metrics without latency or throttling" is the trigger phrase for embedded metric format.

Root Cause Analysis on AWS: Reading Logs, Metrics, and Error Codes — the lesson that teaches this.

Keep going with DVA-C02

DVA-C02 practice by domain

DVA-C02 sample questions: your questions

No. Real exam questions are confidential. These are original questions written to the skills in the official DVA-C02 exam guide, so they test the same knowledge in the same style without being copies of the exam.

Source

The domains and weights on this page come from the official DVA-C02 exam guide.