Table of Contents
AWS is Just Someone Else’s Data Center (With a Very Expensive API)
I once spent thirty-six hours straight in a “War Room” because of a single checkbox in the AWS Console. We were migrating a high-throughput payment processing engine from a colo facility in Virginia to us-east-1. I was the lead SRE, and I thought I had accounted for everything. I didn’t. I had enabled “Multi-AZ” for our RDS Aurora cluster without fully grasping how the synchronous replication would interact with our application’s specific write-heavy workload and the latency overhead of the cross-AZ chatter. By 2:00 AM, the application’s connection pool was saturated, the database was choking on IO:Wait, and our Stripe integration was throwing 504s like it was a sport. I had to manually failover the primary node while my hands were shaking from too much caffeine and not enough sleep.
The worst part? The bill. Because I hadn’t properly configured the VPC Endpoints, every single gigabyte of data traveling between our application servers and S3 was being routed over the public internet and back through a NAT Gateway. We burned $14,000 in data transfer fees in three days. That was my “Welcome to AWS” moment. It wasn’t about “elasticity” or “innovation.” It was about a complex, interconnected web of proprietary APIs that charge you for every breath you take. If you want to know what is AWS, don’t look at the marketing slides. Look at the billing console and the ServiceQuotas page. That’s where the truth lives.
The Marketing Lie vs. The Infrastructure Reality
If you ask a solution architect “what is” AWS, they’ll give you some fluff about “cloud computing” and “on-demand resources.” That’s a sanitized version of the truth. In reality, AWS is a massive collection of managed services built on top of a highly customized version of the Xen (and now KVM/Nitro) hypervisor. It is a way to rent hardware at a massive markup in exchange for the ability to provision that hardware via a POST request.
Most people treat AWS like a magic black box. It isn’t. When you launch an EC2 instance, you are literally just asking a control plane to find a slice of a physical rack in a warehouse in places like Ashburn, Dublin, or Tokyo, and carve out some CPU cycles and RAM for you. The “magic” is the orchestration layer. But that orchestration layer is leaky. You will hit “noisy neighbor” issues. You will experience “Stale NFS file handles.” You will see Internal Server Error (500) from the AWS API itself when you try to spin up too many resources at once. This is the “what is” that no one tells you: AWS is a massive distributed system, and like all distributed systems, it is constantly failing in small, subtle ways.
Pro-tip: Never trust the “Service Health Dashboard.” By the time that little icon turns yellow, your infrastructure has likely been on fire for forty-five minutes. Use Twitter (X) or specialized status aggregators to see what’s actually happening in
us-east-1.
EC2: The Foundation of the Money Pit
Elastic Compute Cloud (EC2) is the core. Everything else—Lambda, RDS, Fargate—is eventually just EC2 with a different coat of paint and a higher price tag. When you’re trying to understand what is AWS, you start here. But don’t get distracted by the 400+ instance types. You only need to care about a few.
- The T-Series (Burstable): These are traps for the unwary. They use “CPU Credits.” If your app stays idle, you’re fine. If you get a spike in traffic, you burn credits. Once you hit zero, AWS throttles your CPU to a crawl. I’ve seen production APIs die because someone used a
t3.mediumfor a background worker that suddenly had a backlog to process. - The M and C Series: These are your workhorses.
m5.large,c6i.xlarge. They provide predictable performance. If you are running a production database or a high-traffic web server, stay here. - The Nitro System: This is the only “modern” part of EC2 worth geeking out over. AWS built custom hardware to offload networking and storage I/O. It means you get almost 100% of the instance’s resources for your code.
Let’s look at a typical “fuck-up” in EC2 provisioning. Most people use the console. Don’t. Use Terraform or Pulumi. If you’re doing it manually, you’ll forget to enable “EBS Optimization” or you’ll pick the wrong AMI (Amazon Machine Image). Here is what a basic, sane EC2 definition looks like in HCL (Terraform):
resource "aws_instance" "api_server" {
ami = "ami-0c55b159cbfafe1f0" # Ubuntu 22.04 LTS
instance_type = "m5.large"
root_block_device {
volume_size = 50
volume_type = "gp3" # Never use gp2. gp3 is cheaper and faster.
iops = 3000
throughput = 125
}
vpc_security_group_ids = [aws_security_group.api_sg.id]
tags = {
Name = "production-api-01"
Environment = "prod"
}
}
Note the gp3 volume type. AWS still defaults many things to gp2. gp2 ties your IOPS (Input/Output Operations Per Second) to the size of the disk. If you have a small 10GB disk, your performance is garbage. gp3 decouples them. It’s a small detail, but it’s the difference between a snappy API and one that hangs every time you write a log file.
S3: The Only Service That Actually Works (Mostly)
Simple Storage Service (S3) is the crown jewel. It is the only service I actually enjoy using. It claims 99.999999999% (eleven nines) of durability. In ten years, I have never lost a file in S3. But I have accidentally made files public, and I have definitely been billed for millions of LIST requests that I didn’t know were happening.
What is AWS S3? It’s an object store. It is not a file system. Do not try to mount it as a drive using FUSE unless you want to experience pain. It’s meant for blobs of data. The biggest “gotcha” here is the consistency model. For years, S3 was “eventually consistent” for overwrites. If you updated config.json and immediately read it back, you might get the old version. They fixed this in 2020 to be “strongly consistent,” but the trauma remains for us old-timers.
The real danger in S3 is permissions. The IAM (Identity and Access Management) policies for S3 are a nightmare. You have Bucket Policies, IAM Policies, and (god forbid) Access Control Lists (ACLs). If you want to stay sane, disable ACLs entirely. Here is a policy that won’t get you fired:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-secure-data-bucket/uploads/*"
},
{
"Effect": "Deny",
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-secure-data-bucket/*",
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
That second block is crucial. It denies any request that isn’t over HTTPS (TLS). If you’re handling sensitive data, this should be your baseline. Most people forget it.
IAM: The Thing That Will Break Your Spirit
If you ask me “what is” the hardest part of AWS, it’s not the networking or the scale. It’s IAM. IAM is the security layer that governs who can do what. It is incredibly powerful and equally frustrating. In AWS, everything is denied by default. You have to explicitly allow every single action.
The “Senior SRE” way to handle IAM is the Principle of Least Privilege. But in the real world, developers get frustrated because they can’t upload a file to S3, so they just attach the AdministratorAccess policy to their user. Do not do this. Once a credential with admin access is leaked (and it will be, probably in a public GitHub repo), your account belongs to a crypto-miner in five minutes.
Use Roles, not Users. If your application is running on EC2, use an Instance Profile. If it’s on EKS (Kubernetes), use IRSA (IAM Roles for Service Accounts). Never, ever hardcode an AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY into a .env file. I’ve seen a company lose $60k in a weekend because an engineer pushed a .env file to a public repo. The bots found it in seconds.
Note to self: Periodically run
aws iam generate-credential-reportand delete any access keys older than 90 days. No exceptions.
Networking: The Hidden Tax
This is where AWS makes its real money. Networking in AWS is a labyrinth of VPCs (Virtual Private Clouds), Subnets, Route Tables, and Gateways. The most important thing to understand about AWS networking is that data transfer is not free.
If you have two servers in the same Availability Zone (AZ) talking to each other via their private IP addresses, it’s free. If they are in different AZs, you pay $0.01 per GB in both directions. That sounds small. It isn’t. If you have a high-traffic microservices architecture where every request hops across three services, your “Cross-AZ Data Transfer” bill will eventually rival your compute bill.
Then there’s the NAT Gateway. A NAT Gateway allows instances in a private subnet to reach the internet. AWS charges you $0.045 per hour just for the privilege of having the gateway exist, and then another $0.045 per GB of data processed. If you are downloading large Docker images or backing up data to an external provider, this will destroy your budget. The solution? VPC Endpoints. They allow you to talk to AWS services (like S3 or DynamoDB) without going through the NAT Gateway. It’s more complex to set up, but it’s the “Senior” way to build.
# Example: Creating a VPC Endpoint for S3 to save thousands on NAT fees
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]
}
If you don’t have that block in your Terraform code, you’re literally throwing money into a furnace.
The Managed Service Trap (RDS, ElastiCache, and more)
AWS loves to sell you “Managed Services.” The pitch is: “We handle the backups and patching, you write the code.” It’s a compelling lie. While it’s true that RDS (Relational Database Service) is easier than managing Postgres on a raw Linux box, you are still the DBA. You still have to tune max_connections. You still have to deal with vacuuming issues. You still have to monitor FreeStorageSpace.
I prefer RDS over self-hosting because I value my sleep, but I recognize the trade-off. You lose access to the underlying OS. You can’t just ssh in and run htop to see what’s eating the CPU. You are at the mercy of the AWS CloudWatch metrics, which are often delayed or insufficiently granular. If you’re running a high-performance Redis cluster, ElastiCache is great until you hit a “Read-only” error because the primary node failed over and your client library didn’t handle the DNS change fast enough.
What is AWS RDS really? It’s a wrapper around a database engine that automates the boring stuff but hides the critical stuff. If you use it, make sure you enable “Performance Insights.” It’s one of the few AWS tools that is actually worth the extra cost. It gives you a breakdown of which SQL queries are causing the most load.
The “What Is” of Serverless: Lambda
Lambda is the ultimate expression of AWS. You give them a ZIP file of code, and they run it. No servers to manage. It sounds like heaven. In reality, it’s a world of “Cold Starts” and “Concurrency Limits.”
If your Lambda function hasn’t been run in a while, the first request will take 2-5 seconds to start because AWS has to spin up a micro-VM (Firecracker) for you. If you’re writing a Java or .NET app, this is a dealbreaker. If you’re using Go or Node.js, it’s manageable. But then there’s the “Shared Fate” problem. If your Lambda talks to a database like Postgres, and you suddenly get 1,000 concurrent requests, Lambda will happily spin up 1,000 instances. Your Postgres database, however, will not happily accept 1,000 new connections. It will die. Immediately.
This is why tools like RDS Proxy exist. It’s another service you have to pay for to solve a problem created by the first service you paid for. This is the AWS ecosystem in a nutshell.
The Real World: A “Gotcha” for the Uninitiated
Here is something they don’t put in the “What is AWS” intro guides: The Default Quotas.
You start a new project. You’ve got your Terraform ready. You run terraform apply. Everything looks good until—VcpuLimitExceeded. AWS limits new accounts to a very small number of vCPUs. You have to open a support ticket to ask for more. And if you’re in a hurry? Too bad. It can take 24-48 hours for a human to review and approve your request. I’ve seen entire product launches delayed because someone forgot to check the service quotas for Elastic IPs or Load Balancers in a new region.
Also, let’s talk about us-east-1. It is the oldest, largest, and most unstable region. When AWS has a global outage, it almost always starts in North Virginia. If you are building something that must stay up, build in us-west-2 (Oregon) or eu-central-1 (Frankfurt). They are newer, cleaner, and generally more reliable. But everyone stays in us-east-1 because that’s where all the new features land first. It’s a technical debt trap.
The Bill is the Architecture
In the old days, we designed for performance. In AWS, we design for the bill. If you see an architecture diagram with a NAT Gateway, a Managed NAT, three different Load Balancers, and a Cross-Region Peering connection, you aren’t looking at a “robust system.” You’re looking at a $50,000-a-month invoice.
A senior SRE knows that “What is AWS” is actually a question of economics. Can we replace this Kinesis stream with a simple SQS queue? Do we really need a Multi-AZ RDS for our staging environment? Why are we using CloudFront for internal assets? Every architectural decision is a financial decision. If you don’t understand the pricing page for a service, you don’t understand the service.
The Technical Walkthrough: Deploying a Sane Web Stack
To truly understand what is AWS, you need to see how the pieces fit together. Let’s look at a “standard” stack: An Application Load Balancer (ALB), an Auto Scaling Group (ASG) of EC2 instances, and an RDS database. This is the bread and butter of AWS.
1. The VPC: You need a /16 CIDR block. Don’t use 10.0.0.0/16 because every other company on earth uses it, and if you ever need to peer your VPC with a partner or another internal project, your IP ranges will clash. Use something weird like 10.154.0.0/16.
2. The Subnets: You need at least two Public subnets (for the ALB) and two Private subnets (for the EC2 instances and RDS). Why two? Because AWS regions are divided into Availability Zones (AZs). If one data center loses power, you want your app to stay up in the other one.
3. The Security Groups: These are stateful firewalls. Your ALB should allow port 80/443 from 0.0.0.0/0. Your EC2 instances should only allow traffic from the ALB’s security group. Your RDS should only allow traffic from the EC2 security group. This is “Defense in Depth.”
# Security Group for the Database - Only allows the API to talk to it
resource "aws_security_group" "db_sg" {
name = "database-sg"
vpc_id = aws_vpc.main.id
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.api_sg.id] # The "Magic" link
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
4. The Load Balancer: The ALB is smart. It can do path-based routing. It can handle SSL termination (using AWS Certificate Manager, which is actually a great, free service). But it’s expensive. You pay for “Load Balancer Capacity Units” (LCUs). If you have millions of tiny requests, the LCU cost will bite you.
The “Done with the Hype” Take on Kubernetes (EKS)
Eventually, someone will tell you that you need Kubernetes. They’ll point you to EKS (Elastic Kubernetes Service). Here is the truth: EKS is a managed control plane. You still have to manage the worker nodes. You still have to manage the CNI (Container Network Interface) plugin. You still have to deal with the fact that AWS’s version of Kubernetes is always six months behind the community version.
EKS is great if you have 50+ microservices. If you have two APIs and a cron job, EKS is a massive waste of time and money. You’ll spend more time debugging aws-auth ConfigMaps than you will writing code. For 90% of companies, a simple Auto Scaling Group with some Docker containers running on it is more than enough. Don’t let the hype-cycle dictate your architecture.
Summary of the “What is” AWS Reality
- EC2: It’s a VM. Watch your CPU credits and use
gp3. - S3: It’s a blob store. Turn off ACLs and use VPC Endpoints.
- IAM: It’s the gatekeeper. Use Roles, not Users. Never use
AdministratorAccessfor an app. - VPC: It’s the network. Data transfer is the hidden killer of budgets.
- RDS: It’s a managed DB. You’re still the DBA, you just don’t have to patch the OS.
AWS is a toolset, not a solution. It provides the raw materials to build something incredible, but it also provides plenty of rope to hang yourself with. The difference between a Junior and a Senior SRE is that the Senior knows which services to avoid. We know that “Serverless” isn’t serverless, “The Cloud” is just a warehouse in Virginia, and the most important metric isn’t CPU usage—it’s the cost per request.
Stop reading the whitepapers. Start reading the pricing pages. If you can’t explain how a service makes AWS money, you don’t understand how that service works. Now, go check your NAT Gateway usage before you go broke.
Related Articles
Explore more insights and best practices: