AWS for .NET — Overview
Key Points
- .NET is a first-class citizen on AWS in 2026. Lambda has a managed
dotnet8/dotnet9runtime; the AWS SDK for .NET covers every major service; Visual Studio, Rider, anddotnetCLI all have AWS extensions. - The "Azure → AWS" translation table is short. Every major Azure service has a near-equivalent AWS counterpart; the operational vocabulary differs, the underlying patterns don't.
- AWS is account/region/VPC-centric. Azure is subscription/region/vnet-centric. Same concepts, different boundaries; you don't get to use Azure's mental model unchanged.
- The four foundational services for most .NET workloads on AWS: Lambda (serverless compute), SQS + SNS (queues + pub/sub), DynamoDB (managed NoSQL), S3 (object storage). Add EventBridge (event bus) and Kinesis (streaming) for event-driven workloads.
- Identity is IAM, not Entra ID. Roles, policies, instance profiles, IAM Identity Center. The mental shift Azure-first engineers usually need: AWS's authorization is more granular and more verbose, with effects (
Allow/Deny) explicit in every policy. - Pick your single cloud unless multi-cloud is a stated requirement. Multi-cloud means twice the IaC, twice the IAM, twice the observability — for benefits that rarely materialize.
Concepts (deep dive)
Why this file exists in an Azure-leaning guide
This guide's other 12-section topics are Azure-deep. That reflects the guide's audience: .NET shops working in the Microsoft ecosystem. But the 2026 reality is that many .NET teams also touch AWS — a customer's AWS account, an acquired company on AWS, a multi-cloud product, a cost-driven migration. This file is the bridge: a senior .NET engineer who's fluent in Azure should be able to come here and have a working model of AWS within an hour, without reading five separate AWS overview docs.
It's deliberately one file, not five. The depth target is "enough to make informed decisions and read the AWS docs from the right starting point" — not "ship a production AWS app from this page alone."
The Azure → AWS translation table
The biggest unlock for an Azure-first engineer is realising that most things have a 1:1 equivalent:
| Azure | AWS | Notes |
|---|---|---|
| App Service | Elastic Beanstalk or App Runner or ECS/Fargate | Beanstalk = nearest "managed web app" cousin; App Runner is the modern simple choice; ECS/Fargate for container-based |
| Functions | Lambda | Same idea: event-driven serverless. Lambda has stricter timeouts (15 min max) |
| Container Apps | ECS on Fargate or App Runner | Container Apps' KEDA-style scaling ≈ Fargate + Application Auto Scaling |
| AKS | EKS | Both managed Kubernetes; same complexity |
| Service Bus (queue) | SQS | Simpler than Service Bus; no sessions/dead-letter-deep features |
| Service Bus (topic) | SNS + SQS | SNS is pub/sub; subscribers are SQS queues, Lambdas, HTTP endpoints |
| Event Hubs | Kinesis Data Streams | Same model: partitioned, durable, replayable stream |
| Event Grid | EventBridge | Event bus; pattern-based routing; SaaS event sources |
| Cosmos DB | DynamoDB | Both managed NoSQL; DynamoDB is simpler and cheaper at scale, less flexible per-query |
| Cosmos DB (Mongo API) | DocumentDB | Mongo-compatible managed service |
| Azure SQL | RDS (SQL Server, PostgreSQL, MySQL) or Aurora | RDS = managed instance; Aurora = AWS-native, cheaper, faster |
| Blob Storage | S3 | The industry standard for object storage |
| Queue Storage | (use SQS) | AWS doesn't have a separate cheap-queue tier; SQS handles both |
| Table Storage | (use DynamoDB) | DynamoDB covers Table's use case |
| Files (SMB) | EFS (Linux NFS) / FSx (Windows SMB) | FSx for direct SMB equivalent |
| Key Vault | Secrets Manager + Parameter Store | Secrets Manager for rotating secrets; Parameter Store for config |
| App Configuration | Parameter Store + AppConfig | AppConfig handles feature flags; Parameter Store handles config |
| Application Insights | CloudWatch + X-Ray | CloudWatch = logs/metrics; X-Ray = distributed tracing |
| Azure Monitor Logs | CloudWatch Logs | Same idea; query language is different (Logs Insights vs KQL) |
| API Management | API Gateway | More raw than APIM; you'll write more Lambda/integration glue |
| Front Door | CloudFront (+ Global Accelerator) | CDN + edge routing |
| App Gateway / WAF | ALB + AWS WAF | Application Load Balancer + WAF |
| Bicep / ARM | CloudFormation | CFN is older, more verbose; most teams reach for Terraform or CDK instead |
az CLI | aws CLI | Same role; richer scripting via --query (JMESPath) |
azd (Azure Developer CLI) | CDK + aws CLI + SAM | No direct "one tool" equivalent; SAM is the Lambda/Serverless-Framework lane |
| Managed Identity | IAM Roles (for EC2/Lambda) + STS | Same shape: code asks for a credential, infra returns one tied to the workload |
| Entra ID | IAM Identity Center (workforce) / Cognito (customer) | Two products: IAM IC for employees; Cognito for end-users |
This table is the cheat sheet. Internalise it and most "how do I do X on AWS?" questions answer themselves.
Lambda for .NET
Lambda is the obvious place to start because the .NET story is well-developed and the pattern is familiar:
using Amazon.Lambda.Core;
using Amazon.Lambda.APIGatewayEvents;
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
public class OrderHandler
{
public async Task<APIGatewayProxyResponse> Get(APIGatewayProxyRequest req, ILambdaContext ctx)
{
var id = req.PathParameters["id"];
ctx.Logger.LogInformation("Fetching order {id}", id);
// ...
return new APIGatewayProxyResponse { StatusCode = 200, Body = JsonSerializer.Serialize(order) };
}
}
The .NET-specific story:
- Managed runtime: Lambda supports
dotnet8,dotnet9(and historical versions). You ship a published .NET app; Lambda runs it. - Native AOT: Lambda supports custom runtimes with AOT-compiled .NET. Cold starts drop from 1–3 seconds to ~100 ms. The 2026 default for new latency-sensitive Lambdas.
- Lambda Annotations Framework — a source-generator-based programming model that lets you write idiomatic ASP.NET-style endpoints (with attribute routing) and have them generate the Lambda boilerplate at compile time:
public class OrdersFunctions
{
[LambdaFunction]
[HttpApi(LambdaHttpMethod.Get, "/orders/{id}")]
public async Task<Order> GetOrder(int id, [FromServices] IOrderRepository repo)
=> await repo.GetAsync(id);
}
- Hosting an ASP.NET Core app in Lambda: the
Amazon.Lambda.AspNetCoreServerpackage wraps an ASP.NET Core app and routes Lambda events through the standard middleware pipeline. Useful for migrating an existing ASP.NET API to Lambda without a rewrite — cold start cost is higher than a native Lambda function.
The big gotchas vs Azure Functions:
- 15-minute hard timeout. No equivalent of "always-on Premium plan with longer runtime."
- Concurrent execution limits per region (default 1,000). Production workloads usually request increases.
- Cold start is real, especially on .NET; AOT or "provisioned concurrency" (pre-warmed instances) are the levers.
- Lambda destinations (success/failure async invocations forwarded to SQS/SNS/EventBridge/another Lambda) replace some of what Azure Functions input/output bindings do.
SQS and SNS
SQS is AWS's queue service; SNS is the pub/sub service. Together they cover what Service Bus does in Azure, with the model split.
SQS — Standard or FIFO queues:
var sqs = new AmazonSQSClient();
await sqs.SendMessageAsync(new SendMessageRequest
{
QueueUrl = "https://sqs.us-east-1.amazonaws.com/123/orders",
MessageBody = JsonSerializer.Serialize(order),
MessageGroupId = order.CustomerId.ToString(), // FIFO only
MessageDeduplicationId = order.Id.ToString() // FIFO only
});
| Property | Standard | FIFO |
|---|---|---|
| Throughput | Effectively unlimited | 300 msg/s per queue (3,000 with batching) |
| Ordering | Best-effort | Strict per-MessageGroupId |
| Delivery | At-least-once | Exactly-once (deduplication window: 5 minutes) |
| Cost | Cheaper | Slightly more |
For most .NET workloads, FIFO is what Service Bus users expect; Standard is fine for fire-and-forget telemetry.
SNS publishes to subscribers — SQS queues, Lambdas, HTTP/HTTPS endpoints, email/SMS. Pattern:
[Publisher] ──► SNS topic ──┬──► SQS queue (Service A)
├──► SQS queue (Service B)
└──► Lambda (audit logger)
The pattern is "publish once, fan out." Each subscriber processes independently. This is the modern AWS event-driven default for service-to-service: combine SNS + SQS to get pub/sub and per-consumer durability.
Dead-letter queues, retries, message visibility timeouts, and idempotent consumers all apply — see messaging fundamentals and idempotency keys.
EventBridge
EventBridge is the AWS event bus — pattern-based routing of events to targets, with first-class support for SaaS integrations (Salesforce, Shopify, Stripe, etc. all publish events directly to EventBridge).
[Source: aws.s3] ──┐
[Source: aws.ec2] ──┼──► [EventBridge rule]──► Lambda
[Source: contoso.app] ──┤ pattern: { SQS
[Source: SaaS partner]──┘ "source": ["aws.s3"], SNS
"detail-type": ["ObjectCreated"]
}
Use cases:
- React to AWS service events (an S3 upload, an EC2 state change, a CloudWatch alarm).
- Route custom application events to multiple consumers based on payload patterns.
- Schedule recurring invocations (replaces "CloudWatch Events" of yore).
- Receive events from SaaS partners without writing webhook receivers.
When to use EventBridge vs SNS: EventBridge has richer rule matching and SaaS integrations; SNS is simpler and faster. The shorthand: SNS for high-volume fan-out, EventBridge for routing/filtering/SaaS.
Kinesis Data Streams
Kinesis is AWS's equivalent of Event Hubs: a partitioned, durable, replayable stream. Producers write; multiple consumers read independently with their own cursors; data is retained for 24h (default) up to 365 days.
var kinesis = new AmazonKinesisClient();
await kinesis.PutRecordAsync(new PutRecordRequest
{
StreamName = "order-events",
Data = new MemoryStream(JsonSerializer.SerializeToUtf8Bytes(orderEvent)),
PartitionKey = orderEvent.CustomerId.ToString()
});
Consumers use the Kinesis Client Library (KCL) — including a .NET implementation — which handles shard discovery, lease management, and checkpointing. For modern .NET, Kinesis as a Lambda trigger is the simplest pattern: Lambda polls the stream, you write handlers that process batches of records.
When to use Kinesis vs SQS: Kinesis is ordered, durable, replayable, and high-throughput per partition; SQS is unordered (Standard) or low-throughput (FIFO), drop-on-ack. Use Kinesis when consumers need to replay or when multiple independent consumers each track their own position.
DynamoDB
DynamoDB is AWS's managed NoSQL service — single-digit-millisecond reads/writes at any scale, fully managed, with strict access patterns at the cost of query flexibility.
The mental model:
- Tables with a partition key (hash) and optional sort key (range).
- Items are documents (up to 400 KB).
- Queries must include the partition key (and optionally filter by sort key).
- Scans read the whole table — avoid in production.
- GSI / LSI (Global / Local Secondary Indexes) provide alternative access patterns without duplicating data.
- DAX (DynamoDB Accelerator) is an in-memory cache; sub-millisecond reads for hot keys.
var ddb = new AmazonDynamoDBClient();
var item = new Dictionary<string, AttributeValue>
{
["pk"] = new AttributeValue($"ORDER#{orderId}"),
["sk"] = new AttributeValue("METADATA"),
["customerId"] = new AttributeValue(customerId),
["total"] = new AttributeValue { N = total.ToString() }
};
await ddb.PutItemAsync("orders", item);
For idiomatic .NET, use the AmazonDynamoDBClient directly for control, or the Object Persistence Model (POCO mapping) for simpler cases. Amazon.DynamoDBv2.DataModel offers attribute-based mapping similar to EF Core's lightweight modes, but it's not an ORM — there are no migrations, no LINQ, no change tracking.
The Cosmos-DB-vs-DynamoDB comparison is in Choosing the right database for the workload; the short version: DynamoDB is more opinionated, cheaper at scale, less flexible per-query. Design access patterns up front.
S3
S3 is what every other cloud's object storage is benchmarked against. There's not much to say specifically about .NET integration — it's been polished for over a decade:
var s3 = new AmazonS3Client();
await s3.PutObjectAsync(new PutObjectRequest
{
BucketName = "contoso-uploads",
Key = $"customers/{customerId}/avatar.png",
InputStream = imageStream,
ContentType = "image/png"
});
Notes worth knowing:
- Storage classes (Standard, Standard-IA, Glacier, Glacier Deep Archive) trade cost vs retrieval time.
- Lifecycle rules transition objects automatically between classes.
- Pre-signed URLs are S3's SAS-token equivalent — short-lived signed URLs for direct browser upload/download.
- S3 events (object created/deleted) publish to SNS, SQS, EventBridge, or invoke Lambda directly. The canonical "upload triggers processing" pattern.
- Versioning is opt-in per bucket; strongly recommended in production.
IAM: the auth model you have to internalise
AWS authorization runs through IAM policies — JSON documents attached to users, roles, groups, or resources. Every API call is checked against every relevant policy; an explicit Deny wins; otherwise an Allow is required.
Minimum-viable Lambda execution role:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": ["dynamodb:GetItem", "dynamodb:PutItem"],
"Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/orders"
}
]
}
The mental shifts vs Azure RBAC:
- Resource ARNs are granular. Permission can be scoped to a single table, a single bucket prefix, a single secret. Azure's RBAC is coarser.
- Allow + Deny. Azure RBAC has only Allow; AWS has both, and Deny wins.
- Policy types: identity-based (attached to principal), resource-based (attached to bucket/queue/etc.), permission boundary (a ceiling), SCP (org-wide ceiling). Order matters.
- Roles, not credentials, for workloads. Lambda assumes an execution role; EC2 instances have instance profiles. Code never sees an access key (analogous to Azure Managed Identity).
The biggest IAM pitfall for newcomers: starting with "Resource": "*" "to make it work," then never tightening it. Production IAM is verbose by design.
Accounts, regions, VPCs
AWS's organisational shape is:
- Account — billing and IAM boundary. Each account is independent; you cross accounts via cross-account IAM trust. Most production setups use AWS Organizations to manage many accounts (one per env, one per team).
- Region — geographic location (
us-east-1,eu-west-1). Each region is independent; cross-region operations are explicit. - Availability Zone (AZ) — failure domain within a region. Production deploys span at least two AZs.
- VPC — virtual network within a region. Holds subnets (public + private), route tables, security groups, NAT gateways.
The "many accounts" pattern is heavier than "many Azure subscriptions" — it's the expected shape for production AWS. Tools: AWS Organizations (account hierarchy), AWS Control Tower (guardrails), AWS Identity Center (SSO across accounts).
IaC on AWS: pick one
Three main paths for .NET teams:
| Tool | Style | When |
|---|---|---|
| CloudFormation (CFN) | AWS-native, declarative JSON/YAML | Don't pick first; it's verbose and slow. Tolerable if your org standardises on it. |
| AWS CDK | Programmatic IaC in TypeScript/Python/Java/C# (compiles to CFN) | Senior default if you like writing IaC as code. C# CDK is real and supported. |
| Terraform | HCL, multi-cloud | The most common third-party choice; works equally well for Azure + AWS shops. Covered in Terraform with Azure. |
For a .NET team that already uses Bicep on Azure, CDK in C# is the most familiar leap. For a team that wants one IaC tool across clouds, Terraform.
Cost shape and pricing surprises
AWS pricing has a few common surprises for Azure-first teams:
- Egress is metered. Data leaving an AZ, leaving a region, or leaving AWS entirely costs money. Cross-AZ traffic alone has surprised many teams' budgets.
- NAT Gateway is per-hour and per-GB. A chatty service in a private subnet talking to the internet through a NAT gateway runs up surprise bills.
- DynamoDB on-demand vs provisioned — on-demand is easy but expensive at scale; provisioned (with autoscaling) is the production default.
- Lambda invocations + duration + memory. Memory ties to CPU; over-provisioning memory often reduces cost because the function finishes faster.
- CloudWatch Logs ingestion is its own line item; high-cardinality logging can cost more than the compute that produced it.
The senior practice: turn on Cost Explorer, set budgets with alerts, and review monthly. AWS gives you good tools; you have to use them.
Observability on AWS
CloudWatch is the umbrella:
- CloudWatch Logs — structured logs (JSON works well). Query via Logs Insights (a SQL-ish language).
- CloudWatch Metrics — custom and standard metrics; alarms.
- X-Ray — distributed tracing. Integrates with the .NET SDK and supports OpenTelemetry.
- CloudWatch Application Signals — newer; aggregates traces/metrics/logs for a service like Application Insights does.
For .NET, OpenTelemetry is the modern path — instrument once, export to X-Ray, CloudWatch, or any OTLP-compatible backend. See OpenTelemetry — traces, metrics, logs.
Aurora vs RDS
Two managed relational options:
- RDS — managed instance of SQL Server, PostgreSQL, MySQL, MariaDB, Oracle. AWS handles backups, patching, failover. SQL Server license cost passes through.
- Aurora — AWS-built MySQL- or PostgreSQL-compatible engine. Storage layer is decoupled across 6 replicas across 3 AZs; failover is seconds; read replicas are cheap; serverless tier scales to zero.
For new .NET workloads on AWS, Aurora PostgreSQL is typically the right call (cheaper, faster, more elastic than RDS Postgres). SQL Server stays on RDS if you need T-SQL compatibility; Aurora has no SQL Server equivalent.
EF Core works fine against both via the Npgsql.EntityFrameworkCore.PostgreSQL provider.
Cognito for end-user identity
Cognito is AWS's customer identity service — sign-up, sign-in, social login, MFA, hosted UI, federation. It's serviceable but not loved; teams often pair AWS workloads with Auth0 or Keycloak instead. See Identity Providers Comparison.
What .NET teams should not do on AWS
- Don't use Elastic Beanstalk for new workloads. It's still maintained but is the most "legacy" of AWS's deployment shapes. App Runner or ECS/Fargate are the modern choices.
- Don't run EC2 instances directly without a strong reason. Fargate (serverless containers) or Lambda cover the majority of compute needs and remove the VM-patching tax.
- Don't roll your own auth. Use Cognito, or Keycloak/Auth0 in front of API Gateway.
- Don't skip multi-AZ in production. Single-AZ is a SPOF.
- Don't store secrets in environment variables of CloudFormation. Use Secrets Manager; reference dynamically.
How it works under the hood
This file is a breadth overview, not a deep-dive into any single service's runtime mechanics. The "how it works" for each individual service deserves its own file in a future AWS-deep wave; for now, the AWS docs at docs.aws.amazon.com are the authoritative source. Pair this overview with the AWS-side reading list below.
Code: correct vs wrong
❌ Wrong: long-lived IAM access keys in app config
The credentials live in your code, your git history, and probably your logs. Rotation requires a deploy. Compromise is permanent.
✅ Correct: IAM role on the workload
// On Lambda, ECS task, EC2 instance — credentials come from the role attached to the workload:
var s3 = new AmazonS3Client(); // SDK discovers the role automatically
No keys to manage; rotation is automatic; revocation is a single IAM update. The .NET SDK uses the credential provider chain (env vars → shared profile → IAM role) so the same code works locally and in production.
❌ Wrong: in-process Lambda handler with synchronous-blocking DB calls
public APIGatewayProxyResponse Get(APIGatewayProxyRequest req, ILambdaContext ctx)
{
var order = _ddb.GetItem(...).Result; // ← .Result on async; blocks the Lambda thread
return new APIGatewayProxyResponse { /* ... */ };
}
You pay for wall-clock execution; blocking the thread wastes it. .NET deadlocks (single-threaded SynchronizationContext) can also bite.
✅ Correct: async all the way
public async Task<APIGatewayProxyResponse> Get(APIGatewayProxyRequest req, ILambdaContext ctx)
{
var order = await _ddb.GetItemAsync(...);
return new APIGatewayProxyResponse { /* ... */ };
}
❌ Wrong: scanning DynamoDB tables in production
var scan = await _ddb.ScanAsync(new ScanRequest("orders")); // reads every item
foreach (var item in scan.Items) { /* filter in code */ }
Scan reads the entire table and bills you for it. At 10M items, that's a budget event and a slow request.
✅ Correct: query by partition key
var query = await _ddb.QueryAsync(new QueryRequest
{
TableName = "orders",
KeyConditionExpression = "pk = :pk",
ExpressionAttributeValues = new() { [":pk"] = new AttributeValue($"CUSTOMER#{customerId}") }
});
If you can't query, you're missing an index (GSI) — design access patterns up front.
❌ Wrong: NAT Gateway for every private subnet's outbound traffic, no thought to volume
A chatty service that pulls 1 TB/month through NAT pays ~$45/month for the gateway and ~$45 for the egress alone — and the egress out to the public S3 endpoint is avoidable.
✅ Correct: VPC endpoints for AWS services
Private subnet ──► VPC endpoint ──► S3 (no NAT, no egress charge)
──► DynamoDB
──► Secrets Manager
...
VPC endpoints route AWS-service traffic privately without leaving the VPC's networking. Free for Gateway endpoints (S3, DynamoDB); cheap for Interface endpoints. The single biggest "we didn't know" cost saver for AWS-newcomers.
Design patterns for this topic
Pattern 1 — "Lambda + API Gateway for APIs; SNS+SQS for events"
- Intent: the AWS default architecture for new .NET microservices.
Pattern 2 — "IAM roles, not access keys"
- Intent: workloads authenticate via attached roles; rotation is automatic.
Pattern 3 — "DynamoDB single-table design with carefully-chosen partition keys"
- Intent: model access patterns up front; avoid scans.
Pattern 4 — "EventBridge for SaaS and pattern-based routing; SNS for simple high-volume fan-out"
- Intent: pick the bus that matches the use case.
Pattern 5 — "Multi-account organization"
- Intent: isolate dev/staging/prod and per-team in separate accounts; cross-account roles bridge.
Pattern 6 — "VPC endpoints for AWS service traffic"
- Intent: avoid NAT egress charges; keep traffic private.
Pattern 7 — "CDK in C# for IaC"
- Intent: keep IaC in the language the team already uses, with full type-checking and IDE support.
Pros & cons / trade-offs
| Aspect | AWS | Azure |
|---|---|---|
| Service breadth | Larger catalog | Slightly narrower; deep where it matters for MS shops |
| .NET first-class? | Yes — fully supported but not the home stack | Yes — the home stack |
| IaC | CloudFormation (verbose), CDK, Terraform | Bicep (clean), Terraform |
| IAM granularity | Very fine | Coarser, simpler |
| Pricing transparency | Complex; many line items | Comparable; Azure Cost Management is decent |
| Identity for end-users | Cognito (functional) | Entra External ID (richer) |
| Multi-account / multi-subscription | Multi-account is the norm; tooling is mature | Multi-subscription works; less common |
| Region count | More regions globally | Comparable; differs by service |
When to use / when to avoid
- Use AWS when an existing AWS account, customer requirement, or cost analysis points there.
- Use AWS when the catalogue advantage matters (specific ML services, specialized hardware, deeper SaaS partner ecosystem).
- Avoid AWS as a second cloud "just in case" — multi-cloud doubles IaC, IAM, observability, and team learning load.
- Avoid mixing AWS Lambda with Azure Functions in one product without an architectural reason; pick one event-driven platform.
- Avoid CloudFormation as your first IaC choice — prefer Terraform or CDK.
Interview Q&A
Q1. What's the closest AWS service to Azure App Service? For .NET web apps, App Runner (newer, simpler) or Elastic Beanstalk (legacy, more configurable). For container-based apps, ECS on Fargate. For Kubernetes, EKS.
Q2. How does Lambda compare to Azure Functions? Same idea — event-driven serverless. Lambda has a hard 15-minute timeout (Functions Premium goes longer); Lambda's cold-start story is similar to Azure isolated-worker Functions and improves dramatically with native AOT. Programming models differ in detail; the mental shape is the same.
Q3. What's the AWS equivalent of Service Bus topics? SNS + SQS together. SNS is the topic; each subscriber is typically an SQS queue (for durability per consumer), a Lambda, or an HTTP endpoint.
Q4. When use Kinesis vs SQS? Kinesis = ordered, partitioned, replayable stream (Event Hubs equivalent). SQS = unordered or per-group ordered (FIFO) queue with drop-on-ack semantics. Use Kinesis when consumers need to replay or rewind; SQS for fire-and-forget work distribution.
Q5. How does .NET workload authenticate to AWS services in production? Via IAM roles attached to the workload (Lambda execution role, ECS task role, EC2 instance profile). The .NET SDK discovers credentials from the role automatically. No access keys in code or config.
Q6. What's an IAM policy? A JSON document granting (or denying) actions on resources. Policies attach to identities (users, roles, groups) or resources (buckets, queues). Explicit Deny wins over Allow.
Q7. Single-table design in DynamoDB? A modeling approach where multiple entity types share one table, using a generic partition-key + sort-key shape to support many access patterns from one table — fewer cross-table lookups, lower cost. Requires planning access patterns up front; doesn't suit ad-hoc query needs.
Q8. What does multi-AZ mean and why does it matter? An AWS region is divided into Availability Zones — independent failure domains. Deploying across two or more AZs survives a single-AZ outage. Single-AZ in production is a single point of failure.
Q9. What's the IaC choice for a .NET team on AWS? For a team that wants type-safety and the .NET language, AWS CDK in C# (compiles to CloudFormation). For a team that wants multi-cloud, Terraform. CloudFormation alone is rarely the first choice — verbose, slow, less ergonomic than the alternatives.
Q10. How do you do "managed identity" on AWS? IAM roles. A Lambda has an execution role; an ECS task has a task role; an EC2 instance has an instance profile. The .NET SDK reads credentials from the role automatically. Same pattern as Azure Managed Identity; different vocabulary.
Q11. What's the biggest unexpected AWS cost driver? NAT Gateway egress + cross-AZ data transfer. The fix: VPC endpoints (gateway endpoints for S3 and DynamoDB are free; interface endpoints are cheap) and careful placement of chatty services in the same AZ.
Q12. How would you migrate an Azure Functions app to Lambda? Map triggers (HTTP → API Gateway; Service Bus → SQS/SNS; Cosmos Trigger → DynamoDB Streams; Blob Trigger → S3 Event); replace bindings with explicit SDK calls in code; switch from Microsoft.Identity.Web to IAM-role-based auth; rebuild for dotnet8 Lambda runtime; redeploy via SAM or CDK. The business logic mostly stays the same.
Gotchas / common mistakes
- ⚠️ Long-lived access keys in code or config — use IAM roles. Rotate any access keys that exist.
- ⚠️
"Resource": "*"in IAM policies — convenient during dev, dangerous in prod. Tighten before production deploy. - ⚠️ DynamoDB Scan in hot paths — reads the whole table; bills you for every byte. Design indexes.
- ⚠️ Lambda blocking on
.Result/.Wait()— wastes wall-clock billing time; risks deadlocks. - ⚠️ NAT Gateway for S3/DynamoDB traffic — use VPC endpoints; saves real money.
- ⚠️ Single-AZ deployments in production — single point of failure; multi-AZ is the floor.
- ⚠️ Putting end-users in the same account as production infra — separate accounts via Organizations; cross-account roles.
- ⚠️ CloudFormation for everything new — Terraform or CDK have better DX; CFN is the last resort.
- ⚠️ Mixing AWS and Azure pub/sub in one architecture — the cost is conceptual (two mental models, two failure modes); pick one.
- ⚠️ No budget alerts — AWS will not tell you ahead of time that you're burning $10k on egress; set Cost Explorer alarms.
Further reading
- AWS SDK for .NET (docs)
- AWS Lambda — .NET on Lambda
- Lambda Annotations Framework (GitHub)
- AWS CDK for C# (docs)
- DynamoDB Best Practices (whitepaper)
- The AWS Well-Architected Framework
- VPC endpoint pricing and patterns
- Identity Providers Comparison — Cognito's place among IAM choices
- NoSQL & event stores — DynamoDB vs Cosmos vs others