A senior DevOps candidate at a Series B fintech got asked one AWS question in April 2026 that had nothing to do with buckets, ACLs, or bucket policies. The interviewer wanted to know what changes in your application design once S3 stops being eventually consistent. The candidate gave the textbook answer about read-after-write lag and got politely cut off. AWS made S3 strongly consistent for every GET, PUT, and LIST operation back in December 2020, automatically, at no extra cost (AWS News Blog, 2020). Plenty of engineers who learned AWS before that update are still answering AWS interview questions with a fact that stopped being true five years ago.
Here's an opinion that might be wrong: I think most AWS interview prep spends too much time memorizing service names and just enough time on IAM to pass a multiple-choice cert, then almost none on the follow-up questions that actually separate someone who's run production infrastructure from someone who's only read the docs. Nobody fails an AWS interview by not knowing what EC2 stands for. People fail it when an interviewer asks why a security group let a request through that a network ACL should have blocked first, or the reverse, and the answer falls apart under one follow-up question.
This page covers AWS interview questions across the services that actually show up in cloud engineer, DevOps, SRE, and backend loops in 2026: compute, storage, IAM, networking, Lambda, two databases that keep getting confused for each other, load balancing, infrastructure as code, monitoring, messaging, and the Well-Architected Framework, plus a handful of scenario questions from system-design-adjacent rounds. We already published a shorter, narrative-driven breakdown of AWS interview failure modes at aws-cloud-interview-questions if you want the trade-off-heavy version with fewer, deeper questions. This page is the fuller reference: more services, more edge cases, meant to be worked through section by section rather than read start to finish in one sitting.
EC2 and compute: purchasing options are where the real questions live
Instance type trivia is mostly memorization, and interviewers know it. The section that actually tests judgment is purchasing options, and what you do when AWS takes an instance away from you mid-job.
Easy questions
15EC2 gives you resizable virtual machines, called instances, that you control down to the OS level. On-Demand billing is per second (with a one-minute minimum), based on instance type, region, and whether you're running plain Linux or a licensed OS like Windows or RHEL.
Interviewers use this to check whether you understand where EC2 sits relative to the serverless options later on this page. EC2 is the tier where you patch the OS yourself; Lambda and Fargate abstract that away, at the cost of some control.
S3 stores objects (data, metadata, and a key) inside buckets, accessed over HTTP, with no filesystem hierarchy of its own; the folder structure you see in the console is a UI illusion built from key prefixes. EBS is a block device attached to a single EC2 instance at a time and formatted with an actual filesystem.
S3 is engineered for 99.999999999 percent durability across multiple facilities. EBS durability is tied to the lifecycle of the volume and the AZ it lives in, which is why nobody treats it as a backup on its own.
A user is a long-term identity with its own credentials, a password and possibly access keys, tied to a specific person or application. A role has no credentials of its own. It's assumed temporarily, and AWS hands out short-lived STS credentials that expire, an hour by default, configurable up to 12.
Interviewers ask this to see whether you default to long-lived keys out of habit or reach for a role when one is available. It usually is.
Deny wins, every time. AWS evaluates every policy attached to a request, identity policies, resource policies, permissions boundaries, and SCPs if the account sits inside an Organization, and the default without any of them is implicit deny. An explicit Allow flips that to allowed, but a single explicit Deny anywhere in that stack overrides every Allow that would otherwise apply, regardless of how many separate policies grant it.
This is why "just add another Allow statement" doesn't fix an access problem actually caused by a Deny sitting two layers up in a permissions boundary or an SCP. I've watched someone spend an hour rewriting an identity policy that was never the problem, because the real Deny was living in an SCP at the organizational unit level nobody thought to check first.
A VPC is your own logically isolated slice of AWS network space, defined by a CIDR block you choose. A subnet is public if its route table sends 0.0.0.0/0 traffic to an Internet Gateway; it's private if that traffic instead routes to a NAT Gateway, or nowhere at all.
A subnet has no inherent "public" flag anywhere in its configuration. It's entirely a function of its route table, a fact that trips up candidates who think of it as a checkbox setting somewhere in the console.
Lambda runs your code in response to an event, with no server to provision or patch. Billing is per millisecond of execution time, multiplied by the memory allocated to the function, plus a per-request charge; AWS moved billing granularity from 100ms down to 1ms a few years back, which quietly helped short, fast functions.
A layer is a zip archive of code or dependencies mounted into a function's execution environment alongside the handler code, up to 5 layers per function. It solves duplication: instead of packaging the same dependency (a shared SDK wrapper, a common set of utilities, something heavier like Pandas) into every function that needs it, you publish it once as a layer and every function just references it.
The catch worth naming out loud: a layer still counts against the function's total unzipped deployment size limit of 250 MB, so stacking a few large layers onto a function that already has its own sizable dependencies is a common way to hit that ceiling without realizing it until a deploy fails.
Multi-AZ keeps a synchronous standby copy in a different Availability Zone purely for failover. In the classic single-standby deployment model, you can't query that standby directly, it exists only to take over if the primary fails. A Read Replica is asynchronous, built for read scaling, and can be promoted to a fully independent, writable database if you need to.
RDS Multi-AZ DB clusters, the newer deployment option, changed part of this by adding two readable standbys instead of one unreadable one. Plenty of production databases still run the older single-standby model though, so don't assume the readable version is universal just because it exists.
ALB operates at Layer 7: HTTP and HTTPS, path-based and host-based routing, WebSocket support, the default choice for a modern web application. NLB operates at Layer 4: raw TCP and UDP, ultra-low latency, a static IP or Elastic IP per AZ, and the ability to handle millions of requests per second, the choice when you need extreme throughput or a fixed IP that a firewall rule downstream depends on. Classic Load Balancer is legacy at this point; there's essentially no reason to reach for it on a new workload in 2026.
CloudFront is AWS's CDN, a global network of edge locations that caches content physically closer to whoever's requesting it, so a user in Singapore isn't pulling every asset from a bucket that only exists in us-east-1. S3 alone, even with static website hosting turned on, serves every request from that one region, over plain HTTP unless you bolt on your own TLS setup in front of it.
CloudFront sits in front of S3, or an ALB, or effectively any other origin, and adds TLS by default, caching that cuts real load off the origin, and access controls S3 alone doesn't have on its own, geo-restriction, signed URLs, a Web Application Firewall attached at the edge. The origin still has to exist somewhere. CloudFront is the delivery layer in front of it, not a replacement for it.
CloudFormation takes a declarative template describing your desired end state, and it reconciles the actual resources in your account to match that state, tracking what it created so it can update or tear it down cleanly later. Manually clicking through the console, or scripting a pile of imperative CLI calls, gives you resources with no record of how they relate to each other or how to reverse the changes.
Metrics are numeric time-series data grouped by namespace and dimensions. Logs stores raw log data from your applications and services. Alarms watch a metric against a threshold and trigger an action, an SNS notification, an Auto Scaling policy, or a Lambda function, when that threshold is breached.
Standard queues are at-least-once delivery with best-effort ordering and nearly unlimited throughput. FIFO queues preserve strict order within a message group and deduplicate messages within a 5-minute window, at meaningfully lower default throughput, though FIFO high-throughput mode raised that ceiling considerably.
Short polling returns immediately even if the queue is empty, so a consumer polling an empty queue burns API calls, and money, checking on nothing. Long polling waits up to 20 seconds for a message to show up before returning, so an empty queue costs one call instead of dozens fired off in quick succession.
Long polling also cuts down on false empty responses. SQS is distributed across multiple servers, and under short polling it's entirely possible to poll, get told the queue is empty, and have a message actually sitting on a server that specific request never sampled. Set WaitTimeSeconds above 0 and that mostly disappears. There's rarely a reason left to sit on the short-polling default.
Operational Excellence, Security, Reliability, Performance Efficiency, Cost Optimization, and Sustainability, added as the sixth pillar in late 2021 (AWS Well-Architected Framework documentation). Interviewers rarely quiz the list itself; they want to see you apply one or two of them to a concrete design decision instead of reciting all six on autopilot.
Medium questions
24On-Demand for unpredictable or short-lived workloads where flexibility matters more than the discount. Reserved Instances (1 or 3 year terms) or Savings Plans (a dollar-per-hour commitment that's more flexible across instance families) for baseline load you can forecast, with discounts that can approach 72 percent over On-Demand on a 3-year all-upfront term. Spot for interruption-tolerant batch work, at discounts that can hit 90 percent, in exchange for AWS being able to reclaim the instance with two minutes' notice.
The trap candidates fall into is treating this as a memorization question. The real test is whether you'd put a stateful primary database on Spot (you wouldn't) versus a batch video-encoding fleet (you'd do it without hesitation).
An AMI is a launch template: OS, application layer, launch permissions, and a block device mapping. A snapshot is a point-in-time backup of one EBS volume's data, nothing more.
An EBS-backed AMI is actually built on top of one or more snapshots plus metadata describing how to assemble them into a bootable instance. You can't launch an instance directly from a snapshot; you have to register it as an AMI first. That distinction trips up candidates who've used snapshots for backups but never had to rebuild an AMI from one.
gp3 decouples performance from volume size. Every gp3 volume ships with a baseline of 3,000 IOPS and 125 MiB/s included in the price, no matter how many gigabytes you provisioned, and you can pay extra to push that up to 16,000 IOPS and 1,000 MiB/s on the same volume without resizing it. gp2 ties performance to size instead: 3 IOPS per GB, so a 100 GB gp2 volume only gets 300 IOPS baseline, with a burst bucket that can spike to 3,000 IOPS for a while before it drains and throttles back down.
The answer worth having ready in an interview: a small gp2 volume, anything under roughly 1 TB, is almost always underprovisioned on IOPS relative to what gp3 gives for less money, since gp3 also runs around 20 percent cheaper per GB for the same baseline performance. I don't have a clean number for how much of the installed base has actually migrated off gp2 by now. Plenty of accounts still default to it out of habit when creating a new volume, since gp2 remains the setting nobody changed rather than the one somebody chose.
aws ec2 modify-volume \
--volume-id vol-0abc123456789 \
--volume-type gp3 \
--iops 4000 \
--throughput 250Standard for frequently accessed data. Standard-IA and One Zone-IA for infrequent access, cheaper storage in exchange for a per-GB retrieval fee. Glacier Instant Retrieval, Flexible Retrieval, and Deep Archive for archival data, trading retrieval latency (milliseconds to hours) for lower and lower storage cost. Intelligent-Tiering moves objects between tiers automatically based on 30 and 90-day access patterns, for a small per-object monitoring fee.
The honest interview answer is that Intelligent-Tiering is the safe default when you genuinely don't know the access pattern yet. Picking a class manually only pays off once you've actually measured usage, not before.
A lifecycle rule is time-based housekeeping inside a single bucket: transition an object to a cheaper storage class after a set number of days, or expire and delete it entirely, based on age or a tag filter you define. Cross-Region Replication (CRR) does something else, it copies new objects to a bucket in a different region, asynchronously, as they're written, usually for compliance, latency, or disaster recovery reasons rather than cost.
The two stack instead of competing. A common pattern is replicating everything to a second region for disaster recovery, then running a separate lifecycle rule on that destination bucket transitioning replicated objects to Glacier after 90 days, since a DR copy rarely needs Standard-class retrieval speed once it's a few months old and nobody's touched it.
With versioning enabled, a DELETE doesn't remove the object. It adds a delete marker as the new current version, and every prior version stays in the bucket, still costing money, until you explicitly delete that specific version ID.
To permanently remove an object you have to delete every version including the marker itself. This is also how an accidentally-versioned bucket with no lifecycle policy quietly balloons a storage bill over a few months without anyone noticing.
An instance profile hands the instance temporary, automatically rotated credentials through the instance metadata service, so there's no static secret sitting on disk or in a config file for someone to leak, screenshot, or accidentally commit to a public repo.
I've seen more security incidents traced back to a leaked access key in a GitHub repo than from any actual AWS platform vulnerability. That's not really an AWS problem, it's a "humans commit secrets" problem, but instance roles remove the temptation entirely.
An IAM policy is a JSON document made of statements, each with an Effect, an Action, a Resource, and optionally a Condition. Least privilege means scoping Resource down to specific ARNs instead of a wildcard, and adding conditions like source IP range or a requirement for MFA, rather than granting broad access and hoping nobody notices.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::invoice-uploads-prod/*",
"Condition": {
"Bool": { "aws:MultiFactorAuthPresent": "true" }
}
}
]
}A policy that grants s3:* on Resource: "*" technically "works" the same way a master key works on every door in a building. Interviewers want to hear you name the specific ARN and action, not just recite the term "least privilege."
Security groups attach to individual instances (or ENIs) and are stateful: allow inbound traffic on a port, and the matching response traffic is automatically allowed back out, no separate rule needed. They only support Allow rules, nothing is ever explicitly denied, it's just absent from the list. NACLs attach at the subnet level and are stateless: an allowed inbound rule doesn't automatically permit the outbound response, you write both directions yourself. NACLs also support explicit Deny rules and evaluate rules in numbered order, first match wins.
aws ec2 authorize-security-group-ingress
--group-id sg-0abc123456789
--protocol tcp
--port 443
--cidr 10.0.0.0/16The scenario interviewers love: a request gets through the security group fine but never arrives, or the reverse, arrives but the response never comes back. Nine times out of ten that's a missing outbound NACL rule for the ephemeral port range, something a stateful security group would never have required you to think about.
Both let a private-subnet resource reach an AWS service without routing through the public internet or a NAT Gateway. A Gateway endpoint is free and only covers S3 and DynamoDB, working by adding a route to the subnet's route table that points traffic for that service directly at the endpoint. An Interface endpoint is billed per hour plus per GB processed, backed by an ENI with a private IP dropped into your subnet, and it covers most other AWS services, Secrets Manager and SNS among them.
The reason to reach for either over a NAT Gateway: traffic to S3 or DynamoDB through a Gateway endpoint never touches a NAT Gateway's per-GB processing charge or bandwidth ceiling, and for anything security-sensitive, that traffic never leaves the AWS network backbone at all. I'd default every private-subnet workload talking to S3 or DynamoDB onto a Gateway endpoint before letting that traffic go out through NAT for no reason other than nobody set the endpoint up.
A VPC peering connection is a direct, one-to-one link between two VPCs, and it's non-transitive: if VPC A peers with B and B peers with C, A still can't reach C through B without its own separate peering connection. That's fine at 3 or 4 VPCs. It stops being fine once a company has 20 VPCs spread across a few dozen accounts, since peering connections scale roughly with the square of the VPC count, not linearly with it.
A Transit Gateway is a regional hub that every VPC, VPN, and Direct Connect circuit attaches to once, with routing between any two attachments flowing through route tables you define, including exactly which attachments can reach which others. It costs more per hour and per GB than peering does. The operational math flips anyway once you're the one maintaining dozens of point-to-point connections by hand instead of one hub.
A cold start happens when Lambda has to spin up a brand-new execution environment: download your code, start the runtime, run any code outside your handler. Warm invocations reuse an existing environment and skip all of that.
VPC-attached functions used to pay a much heavier cold start tax because Lambda had to create a fresh ENI per execution environment, which could take seconds. AWS re-architected this in 2019 with shared Hyperplane ENIs across invocations, and the VPC-specific penalty dropped dramatically. Plenty of engineers still repeat "never put Lambda in a VPC, cold starts" as received wisdom from before that fix shipped.
Reserved concurrency sets a hard ceiling on how many concurrent executions one function can use, and it also guarantees that ceiling is available to that function, carved out of the account-wide concurrency pool so other functions can't starve it.
Provisioned concurrency pre-initializes a set number of execution environments ahead of time, so invocations against that pool skip the cold start entirely. You pay for that capacity even when it's sitting idle, which is the real trade-off: predictable low latency in exchange for a bill that doesn't scale to zero anymore.
Aurora is AWS's own MySQL and Postgres-compatible engine, not the open-source engine running unmodified on RDS infrastructure. The storage layer is the actual difference: Aurora storage auto-scales in 10 GB increments up to 128 TB, replicates data six ways across three Availability Zones automatically, and only needs 4 of those 6 copies to acknowledge a write before it's considered durable.
Standard RDS, even in Multi-AZ, is still the stock engine sitting on regular EBS volumes with a single standby. Aurora Replicas, up to 15 of them, share that same underlying storage volume, so promoting one to primary during a failover doesn't need to re-copy data the way a standard RDS Read Replica promotion does, which is a large part of why Aurora failover tends to run faster. The trade-off is cost. Aurora usually runs more expensive per hour than the equivalent RDS instance, and it's a fair question in an interview to ask whether a given workload's durability and read-scaling needs actually justify that premium before defaulting to it.
DynamoDB fits when you know your access patterns upfront, need single-digit-millisecond latency at any scale, and are willing to model your data around your queries rather than run ad hoc joins later. RDS fits when you need relational integrity, complex or evolving queries, or you're already building on a SQL-heavy application layer.
The honest answer is that most teams pick based on what they already know, not based on the access pattern, and that's usually the wrong reason to choose either one.
Provisioned capacity means setting a fixed number of read and write capacity units ahead of time, cheaper per unit if traffic is predictable, but throttling hits if a spike blows past what's provisioned since auto scaling reacts rather than predicts. On-demand bills per request with no capacity planning at all, more expensive per request, and it's the safer default for a new table whose traffic pattern nobody has actually measured yet.
A DynamoDB Stream is a separate, ordered log of every item-level change to a table, insert, update, delete, that other services can read. The most common pattern is a Lambda function subscribed to the stream firing on every write, used for keeping a search index in sync, fanning a change out to another table, or feeding an audit log. Streams only keep 24 hours of change data available, so anything needing to reprocess older history has to have already captured it somewhere else.
Eventually consistent reads are the default, cost half the read capacity of a strong read, and might not reflect a write from the last few hundred milliseconds. Strongly consistent reads always return the latest committed write, cost full read capacity, and aren't available across a Global Table's replicated regions.
Here's the nuance that catches people who've only read the summary docs: Global Secondary Indexes only support eventually consistent reads, full stop, even if you request strong consistency on the base table. If your access pattern genuinely requires a strong read against index data, you're querying the base table, not the GSI.
Target tracking is closer to a thermostat: you set a target value, say 50 percent average CPU, and AWS manages the step adjustments to hold that target. Step scaling hands you direct control, you define specific thresholds and exactly how many instances to add or remove at each one.
Target tracking covers most real workloads with far less configuration. Step scaling earns its complexity when your traffic has genuinely unusual shape, like a scaling curve that needs to react much harder past a certain threshold than below it.
Drift detection compares each resource's live configuration against what the template last declared, and flags anything that's changed out-of-band, someone manually edited a security group rule in the console, say, without going through the template.
No, it doesn't auto-remediate anything. It reports which resources drifted and which properties differ, and you decide whether to update the template to match the manual change or revert the resource back to match the template. Skipping drift checks on a stack nobody's touched in months is how teams end up surprised by their own infrastructure.
Standard metrics report at 1-minute granularity by default (5-minute for basic monitoring on some resources). Custom high-resolution metrics can be published as often as once per second, at extra cost per metric.
You need the high-resolution option when a 1-minute average would smooth away exactly the thing you're trying to catch, a latency spike that lasts 8 seconds during a deploy, for instance, which a 1-minute average will average right out of visibility.
INSUFFICIENT_DATA isn't just "no recent data point." It shows up when there literally isn't enough history yet to evaluate the alarm's condition, right after the alarm is created, or when the underlying metric stops reporting entirely, like an instance that got terminated and never sent another data point.
Treating INSUFFICIENT_DATA as functionally equivalent to OK is a common on-call mistake. A metric that's gone silent because the thing it monitors is actually broken looks identical, on a quick glance, to a metric that's just quiet because nothing's wrong.
An SNS topic publish delivers a copy of the message to every subscribed SQS queue independently, so each downstream consumer processes it at its own pace without the publisher needing to know or care who's listening.
A single queue gives you one logical consumer group, competing for the same messages. Fan-out gives you N independent consumer groups off the same event, an order-confirmation queue, an analytics queue, and a fraud-check queue all getting their own copy of the same "order placed" event without touching each other's processing.
A dead-letter queue (DLQ) is a regular SQS queue designated as the destination for messages that failed processing too many times. The redrive policy, set on the source queue, defines maxReceiveCount, how many times a message can be received and go unprocessed before SQS moves it to the DLQ instead of leaving it to loop forever.
aws sqs set-queue-attributes \
--queue-url https://sqs.us-east-1.amazonaws.com/123456789012/orders \
--attributes '{"RedrivePolicy":"{\"deadLetterTargetArn\":\"arn:aws:sqs:us-east-1:123456789012:orders-dlq\",\"maxReceiveCount\":\"5\"}"}'Without a DLQ, a message the consumer can't process, a malformed payload, a downstream dependency that's permanently down, just keeps getting redelivered after every visibility timeout, forever, quietly burning through invocations or worker time on something that was never going to succeed. A DLQ isn't automatic cleanup either. Someone still has to look at what landed there and decide whether to fix and replay it or throw it away.
My honest opinion, and it might be unpopular: most companies asking about multi-region active-active in an interview don't actually operate that way in production. Multi-AZ within a single region already covers the failure modes that happen most often, an AZ losing power, a rack failing, a single data center having a bad day.
Multi-region protects against an entire AWS region going down, which has happened, but it roughly doubles operational complexity and often the bill too. I'd rather hear a candidate say "multi-AZ covers most realistic failures, and multi-region is expensive insurance for the rest" than hear a textbook description of an active-active setup they've never actually run.
Hard questions
16You get a two-minute interruption notice, available through the instance metadata service or as an EventBridge event you can subscribe to. Design for it by checkpointing progress somewhere durable (S3, a database) rather than instance-local disk, so the replacement instance resumes from the last checkpoint instead of restarting from zero.
Diversify across instance types and AZs with a mixed-instance Auto Scaling group or Spot Fleet, since Spot capacity fragments differently by pool and by hour. I don't have a clean number for how often a given pool actually gets reclaimed. It varies by instance family, region, and week, and anyone who quotes you one fixed percentage is guessing.
Since December 2020, S3 delivers strong read-after-write consistency for all GET, PUT, and LIST operations automatically, at no extra cost, with no performance penalty, in every region (AWS News Blog, 2020). Before that update, a GET immediately following a PUT to a brand-new key could occasionally return stale data or a 404.
The trap in the interview isn't naming the old behavior. It's stating the old behavior with confidence as if it still applies today. "You need to build your own consistency layer on top of S3" was correct advice in 2015. It hasn't been correct for over five years, and citing outdated information that used to be right is exactly the kind of thing a sharp interviewer will catch.
All three can grant or restrict access to the same object, and AWS evaluates every one of them together rather than picking a single source of truth. A bucket policy is attached to the bucket and can grant access to other accounts or the public. An IAM policy is attached to a user or role and travels with that identity across every bucket it touches. An ACL is the oldest mechanism of the three, attached to the individual object or bucket, and AWS has been steering people away from it for a while. In April 2023, AWS started disabling ACLs by default on every new bucket and automatically enabling Block Public Access alongside it, on top of recommending IAM policies as the modern replacement since 2021.
The evaluation logic candidates get wrong is assuming one of the three wins outright. There is no single winner. AWS combines every applicable policy, and an explicit Deny anywhere in that combined set overrides any Allow, no matter which of the three granted it. If the bucket policy allows public read but the calling role's IAM policy never grants s3:GetObject, the request still fails. Most teams I've seen use IAM policies for anything inside their own account and reserve bucket policies for the cross-account or public cases ACLs used to handle, badly.
The trust policy is attached to the role itself and defines who's allowed to assume it, an account, a specific role ARN, or an AWS service, through the Principal field. The permissions policy, also attached to the role, defines what the role can actually do once assumed. Those are two different documents doing two different jobs, and candidates conflate them constantly.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:root" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": { "sts:ExternalId": "vendor-4471" }
}
}
]
}A caller in Account A runs sts:AssumeRole against a role in Account B. If B's trust policy lists A (or a specific principal in A) and the caller has permission on their own side to call AssumeRole, the call succeeds and returns temporary credentials scoped to whatever B's permissions policy allows. The ExternalId condition above matters specifically for third-party access, where you're not the one who controls the caller's account. It exists to prevent the confused-deputy problem, where a third party accidentally uses one customer's role to reach a different customer's resources.
A permissions boundary is a managed policy attached to a user or role that caps the maximum permissions that identity can ever have, regardless of what its identity-based policies grant on top of it. A boundary doesn't grant anything by itself. The identity's effective permissions end up being the intersection of its identity policy and its boundary, whichever one says no wins.
The real use case is delegated administration. A team lead gets to create IAM roles for their own team through a self-service pipeline, but every role that pipeline creates gets the same permissions boundary attached automatically, so even a fat-fingered wildcard Action in an identity policy still can't exceed what the boundary allows. Without that boundary in place, a self-service IAM pipeline is one typo away from someone handing themselves admin.
Put a NAT Gateway in a public subnet, give it an Elastic IP, then point the private subnet's route table at that NAT Gateway for 0.0.0.0/0 traffic. Inbound connections initiated from the internet still can't reach the instance; only outbound-initiated traffic and its return path work.
Run one NAT Gateway per AZ if you actually care about availability, since a NAT Gateway is an AZ-scoped resource and a single one becomes a single point of failure for every private subnet routing through it. A self-managed NAT instance is cheaper on paper, but you're now the one patching and scaling it, which is usually a bad trade for the money saved.
First check whether you're hitting account or function concurrency limits and getting throttled (a 429), which looks like intermittent failure under load but isn't actually a timeout at all. If concurrency isn't the issue, look at what the function talks to downstream.
The classic cause: each concurrent Lambda invocation opens its own database connection, so a burst of 500 concurrent invocations can try to open 500 connections against an RDS instance whose max_connections ceiling is nowhere close to that. The fix is usually RDS Proxy to pool and reuse connections across invocations, or capping the function's reserved concurrency so it can't overwhelm the database in the first place, or moving the work behind a queue so Lambda pulls at a rate the database can actually absorb.
DynamoDB spreads your table's throughput across partitions based on the partition key. If one key value (or a small set of them) gets a disproportionate share of reads or writes, like a single "trending" item ID getting hammered, that one partition throttles even though the table's overall provisioned or on-demand capacity looks fine on a dashboard.
The real fix is key design: add a random or calculated suffix to spread a hot logical key across several physical partitions, or pick a more selective partition key from the start. AWS added adaptive capacity to absorb some imbalance automatically, but it's a cushion, not a substitute for a partition key that was poorly chosen in the first place.
RDS detects the primary is unhealthy, promotes the standby, and flips the DNS CNAME endpoint your application connects to so it now resolves to the new primary's IP. That typically takes somewhere around 60 to 120 seconds depending on the engine and what triggered the failover.
Every connection your application had open to the old primary gets dropped mid-flight. Applications that don't handle reconnect and retry logic gracefully will throw errors during that window no matter how fast the failover itself completes, which is why "does your app retry on connection loss" is often the real follow-up question, not the failover mechanics themselves.
That's classic flapping: a scaling metric that swings quickly around the threshold, paired with a cooldown period too short to let the new instances actually absorb load before the group decides to shrink again.
The fix is usually some combination of a longer cooldown or warm-up period, scaling on a smoothed metric averaged over several minutes rather than an instantaneous reading, and widening the target tracking band so the policy isn't hunting around a single number. I'd add a slightly unpopular take here: teams chase a "perfect" scaling policy for weeks when just widening the target band from, say, 50 percent to a 45-to-60 range would've solved it in an afternoon.
Signed URLs and signed cookies solve the same problem from two directions, making sure only someone holding a valid, time-limited signature can fetch private content through CloudFront. Signed URLs work per object, appending a signature and expiration to each individual URL, useful for something like a single paid video file. Signed cookies apply to a whole path pattern at once, so a video streaming app can grant access to every segment of a series without generating a separate signed URL for each one.
Origin Access Control (OAC) is a different layer entirely. It locks down the origin itself, so the S3 bucket behind CloudFront only accepts requests that actually came through CloudFront, not someone hitting the bucket's direct S3 URL and skipping the CDN, and the signed URL check, entirely. AWS introduced OAC in 2022 as the replacement for the older Origin Access Identity (OAI), and OAI doesn't support SSE-KMS-encrypted buckets or several newer AWS regions, so any new distribution built now should reach for OAC, not the legacy OAI setup a lot of older tutorials still walk through.
Nested stacks split one large deployment into reusable child templates that all get deployed together, within a single account and region, useful for something like a shared VPC template referenced by several service-specific stacks. StackSets deploy the same stack across many accounts and regions at once, from a central administrator account, meant for org-wide guardrails like a mandatory logging bucket or a baseline IAM policy every account needs.
Resources:
NetworkStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/my-templates/network.yaml
Parameters:
VpcCidr: 10.0.0.0/16
AppStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/my-templates/app.yaml
Parameters:
VpcId: !GetAtt NetworkStack.Outputs.VpcIdInterviewers rarely expect deep StackSets knowledge unless you're targeting a platform or DevOps-heavy role, but naming the account-and-region-scale difference unprompted is usually enough to show you've actually operated at this level before.
Not quite, and this is the question that separates people who've actually run a queue in production from people who read the feature name. "Exactly-once processing" in FIFO means no duplicate is introduced into the queue itself within the 5-minute deduplication window. It does not guarantee your own consumer only processes a given message a single time end to end.
If your visibility timeout is shorter than your actual processing time, the message becomes visible again before the first consumer finishes and deletes it, and a second consumer can grab it, producing a real duplicate at the application level. The fix: set the visibility timeout comfortably above your p99 processing time, extend it dynamically with ChangeMessageVisibility for genuinely long jobs, and build consumers to be idempotent regardless of what the queue promises on paper.
On-Demand guarantees it finishes but costs the most. Spot is far cheaper but can be interrupted, which is dangerous against a hard deadline unless you've built in checkpointing and enough slack in the window to absorb an interruption or two. A Savings Plan makes sense only if this job (or similarly-shaped ones) runs every night indefinitely, since the commitment is time-based, not job-based.
My honest answer here: for a genuinely hard 6-hour deadline with real business consequences for missing it, I'd run the core of the job on-demand or reserved and only push the truly parallelizable, restartable chunks to Spot. Betting the whole deadline on Spot to save money is the kind of decision that looks smart until the one night it isn't.
Recovery Time Objective (RTO) is how long the business can tolerate being down. Recovery Point Objective (RPO) is how much data it can afford to lose, measured in time, the gap between the last good backup or replica and the moment of failure. The two are independent. A system can have a tight RPO, near-zero data loss, paired with a loose RTO that's fine being down for hours, or the reverse.
AWS's own Well-Architected reliability guidance lays out four DR strategies on a spectrum from cheap-and-slow to expensive-and-fast: backup and restore, the cheapest option with an RTO measured in hours to days, pilot light, a minimal always-on copy of core infrastructure scaled up during a failure, warm standby, a scaled-down but fully functional copy running continuously, and multi-site active-active, full capacity in two regions at once, the fastest RTO and the most expensive by a wide margin. Picking one is a business conversation before it's an engineering one. An interviewer asking this usually wants to hear you ask what the actual RTO and RPO targets are before proposing an architecture, not jump straight to naming multi-site active-active because it sounds the most impressive answer to give.
An Application Load Balancer spread across both AZs in front of the app tier. An Auto Scaling group of stateless app servers, also spread across both AZs, so losing one AZ doesn't take the whole app down. RDS Multi-AZ for the database tier, so a primary failure triggers an automatic failover instead of an outage. S3 plus CloudFront for static assets, offloading that traffic entirely from the app servers.
The follow-up worth naming before it's asked: anywhere the app does slow background work (sending emails, generating reports), decouple it behind SQS instead of doing it synchronously in the request path, so a slow downstream dependency doesn't take down the whole request.
How to prepare for AWS interview questions in 2026
Skip the flashcard approach to service names. Knowing that DynamoDB is "a NoSQL key-value database" doesn't help when an interviewer hands you a hot partition scenario and asks you to fix it live. Spin up a small multi-service project (an API behind Lambda and API Gateway writing to DynamoDB, or a three-tier app behind an ALB with an RDS backend) and then deliberately break something: throttle a table, kill an AZ, misconfigure a security group. Fixing your own break teaches the mental model faster than another practice test does.
Across the cloud-tagged mock interview sessions run through LastRoundAI this year, the question that stalls candidates most often isn't a service definition. It's the "why not the other one" follow-up, RDS versus DynamoDB, security group versus NACL, Reserved versus Spot, asked right after a confident first answer. We don't have a clean percentage to put on that pattern, only that it shows up in review often enough to flag here.
On adoption: AWS remains the cloud platform 45.9 percent of professional developers report using, ahead of Azure at 27.2 percent and Google Cloud at 24.3 percent (Stack Overflow Developer Survey, 2025). That gap is exactly why AWS interview questions keep showing up across roles that aren't formally "cloud engineer" titles at all, backend, DevOps, SRE, even some data engineering loops now assume baseline AWS fluency. We're still building out the matching Azure and GCP versions of this page; they're not live yet, so if your target role runs on one of those instead, treat the service-specific sections here as a mental model more than a literal answer key.
Get the reps in before the real interview
Reading the right answer to a hot-partition question is not the same as defending it out loud once an interviewer changes one variable on you. LastRoundAI's mock interview mode runs cloud and DevOps-focused rounds with real-time follow-up questions instead of a static bank, and the free plan includes 15 credits a month that reset monthly, Starter is $19/mo if you need more sessions than that covers.
If the slower part of the job hunt right now is finding enough cloud, DevOps, or backend roles rather than passing the interview once you land one, Auto-Apply matches and applies to roles for you, 10 a month on the free plan, up to 400 a month on the Ultimate plan, with every application held in a review queue until you approve it. Nothing goes out on your behalf without you seeing it first.
Questions about either product go to contact@lastroundai.com. That's the only inbox we check.

