AWS Interview Questions and How to Answer Them (45+ Questions)
You have an AWS interview coming up. This article gives you every question worth preparing, with the exact answer a senior engineer would give — including real code, not toy examples.
The questions are grouped by topic. Work through them in order or jump to the section where you're weakest. Each answer tells you *what* to say and *why* it matters to the interviewer.
Table of Contents
- 1Core Services and Fundamentals (Q1–Q10)
- 2IAM and Security (Q11–Q18)
- 3Compute: EC2, Lambda, ECS (Q19–Q27)
- 4Storage: S3, EBS, EFS (Q28–Q33)
- 5Networking: VPC, Route 53, CloudFront (Q34–Q39)
- 6Databases: RDS, DynamoDB, ElastiCache (Q40–Q44)
- 7Architecture and Best Practices (Q45–Q48)
Core Services and Fundamentals
Q1. What is the difference between a Region, an Availability Zone, and an Edge Location?
What they want to hear: You understand AWS's physical infrastructure and can explain why it matters for reliability and latency.
Answer:
A Region is a geographic area (e.g., us-east-1, eu-west-1) containing multiple isolated data centers. AWS has 30+ Regions. You choose a Region based on latency, data residency requirements, and service availability.
An Availability Zone (AZ) is one or more discrete data centers within a Region, each with redundant power, networking, and cooling. A Region has at least 3 AZs. AZs within a Region are connected by low-latency private fiber — but isolated from each other so a flood in one AZ doesn't affect another. When you deploy across 3 AZs, a single facility failure doesn't take your service down.
An Edge Location is a site used by CloudFront (CDN) and Route 53 to cache content and answer DNS queries close to end users. There are 400+ Edge Locations globally — far more than Regions. Edge Locations don't run general compute; they serve cached assets and accelerate traffic routing.
The practical implication: A multi-AZ RDS deployment survives an AZ failure automatically. A multi-Region deployment survives a full Regional outage — but costs more and requires data replication strategy. You almost never need multi-Region unless your SLA demands 99.99%+ uptime or you have data sovereignty requirements.
Q2. Explain the AWS Shared Responsibility Model.
What they want to hear: You can draw the security boundary and apply it to concrete scenarios.
Answer:
AWS is responsible for the security of the cloud. You are responsible for security in the cloud.
AWS owns:
- Physical hardware and data centers
- Hypervisor and virtualization layer
- Managed service security (e.g., RDS patches the database engine; you patch the data and configurations)
- Network infrastructure between AZs
You own:
- OS patches on EC2 instances
- IAM configuration (who can do what)
- Security group and NACL rules
- Data encryption at rest and in transit
- Application-level security
- Customer data
Where people get confused: For a managed service like Lambda, AWS patches the runtime. But you still own the code, the IAM execution role, and the environment variables. For RDS, AWS patches the DB engine; you own the database user permissions and what data you store.
A concrete example: If you leave an S3 bucket publicly readable and customer data leaks, that's your responsibility — AWS gave you the tools to lock it down. If a physical hard drive gets stolen from an AWS data center, that's AWS's problem.
Q3. What is the difference between horizontal scaling and vertical scaling? How does AWS support each?
Answer:
Vertical scaling (scale up): Increase the size of a single instance. EC2 t3.medium → m5.xlarge. Simple, but has a ceiling, requires downtime for EC2, and creates a single point of failure.
Horizontal scaling (scale out): Add more instances behind a load balancer. This is how you build fault-tolerant, elastic systems.
AWS supports both:
- Vertical: Stop the EC2 instance, change instance type, restart. For RDS, you modify the DB instance class (brief downtime, or zero downtime with Multi-AZ).
- Horizontal: EC2 Auto Scaling Groups (ASG) add/remove instances based on CloudWatch metrics. ECS and EKS scale tasks/pods. Lambda scales horizontally by default — each invocation gets its own execution environment.
The answer interviewers want: Horizontal scaling is almost always the right answer for production systems. It eliminates single points of failure, allows gradual scaling, and fits AWS's pricing model. Design stateless services so any instance can handle any request.
Q4. What is an Auto Scaling Group and how does it work?
Answer:
An Auto Scaling Group (ASG) manages a fleet of EC2 instances. You define:
- Launch template: Instance type, AMI, security groups, user data
- Min/Max/Desired capacity: The floor, ceiling, and target count
- Scaling policies: Rules that trigger scale-out or scale-in
Types of scaling policies:
- 1Target tracking: "Keep average CPU at 50%." ASG figures out how many instances that requires. Simplest and recommended for most cases.
- 2Step scaling: "When CPU > 70%, add 2 instances. When CPU > 90%, add 5." More control, more configuration.
- 3Scheduled scaling: "Every Monday at 8am, set desired capacity to 10." Predictable traffic patterns.
- 4Predictive scaling: Uses ML to forecast traffic and scale ahead of demand.
Real configuration (Terraform):
resource "aws_autoscaling_group" "app" {
name = "app-asg"
min_size = 2
max_size = 10
desired_capacity = 2
vpc_zone_identifier = var.private_subnet_ids
launch_template {
id = aws_launch_template.app.id
version = "$Latest"
}
target_group_arns = [aws_lb_target_group.app.arn]
health_check_type = "ELB"
health_check_grace_period = 300
tag {
key = "Name"
value = "app-instance"
propagate_at_launch = true
}
}
resource "aws_autoscaling_policy" "cpu_target" {
name = "cpu-target-tracking"
autoscaling_group_name = aws_autoscaling_group.app.name
policy_type = "TargetTrackingScaling"
target_tracking_configuration {
predefined_metric_specification {
predefined_metric_type = "ASGAverageCPUUtilization"
}
target_value = 50.0
}
}Key detail: health_check_type = "ELB" means the ASG uses your load balancer's health check, not just EC2 status. An instance that's running but returning 500s gets replaced. Always set this for web services.
Q5. What is CloudFormation and how does it differ from Terraform?
Answer:
CloudFormation is AWS's native Infrastructure as Code (IaC) tool. You write YAML or JSON templates describing AWS resources, and CloudFormation provisions and manages them as a stack.
CloudFormation strengths:
- Native AWS integration — supports new services faster
- Drift detection tells you when someone changed infrastructure outside IaC
- Change sets let you preview changes before applying
- No state file to manage (AWS manages state)
- Free (you pay for the resources, not CloudFormation itself)
Terraform strengths:
- Multi-cloud (Azure, GCP, etc.)
- Larger ecosystem and community modules
- HCL is more readable than CloudFormation JSON/YAML for complex infra
- Plan command is equivalent to change sets but more widely understood
- State locking with S3 + DynamoDB is explicit and portable
In interviews: Both are valid. If the job uses Terraform, know Terraform. If they're AWS-only and use CDK or CloudFormation, show fluency there. The important thing is demonstrating you understand IaC as a practice — version control, peer review, no console-clicking in production.
CloudFormation example — S3 bucket with versioning:
AWSTemplateFormatVersion: '2010-09-09'
Description: S3 bucket with versioning and encryption
Resources:
DataBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Retain
Properties:
BucketName: !Sub '${AWS::AccountId}-data-${AWS::Region}'
VersioningConfiguration:
Status: Enabled
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: aws:kms
KMSMasterKeyID: !Ref EncryptionKey
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
EncryptionKey:
Type: AWS::KMS::Key
Properties:
EnableKeyRotation: true
KeyPolicy:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
Action: 'kms:*'
Resource: '*'
Outputs:
BucketName:
Value: !Ref DataBucket
Export:
Name: !Sub '${AWS::StackName}-BucketName'Q6. How does AWS pricing work? What are the main ways to reduce costs?
Answer:
AWS pricing has three main models:
On-Demand: Pay per second/hour, no commitment. Highest unit price, maximum flexibility. Good for unpredictable workloads, dev/test environments.
Reserved Instances (RI) / Savings Plans: Commit to usage for 1 or 3 years. 30–72% discount. Savings Plans are more flexible than RIs — they apply across instance families and even Lambda and Fargate.
Spot Instances: Bid on unused AWS capacity. Up to 90% cheaper than On-Demand. AWS can reclaim Spot instances with a 2-minute warning. Good for batch jobs, ML training, stateless workers in an ASG.
Cost reduction strategies:
- 1Right-size instances — Use AWS Cost Explorer and Compute Optimizer to find over-provisioned instances
- 2Auto Scaling — Don't run peak-capacity instances 24/7; scale down at night
- 3S3 lifecycle policies — Move old data to S3 Glacier automatically
- 4Reserved capacity for steady-state workloads — If you run 5 instances 24/7, buying RIs for those 5 pays back in months
- 5Spot for batch and fault-tolerant work — ML training on Spot cuts GPU costs dramatically
- 6Delete unused resources — Unattached EBS volumes, old snapshots, idle load balancers add up
- 7Use CloudFront — Serving traffic from edge caches is cheaper than serving from EC2/S3 directly
- 8Enable S3 Intelligent-Tiering — Automatically moves objects between tiers based on access patterns
Q7. What is the difference between CloudWatch and CloudTrail?
Answer:
CloudWatch monitors the *operational health* of your resources. It collects metrics (CPU, memory, request counts), logs (application logs, Lambda logs), and lets you set alarms and dashboards.
CloudTrail is the *audit log* of AWS API calls. Every action taken in your AWS account — who did what, when, from which IP — is recorded by CloudTrail. It answers "who deleted that S3 bucket?" and "which IAM user changed this security group?"
Memory device: Watch = monitoring. Trail = who walked through here.
Practical setup — CloudWatch alarm for high error rate:
import boto3
cloudwatch = boto3.client('cloudwatch', region_name='us-east-1')
cloudwatch.put_metric_alarm(
AlarmName='HighErrorRate-ProductionAPI',
ComparisonOperator='GreaterThanThreshold',
EvaluationPeriods=2,
MetricName='5XXError',
Namespace='AWS/ApplicationELB',
Period=60,
Statistic='Sum',
Threshold=10.0,
AlarmDescription='More than 10 5XX errors per minute for 2 consecutive minutes',
Dimensions=[
{
'Name': 'LoadBalancer',
'Value': 'app/my-alb/1234567890abcdef'
}
],
AlarmActions=['arn:aws:sns:us-east-1:123456789012:ops-alerts'],
TreatMissingData='notBreaching'
)CloudTrail — query who deleted a resource (Athena):
SELECT
eventtime,
useridentity.arn,
useridentity.sessioncontext.sessionissuer.arn as assumed_role,
sourceipaddress,
requestparameters
FROM cloudtrail_logs
WHERE
eventsource = 's3.amazonaws.com'
AND eventname = 'DeleteBucket'
AND eventtime >= '2026-09-01'
ORDER BY eventtime DESC
LIMIT 20;Q8. What is AWS Organizations and why would you use it?
Answer:
AWS Organizations lets you manage multiple AWS accounts under a single root. You group accounts into Organizational Units (OUs) and apply Service Control Policies (SCPs) that set the maximum permissions for accounts in that OU.
Why use multiple accounts at all? Hard blast radius containment. If a developer's credentials leak in the dev account, they can't touch production. Cost tracking is cleaner. Security teams can audit one account without access to all.
Key concepts:
- Management account: The root account that controls the organization. Do minimal actual work here.
- Member accounts: Where workloads live. Typically: dev, staging, production, security, shared-services.
- SCPs: Policy guardrails. "No account in the production OU can disable CloudTrail." SCPs don't grant permissions — they restrict what IAM policies can grant.
SCP example — prevent disabling CloudTrail:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyCloudTrailDisable",
"Effect": "Deny",
"Action": [
"cloudtrail:DeleteTrail",
"cloudtrail:StopLogging",
"cloudtrail:UpdateTrail"
],
"Resource": "*"
}
]
}This SCP, attached to the production OU, prevents anyone — including the account root user — from touching CloudTrail. Even if an attacker compromises admin credentials, they cannot erase their tracks.
Q9. What is the Well-Architected Framework?
Answer:
Six pillars for building good systems on AWS:
- 1Operational Excellence — Run and monitor systems, improve processes. Automate runbooks, use IaC, post-mortem everything.
- 2Security — Protect data and systems. Least privilege IAM, encryption everywhere, GuardDuty for threat detection.
- 3Reliability — Recover from failures. Multi-AZ, circuit breakers, chaos engineering.
- 4Performance Efficiency — Use resources efficiently. Right-size instances, use managed services instead of rolling your own.
- 5Cost Optimization — Avoid unnecessary spend. Rightsizing, Spot instances, deleting waste.
- 6Sustainability — Minimize environmental impact (newer pillar). Efficient architectures reduce energy consumption.
In interviews: You don't need to recite all six — you need to show you apply them. When you describe an architecture decision, frame it with "this improves reliability because..." or "we optimized cost by...". That signals you think in frameworks, not just code.
Q10. What is the difference between SQS, SNS, and EventBridge?
Answer:
All three decouple services, but they do different things:
SQS (Simple Queue Service): A queue. Producers put messages in; consumers pull and process them. One consumer processes each message. Messages persist until processed or expired (up to 14 days). Good for work queues, task distribution, buffering traffic spikes.
SNS (Simple Notification Service): A pub/sub system. Publishers send to a topic; all subscribers receive the message. Push-based — SNS pushes to SQS queues, Lambda functions, HTTP endpoints, email. Good for fan-out: one event triggers multiple downstream actions.
EventBridge: An event bus with routing rules. Events can come from AWS services (EC2 state change, RDS failover), your own applications, or SaaS partners. You write rules to route specific events to specific targets. More powerful than SNS for complex routing.
Common pattern — SNS fan-out to SQS:
Order placed
└── SNS Topic
├── SQS Queue → Fulfillment Service
├── SQS Queue → Email Notification Lambda
└── SQS Queue → Analytics ProcessorEach service has its own queue, so a slow fulfillment service doesn't block email sending.
Python — sending to SQS:
import boto3
import json
sqs = boto3.client('sqs', region_name='us-east-1')
QUEUE_URL = 'https://sqs.us-east-1.amazonaws.com/123456789012/order-processing'
def enqueue_order(order: dict) -> str:
response = sqs.send_message(
QueueUrl=QUEUE_URL,
MessageBody=json.dumps(order),
MessageGroupId=str(order['customer_id']),
MessageDeduplicationId=order['order_id'],
MessageAttributes={
'OrderType': {
'DataType': 'String',
'StringValue': order['type']
}
}
)
return response['MessageId']
def process_messages():
response = sqs.receive_message(
QueueUrl=QUEUE_URL,
MaxNumberOfMessages=10,
WaitTimeSeconds=20,
MessageAttributeNames=['All']
)
for message in response.get('Messages', []):
order = json.loads(message['Body'])
try:
process_order(order)
sqs.delete_message(
QueueUrl=QUEUE_URL,
ReceiptHandle=message['ReceiptHandle']
)
except Exception as e:
print(f"Failed to process order {order['order_id']}: {e}")IAM and Security
Q11. Explain IAM: users, groups, roles, and policies.
Answer:
Users: Human identities with long-term credentials (access keys, passwords). For actual people. Best practice: don't create users if you can avoid it — prefer SSO with an identity provider.
Groups: Collections of users. Assign policies to groups, add users to groups. Never assign policies directly to users in production — it becomes unmanageable.
Roles: Identities assumed temporarily. No long-term credentials. EC2 instances assume roles to call AWS APIs. Lambda functions run with a role. Cross-account access uses roles. This is the correct model for all machine-to-machine authentication.
Policies: JSON documents defining permissions. Attached to users, groups, or roles.
Policy types:
- Identity-based policies: Attached to an IAM identity, define what that identity can do
- Resource-based policies: Attached to a resource (S3 bucket, KMS key), define who can access that resource
- Permission boundaries: Maximum permissions an identity-based policy can grant — used to delegate admin safely
- SCPs: Org-level guardrails (covered in Q8)
Example — least-privilege policy for a service that reads from S3 and writes to DynamoDB:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadProcessingBucket",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-processing-bucket",
"arn:aws:s3:::my-processing-bucket/*"
]
},
{
"Sid": "WriteToOrdersTable",
"Effect": "Allow",
"Action": [
"dynamodb:PutItem",
"dynamodb:UpdateItem"
],
"Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/orders"
}
]
}Q12. How does an EC2 instance authenticate to AWS services without credentials in code?
Answer:
Through IAM Instance Profiles (which attach an IAM role to the instance).
When you attach a role to an EC2 instance, the instance metadata service (IMDS) provides temporary credentials that the AWS SDK automatically rotates. Your code never stores or manages credentials.
Trust policy for EC2 role:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}Python code — note there are no credentials:
import boto3
# The SDK automatically uses the instance role
s3 = boto3.client('s3')
response = s3.list_objects_v2(Bucket='my-bucket')Never do this:
# WRONG - hardcoded credentials
s3 = boto3.client(
's3',
aws_access_key_id='AKIAIOSFODNN7EXAMPLE',
aws_secret_access_key='wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'
)Use IMDSv2 (the newer version that requires a session token for the metadata call) to protect against SSRF attacks that could steal instance credentials.
Q13. What is the difference between an IAM Role and a Resource-Based Policy?
Answer:
IAM Role: You assume the role; the role's permissions apply to you. Cross-account access requires the target account to have a role that your account's principals can assume.
Resource-based policy: Attached directly to the resource (S3, SQS, KMS, Lambda, etc.). Grants access to specified principals, potentially from other accounts.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCrossAccountRead",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT-A-ID:role/data-reader"
},
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::shared-data-bucket",
"arn:aws:s3:::shared-data-bucket/*"
]
}
]
}Rule of thumb: For same-account access, identity-based policies are enough. For cross-account access, you need either a role with a trust policy pointing to the other account, or a resource-based policy — or both.
Q14. What is AWS Secrets Manager and how does it differ from Parameter Store?
Answer:
Secrets Manager:
- Designed specifically for secrets (DB passwords, API keys)
- Built-in automatic rotation (triggers a Lambda to rotate the secret)
- Costs ~$0.40/secret/month + API call charges
- Native integration with RDS, Redshift, DocumentDB for zero-downtime rotation
Parameter Store (SSM):
- General-purpose configuration storage
- Standard tier is free; Advanced tier costs ~$0.05/parameter/month
- No built-in rotation
- Good for non-secret config: feature flags, database hostnames, env vars
Fetching a secret in Python:
import boto3
import json
from functools import lru_cache
@lru_cache(maxsize=1)
def get_db_credentials() -> dict:
client = boto3.client('secretsmanager', region_name='us-east-1')
response = client.get_secret_value(SecretId='prod/myapp/db')
return json.loads(response['SecretString'])Caching matters: Don't call Secrets Manager on every Lambda invocation. Cache in the execution environment.
Q15. How do you secure an S3 bucket?
Answer:
1. Block Public Access (always on):
aws s3api put-public-access-block \
--bucket my-bucket \
--public-access-block-configuration \
"BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"2. Bucket policy — enforce HTTPS only:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyHTTP",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": ["arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*"],
"Condition": {
"Bool": { "aws:SecureTransport": "false" }
}
}
]
}3. Enable server-side encryption with KMS.
4. Enable versioning — protects against accidental deletes.
5. Enable access logging.
6. Use VPC Endpoint policies for internal services.
Q16. What is AWS KMS and how does envelope encryption work?
Answer:
KMS manages cryptographic keys. Envelope encryption:
- 1Ask KMS to generate a data encryption key (DEK)
- 2KMS returns the DEK in plaintext AND encrypted form
- 3Encrypt your data locally with the plaintext DEK
- 4Store the encrypted data + the encrypted DEK together
- 5Discard the plaintext DEK
To decrypt: send the encrypted DEK to KMS, get the plaintext DEK back, decrypt locally. Your actual data never goes to KMS.
import boto3, base64
from cryptography.fernet import Fernet
kms = boto3.client('kms', region_name='us-east-1')
KEY_ID = 'arn:aws:kms:us-east-1:123456789012:key/my-key-id'
def encrypt_data(plaintext: bytes) -> dict:
response = kms.generate_data_key(KeyId=KEY_ID, KeySpec='AES_256')
plaintext_dek = response['Plaintext']
encrypted_dek = response['CiphertextBlob']
fernet = Fernet(base64.urlsafe_b64encode(plaintext_dek[:32]))
encrypted_data = fernet.encrypt(plaintext)
del plaintext_dek
return {
'encrypted_data': base64.b64encode(encrypted_data).decode(),
'encrypted_dek': base64.b64encode(encrypted_dek).decode()
}Q17. What is AWS WAF and when would you use it?
Answer:
AWS WAF sits in front of CloudFront, ALB, API Gateway, or AppSync. It inspects HTTP requests and blocks ones matching rules you define.
Use it when: blocking specific IPs/countries, SQL injection/XSS protection, rate limiting by IP, compliance requirements.
resource "aws_wafv2_web_acl" "main" {
name = "production-waf"
scope = "REGIONAL"
default_action { allow {} }
rule {
name = "RateLimitRule"
priority = 2
action { block {} }
statement {
rate_based_statement {
limit = 2000
aggregate_key_type = "IP"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "RateLimit"
sampled_requests_enabled = true
}
}
}Q18. How does AWS GuardDuty work and what does it detect?
Answer:
GuardDuty analyzes CloudTrail logs, VPC Flow Logs, and DNS logs using ML and threat intelligence. Enable with one click; no agents.
Detects: Unusual API calls from foreign IPs, credential theft, crypto mining, port scanning from EC2 instances, brute force against RDS, data exfiltration patterns.
resource "aws_guardduty_detector" "main" {
enable = true
datasources {
s3_logs { enable = true }
kubernetes { audit_logs { enable = true } }
}
}Enable GuardDuty in every account and every region. Attackers know which regions companies neglect.
Compute: EC2, Lambda, ECS
Q19. Explain the EC2 instance lifecycle.
Answer:
- Pending: Starting; not billed yet
- Running: Running; billing starts
- Stopping → Stopped: Compute billing stops, EBS storage billing continues
- Shutting-down → Terminated: Instance deleted permanently
- Rebooting: OS reboot; stays on same host
Key gotcha: A stopped EC2 may get a new public IP when started (unless you use an Elastic IP). Private IP stays the same within the VPC.
Hibernate: Saves RAM contents to EBS; instance resumes in same state.
Q20. What is the difference between an ALB, NLB, and CLB?
Answer:
Classic Load Balancer (CLB): Legacy. Don't use for new projects.
Application Load Balancer (ALB): Layer 7. Routes based on HTTP content — path, headers, query parameters, hostname. Supports WebSockets, HTTP/2, gRPC. Right choice for web applications and microservices.
Network Load Balancer (NLB): Layer 4 (TCP/UDP). Millions of requests/second, sub-millisecond latency. Preserves client IP. Static IPs. Use for non-HTTP workloads.
resource "aws_lb_listener_rule" "api_v2" {
listener_arn = aws_lb_listener.https.arn
priority = 100
condition {
path_pattern { values = ["/api/v2/*"] }
}
action {
type = "forward"
target_group_arn = aws_lb_target_group.api_v2.arn
}
}Q21. What is AWS Lambda? What are its limits and cold start behavior?
Answer:
Lambda is serverless compute. You pay per invocation and per GB-second of compute.
Hard limits:
- Max execution timeout: 15 minutes
- Memory: 128 MB – 10,240 MB
- Ephemeral storage: 512 MB – 10,240 MB
- Concurrent executions: 1,000 per region default
- Payload: 6 MB synchronous, 256 KB async
Cold start: When no warm environment exists, Lambda provisions a new one (100ms–1s extra latency depending on runtime and package size).
import boto3
# Initialize outside handler — reused across warm invocations
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('orders')
def lambda_handler(event, context):
response = table.get_item(Key={'id': event['id']})
return response.get('Item')Provisioned concurrency: Pre-warm N environments to eliminate cold starts for critical functions.
Q22. What is the difference between ECS and EKS?
Answer:
ECS: AWS-native container orchestrator. Simpler. Two launch types: EC2 (you manage instances) or Fargate (serverless).
EKS: Managed Kubernetes. Full Kubernetes API compatibility. More complex, but portable across clouds.
Choose ECS: AWS-only, want simplicity, no Kubernetes expertise needed.
Choose EKS: Team knows Kubernetes, need Kubernetes-native tooling, multi-cloud requirements.
{
"family": "web-api",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "512",
"memory": "1024",
"containerDefinitions": [{
"name": "web-api",
"image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/web-api:v1.2.3",
"portMappings": [{"containerPort": 8080}],
"secrets": [{
"name": "DB_PASSWORD",
"valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/db-password"
}]
}]
}Q23. How does Lambda handle concurrency and what is reserved concurrency?
Answer:
Lambda scales by running multiple instances simultaneously. Account limit: 1,000 concurrent executions per region (shared across all functions).
Reserved concurrency: Guarantee a specific number for a function, and cap it at that number.
Provisioned concurrency: Pre-initialized environments, always warm. Costs apply when idle.
lambda_client = boto3.client('lambda')
lambda_client.put_function_concurrency(
FunctionName='payment-processor',
ReservedConcurrentExecutions=100
)Always set reserved concurrency for critical functions and monitor the Throttles CloudWatch metric.
Q24. What is AWS Fargate?
Answer:
Fargate is serverless compute for containers. No EC2 instances to provision, manage, or patch. You define your container spec; Fargate runs it.
| Aspect | ECS on EC2 | ECS on Fargate |
|---|---|---|
| Operational overhead | Higher | Lower |
| Cost for sustained workloads | Lower (reserved instances) | Higher |
| Cost for spiky workloads | Higher | Lower |
| Customization | Full OS access | No OS access |
When Fargate makes sense: Microservices with variable traffic, batch jobs, workloads where engineering time > compute cost.
Q25. Explain EC2 Spot Instances.
Answer:
Spot Instances are unused EC2 capacity at 60–90% discount. AWS can reclaim with 2-minute warning.
Use for: Stateless web workers, batch processing, ML training, CI/CD runners.
Never use for: Databases, stateful applications.
def check_spot_interruption() -> bool:
try:
token_response = requests.put(
'http://169.254.169.254/latest/api/token',
headers={'X-aws-ec2-metadata-token-ttl-seconds': '21600'},
timeout=1
)
response = requests.get(
'http://169.254.169.254/latest/meta-data/spot/interruption-action',
headers={'X-aws-ec2-metadata-token': token_response.text},
timeout=1
)
return response.status_code == 200
except:
return FalseUse multiple instance types and AZs in Spot Fleet. Set capacity-optimized allocation strategy.
Q26. What is AWS Step Functions?
Answer:
Step Functions orchestrates multi-step workflows as state machines. Each state can invoke Lambda, wait for approval, retry on failure, run parallel branches, or wait days for an event.
Use over SQS when: orchestrating multiple services in sequence, need retry/error handling at workflow level, need visibility into current step, long-running workflows.
{
"StartAt": "ValidateOrder",
"States": {
"ValidateOrder": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:validate-order",
"Retry": [{"ErrorEquals": ["Lambda.ServiceException"], "MaxAttempts": 3}],
"Next": "ChargePayment"
},
"ChargePayment": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:charge-payment",
"Next": "OrderComplete"
},
"OrderComplete": {"Type": "Succeed"}
}
}Q27. What is Amazon ECR?
Answer:
ECR is a managed Docker container registry in your AWS account. IAM-based access control, vulnerability scanning, lifecycle policies.
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin \
123456789012.dkr.ecr.us-east-1.amazonaws.com
docker build -t web-api:${GITHUB_SHA} .
docker tag web-api:${GITHUB_SHA} \
123456789012.dkr.ecr.us-east-1.amazonaws.com/web-api:${GITHUB_SHA}
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/web-api:${GITHUB_SHA}Set lifecycle policies to delete untagged images older than 7 days and keep only the last 10 tagged versions.
Storage: S3, EBS, EFS
Q28. Explain S3 storage classes.
| Storage Class | Use Case | Retrieval |
|---|---|---|
| S3 Standard | Frequently accessed | Immediate |
| S3 Intelligent-Tiering | Unknown access patterns | Immediate |
| S3 Standard-IA | Infrequent, immediate retrieval | Immediate |
| S3 Glacier Instant Retrieval | Archive, few times/year | Milliseconds |
| S3 Glacier Flexible Retrieval | Long-term archive | 1–12 hours |
| S3 Glacier Deep Archive | 7-10 year compliance | 12–48 hours |
{
"Rules": [{
"ID": "LogRetentionPolicy",
"Status": "Enabled",
"Filter": {"Prefix": "logs/"},
"Transitions": [
{"Days": 30, "StorageClass": "STANDARD_IA"},
{"Days": 90, "StorageClass": "GLACIER_IR"},
{"Days": 365, "StorageClass": "DEEP_ARCHIVE"}
],
"Expiration": {"Days": 2555}
}]
}Q29. What is S3 multipart upload?
Answer:
For objects over 100 MB, use multipart upload. Objects over 5 GB require it (single PUT limit). Benefits: resume interrupted uploads, parallel upload of parts.
from boto3.s3.transfer import TransferConfig
config = TransferConfig(
multipart_threshold=100 * 1024 * 1024,
max_concurrency=10,
multipart_chunksize=100 * 1024 * 1024,
use_threads=True
)
s3.upload_file(Filename=local_path, Bucket=bucket, Key=key, Config=config)Set a lifecycle rule to abort incomplete multiparts after 7 days — they cost money.
Q30. What is the difference between S3, EBS, and EFS?
Answer:
S3: Object storage via HTTP API. Infinitely scalable. Good for static files, backups, data lake, media. Not for POSIX filesystem access.
EBS: Block storage attached to a single EC2 instance. High performance, low latency. Provisioned capacity. Good for OS volumes, databases on EC2.
EFS: NFS-compatible shared file system. Multiple EC2 instances can mount it simultaneously. More expensive than EBS per GB. Good for shared config, CMS media, anything needing concurrent read/write from multiple instances.
Decision: Multiple services need same data → EFS. One instance, high performance → EBS. HTTP access, large scale → S3.
Q31. How do you design a disaster recovery strategy for S3?
Answer:
S3 already stores data across 3+ AZs (11 nines durability). For higher requirements:
S3 Cross-Region Replication (CRR): Automatically replicate objects to another region.
resource "aws_s3_bucket_replication_configuration" "replication" {
role = aws_iam_role.replication.arn
bucket = aws_s3_bucket.source.id
rule {
id = "replicate-all"
status = "Enabled"
destination {
bucket = aws_s3_bucket.destination.arn
storage_class = "STANDARD_IA"
}
}
}Also: enable versioning on both source and destination, consider Object Lock (WORM) for compliance data, and MFA Delete to prevent accidental deletion.
Q32. What are S3 pre-signed URLs?
Answer:
A time-limited URL granting temporary access to a private S3 object. No AWS credentials needed by the requester.
Use cases: Direct browser uploads, time-limited download links, sharing private files externally.
def create_presigned_upload_url(bucket, key, content_type, expiry_seconds=300):
return s3.generate_presigned_post(
Bucket=bucket,
Key=key,
Fields={'Content-Type': content_type},
Conditions=[
{'Content-Type': content_type},
['content-length-range', 1, 10 * 1024 * 1024]
],
ExpiresIn=expiry_seconds
)Q33. How does EBS snapshot work?
Answer:
EBS snapshots are point-in-time copies stored in S3 (not visible in your buckets). Incremental after the first full snapshot — only changed blocks stored.
Amazon Data Lifecycle Manager (DLM) automates backups:
resource "aws_dlm_lifecycle_policy" "ebs_backup" {
description = "Daily EBS snapshots with 7-day retention"
execution_role_arn = aws_iam_role.dlm.arn
state = "ENABLED"
policy_details {
resource_types = ["VOLUME"]
schedule {
name = "Daily snapshots"
create_rule { interval = 24; interval_unit = "HOURS"; times = ["03:00"] }
retain_rule { count = 7 }
}
target_tags = { Backup = "daily" }
}
}Networking: VPC, Route 53, CloudFront
Q34. Explain VPC, subnets, route tables, and security groups.
Answer:
VPC: Your isolated network. You define the IP CIDR block.
Public subnet: Route table has route to Internet Gateway. Resources reachable from internet.
Private subnet: No route to Internet Gateway. Reach internet via NAT Gateway.
Security group: Stateful firewall attached to instances. Allow rules only. Stateful — return traffic automatically allowed.
NACL: Stateless firewall at subnet level. Explicit allow for both directions. Use to block specific IPs.
Standard 3-tier architecture:
Public subnets: Load Balancers, NAT Gateways
Private app: EC2/ECS/Lambda
Private data: RDS, ElastiCache (no internet access)resource "aws_security_group" "app" {
ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
security_groups = [aws_security_group.alb.id] # Only from ALB
}
egress {
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.rds.id] # Only to RDS
}
}Q35. What is a NAT Gateway?
Answer:
Allows instances in private subnets to initiate outbound internet connections while remaining unreachable from outside.
One NAT Gateway per AZ for high availability. Cost: ~$0.045/hr + $0.045/GB processed.
Optimization: Use VPC Endpoints for AWS service traffic — bypasses NAT Gateway entirely.
resource "aws_vpc_endpoint" "s3" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.us-east-1.s3"
vpc_endpoint_type = "Gateway"
route_table_ids = aws_route_table.private[*].id
}Q36. How does Route 53 routing work?
Answer:
Simple: One record, one destination.
Weighted: Split traffic by percentage. Good for canary deployments.
Latency-based: Route to region with lowest latency for user.
Failover: Route to secondary if health checks fail on primary.
Geolocation: Route based on user's geographic location (GDPR data residency).
Multi-value: Returns multiple records; removes unhealthy ones.
resource "aws_route53_record" "api_canary" {
zone_id = aws_route53_zone.main.zone_id
name = "api.example.com"
type = "A"
weighted_routing_policy { weight = 10 }
set_identifier = "canary"
alias {
name = aws_lb.canary.dns_name
zone_id = aws_lb.canary.zone_id
evaluate_target_health = true
}
}Q37. How does CloudFront work?
Answer:
CloudFront is AWS's CDN. Requests for cached content are served from the nearest edge location — faster for users, cheaper for your origin.
Cache by: URL path by default. Add headers, query strings, cookies to cache key selectively.
Lambda@Edge / CloudFront Functions: Run code at edge for A/B testing, auth, URL rewrites, security headers.
function handler(event) {
var response = event.response;
response.headers['strict-transport-security'] = {
value: 'max-age=31536000; includeSubdomains; preload'
};
response.headers['x-content-type-options'] = { value: 'nosniff' };
response.headers['x-frame-options'] = { value: 'DENY' };
return response;
}Q38. What is VPC Peering vs. Transit Gateway?
Answer:
VPC Peering: Direct connection between two VPCs. Not transitive.
Transit Gateway: Hub-and-spoke. All attached VPCs can communicate. Centralized routing.
Use peering for 2–5 VPCs. Use Transit Gateway for 6+ or when you need on-premises connectivity. At 10 VPCs, peering requires up to 45 connections; Transit Gateway requires 10 attachments.
Q39. How do you connect on-premises to AWS?
Answer:
Site-to-Site VPN: IPSec over internet. Quick to set up. Up to 1.25 Gbps. Cost: ~$0.05/hr.
Direct Connect: Dedicated private fiber. 1–100 Gbps. Consistent latency. Takes weeks to provision. Essential for latency-sensitive or high-volume workloads.
Hybrid: Direct Connect as primary, VPN as backup. Both connect to Transit Gateway for routing to multiple VPCs.
Databases: RDS, DynamoDB, ElastiCache
Q40. When would you use RDS vs. DynamoDB?
Answer:
RDS: Complex queries with JOINs/transactions, existing relational models, reporting, SQL-interface requirements.
DynamoDB: Single-digit millisecond latency at any scale, massive throughput, known access patterns, serverless architectures, gaming/IoT/sessions/carts.
Common mistake: Choosing DynamoDB because it "scales better" without understanding that NoSQL data modeling is harder. Access patterns must be designed upfront.
Complex relational queries / ACID transactions? → RDS/Aurora
<10ms latency at millions req/sec, known patterns? → DynamoDB
Need both? → Use both: RDS for complex queries, DynamoDB for hot pathsQ41. Explain DynamoDB primary keys, GSIs, and LSIs.
Answer:
Partition key only: Every item has a unique partition key.
Composite key: Partition key + sort key combination must be unique. Enables range queries.
GSI: Index with different partition key. Query by non-primary attributes. Eventually consistent. Can add after creation.
LSI: Same partition key, different sort key. Must be created at table creation. Range queries within a partition.
# Single-table design: one table stores Organizations, Users, Projects
table.put_item(Item={
'PK': 'ORG#acme',
'SK': 'USER#user-123',
'GSI1PK': 'USER#user-123',
'GSI1SK': 'PROFILE',
'name': 'Alice Smith',
'email': 'alice@acme.com'
})
# Query all items for org
response = table.query(
KeyConditionExpression='PK = :pk',
ExpressionAttributeValues={':pk': 'ORG#acme'}
)Q42. What is Aurora and how is it different from standard RDS?
Answer:
Aurora is AWS's cloud-native relational database (MySQL/PostgreSQL compatible) with a rewritten storage layer.
Key differences:
- Storage: Distributed across 3 AZs, 6 copies of data. Survives losing 2 copies for reads, 3 for writes.
- Read replicas: Up to 15, share underlying storage (near-instant replication). Standard RDS: 5.
- Failover: ~30 seconds vs. RDS Multi-AZ ~60-120 seconds.
- Aurora Serverless v2: Scales in 0.5 ACU increments, responds in seconds.
- Aurora Global Database: Up to 5 secondary regions, replication lag under 1 second.
Use Aurora over RDS when you need more read replicas, faster failover, Global Database, or high write throughput.
Q43. How does DynamoDB handle capacity?
Answer:
Provisioned: Specify RCUs and WCUs. Pay for allocated capacity. Throttling when exceeded. Enable auto-scaling to adjust based on utilization.
On-demand: Pay per request. No capacity planning. More expensive per request at steady state. Ideal for unpredictable workloads.
When to use:
- Predictable, steady traffic → Provisioned + Auto Scaling
- Spiky or unknown traffic → On-Demand
- Dev/test → On-Demand
Hot partition warning: If 90% of traffic hits one partition key, that partition throttles regardless of total capacity. Design for even distribution; use write sharding for truly hot keys.
Q44. When would you use ElastiCache? Redis vs. Memcached?
Answer:
Use ElastiCache when your database is the bottleneck and the same queries are repeated. Common uses: session storage, query caching, rate limiting, leaderboards.
Default to Redis. Memcached is multi-threaded but Redis wins on data structures, persistence, replication, and pub/sub.
def cache_aside(key, ttl_seconds, fetch_fn, *args, **kwargs):
cached = redis_client.get(key)
if cached is not None:
return json.loads(cached)
result = fetch_fn(*args, **kwargs)
if result is not None:
redis_client.setex(key, ttl_seconds, json.dumps(result))
return result
def get_user_profile(user_id):
return cache_aside(
key=f"user:profile:{user_id}",
ttl_seconds=300,
fetch_fn=db.query_user_profile,
user_id=user_id
)Architecture and Best Practices
Q45. Design a highly available, scalable web application on AWS.
Answer:
Route 53 (latency-based routing)
↓
CloudFront (CDN, WAF, SSL termination)
↓
Application Load Balancer (HTTPS, health checks)
↓
Auto Scaling Group of EC2 (or ECS Fargate)
across 3 Availability Zones
↓
├── Aurora PostgreSQL (Multi-AZ, read replicas)
├── ElastiCache Redis (sessions, cache)
└── SQS + Lambda (async jobs)
Supporting:
S3, CloudFront→S3, Secrets Manager,
CloudWatch, GuardDuty, WAFKey decisions:
- Multi-AZ app tier: ASG across 3 AZs; ALB routes to healthy only
- Aurora Multi-AZ: ~30s failover, synchronous standby
- ElastiCache: Cache frequent reads, reduce DB load 60–80%
- SQS for async: Email, image processing, notifications — decouple from request cycle
- CloudFront: Reduces origin hits, absorbs DDoS at edge
Q46. What is blue/green deployment and how do you implement it on AWS?
Answer:
Two identical environments ("blue" = current, "green" = new). Deploy to green, test, cut traffic over. Rollback = switch back to blue.
Implementations:
- Route 53 weighted routing: Gradually shift 100% → 90/10 → 50/50 → 100%
- ALB target group switching: Change listener's default action instantaneously
- CodeDeploy ECS: Built-in canary and linear configurations
resource "aws_codedeploy_deployment_group" "ecs_bg" {
deployment_config_name = "CodeDeployDefault.ECSCanary10Percent5Minutes"
auto_rollback_configuration {
enabled = true
events = ["DEPLOYMENT_FAILURE", "DEPLOYMENT_STOP_ON_ALARM"]
}
alarm_configuration {
alarms = [aws_cloudwatch_metric_alarm.error_rate.name]
enabled = true
}
}Q47. How do you design for failure on AWS?
Answer:
Principles:
- 1Redundancy at every tier: multiple instances, multiple AZs
- 2No single points of failure
- 3Graceful degradation: non-critical failures return degraded responses, not errors
- 4Circuit breakers: stop calling failing services, return fallback
- 5Timeout everything: every external call must have a timeout
- 6Idempotent operations: retries don't cause duplicates
- 7Dead letter queues: failed messages saved for investigation
resource "aws_sqs_queue" "orders" {
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.orders_dlq.arn
maxReceiveCount = 3
})
}
resource "aws_cloudwatch_metric_alarm" "dlq_messages" {
alarm_name = "OrdersDLQ-HasMessages"
comparison_operator = "GreaterThanThreshold"
threshold = 0
metric_name = "ApproximateNumberOfMessagesVisible"
namespace = "AWS/SQS"
alarm_actions = [aws_sns_topic.ops_alerts.arn]
}Chaos engineering: AWS Fault Injection Simulator (FIS) deliberately injects failures (terminate instances, inject latency, fail AZs) to test system resilience.
Q48. What is AWS CodePipeline and how do you build a CI/CD pipeline?
Answer:
CodePipeline orchestrates CI/CD: Source → Build → Deploy.
Realistic pipeline:
GitHub push → CodeBuild (test + docker build + ECR push)
→ Deploy to Staging (ECS blue/green)
→ Manual approval
→ Deploy to Production (canary 10% → 5 min → 100%)
→ Auto-rollback on alarm# buildspec.yml
version: 0.2
phases:
pre_build:
commands:
- aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_REGISTRY
build:
commands:
- docker build --target test -t test-image .
- docker run --rm test-image pytest tests/
- docker build -t $ECR_REGISTRY/$IMAGE_REPO:$CODEBUILD_RESOLVED_SOURCE_VERSION .
- docker push $ECR_REGISTRY/$IMAGE_REPO:$CODEBUILD_RESOLVED_SOURCE_VERSION
- printf '[{"name":"%s","imageUri":"%s"}]' $CONTAINER_NAME $ECR_REGISTRY/$IMAGE_REPO:$CODEBUILD_RESOLVED_SOURCE_VERSION > imagedefinitions.json
artifacts:
files:
- imagedefinitions.jsonWhat Interviewers Are Really Evaluating
1. Breadth of knowledge. Can you name the right service for a given problem?
2. Depth on at least a few topics. Know IAM, VPC, and one or two core services deeply. Discuss trade-offs, not just definitions.
3. Judgment. Can you reason through an architecture decision? Name constraints, propose a solution, identify weaknesses, explain mitigations.
Quick-Reference: Services and Their Purpose
| Service | Purpose |
|---|---|
| EC2 | Virtual machines |
| Lambda | Serverless functions |
| ECS | Container orchestration |
| EKS | Managed Kubernetes |
| Fargate | Serverless containers |
| S3 | Object storage |
| EBS | Block storage for EC2 |
| EFS | Shared file system |
| RDS | Managed relational databases |
| Aurora | Cloud-native MySQL/PostgreSQL |
| DynamoDB | Managed NoSQL database |
| ElastiCache | Managed Redis/Memcached |
| VPC | Isolated network |
| Route 53 | DNS and routing |
| CloudFront | CDN |
| ALB/NLB | Load balancers |
| IAM | Identity and access management |
| KMS | Key management |
| Secrets Manager | Secrets storage with rotation |
| CloudWatch | Monitoring and logs |
| CloudTrail | API audit logging |
| GuardDuty | Threat detection |
| WAF | Web application firewall |
| SQS | Message queue |
| SNS | Pub/sub notifications |
| EventBridge | Event bus and routing |
| Step Functions | Workflow orchestration |
| CodePipeline | CI/CD orchestration |
| CodeBuild | Build service |
| CodeDeploy | Deployment automation |
| CloudFormation | Infrastructure as code |
| Organizations | Multi-account management |
| Direct Connect | Dedicated network to AWS |