You open your todo list · Lambda + RDS MySQL
9 steps from your browser to the database and back.
No background job: reading doesn't change any todos. Try Create, Update or Delete.
Text version of this diagram.
What sits where:
- AWS Region · us-east-1: A Region is a part of the world where AWS has data centers. Most things you build live in one Region. us-east-1 is in northern Virginia. contains:
- VPC: Virtual private cloud: your own private network inside AWS. Nothing gets in or out except the ways you allow. contains:
- Private subnet · no internet: A slice of the VPC with no route to the internet at all. Nothing here can be reached from outside. contains:
- ENI (function's network card): Elastic network interface: a virtual network card. It gives the function an address inside your VPC.
- RDS MySQL (database: todoio): A MySQL database that AWS runs for you, including the server, patches and backups. todoio is the database's name.
- Private subnet · no internet: A slice of the VPC with no route to the internet at all. Nothing here can be reached from outside. contains:
- API Gateway (HTTP API · front door): The front door for the app's web requests: it receives each one and hands it to your code. An HTTP API is its simple kind for ordinary requests.
- CloudWatch Logs (app log lines): Collects the lines your app writes about what it's doing (its logs), so you can search them later.
- Lambda function (runs once per request): Code that AWS runs only when a request arrives. No server to look after, and you pay per request.
- VPC: Virtual private cloud: your own private network inside AWS. Nothing gets in or out except the ways you allow. contains:
- Your browser (on the internet)
Steps, in order:
- You open your todo list. Path: Your browser. Your browser sends GET /todos over HTTPS.
- Into the front door. Path: Your browser → API Gateway. The request arrives at API Gateway, a managed HTTPS front door. There's no server or firewall for you to look after.
- Wake up the function. Path: API Gateway → Lambda function. API Gateway invokes your Lambda function and hands it the request as an event. Checks: iam: Lambda resource policy: API Gateway may invoke todo-api → allow.
- Who are you?. Path: Lambda function. The app checks your signed session cookie and finds your user id, u-123. This is the app's own login, not AWS.
- Step into the VPC. Path: Lambda function → ENI. The database lives in a private subnet of a VPC, so the function is attached to that VPC. AWS gives it an ENI (a network card) in the private subnet.
- Ask the database. Path: ENI → RDS MySQL. The app sends SQL to RDS MySQL in the private subnet on port 3306. It logs in with a database username and password, not with IAM. Checks: security-group: todo-db-sg: TCP 3306 from todo-lambda-sg → allow; mysql: MySQL user todo_app: SELECT on todoio.todos → allow.
- The database answers. Path: RDS MySQL → ENI → Lambda function. MySQL returns your 3 todos.
- Back to you. Path: Lambda function → API Gateway → Your browser. You get 200 OK with your todos, and the list appears.
- Leave a note. Path: Lambda function → CloudWatch Logs. Lambda sends what the function printed to CloudWatch Logs, so Todo.io's engineers can see what happened.
Your browser sends
GET /todosover HTTPS.Show me the real thing
The HTTP request
GET /todos HTTP/1.1 Host: abc123.execute-api.us-east-1.amazonaws.com Cookie: session=eyJ1c2VySWQiOiJ1LTEyMyJ9.Zm9vThe request arrives at API Gateway, a managed HTTPS front door. There's no server or firewall for you to look after.
API Gateway invokes your Lambda function and hands it the request as an event.
- 🔑IAM Lambda resource policy: API Gateway may invoke todo-apiAllowed
Show me the real thing
Resource-based policy on the function: who may call it
{ "Effect": "Allow", "Principal": { "Service": "apigateway.amazonaws.com" }, "Action": "lambda:InvokeFunction", "Resource": "arn:aws:lambda:us-east-1:111122223333:function:todo-api", "Condition": { "ArnLike": { "AWS:SourceArn": "arn:aws:execute-api:us-east-1:111122223333:abc123/*" } } }Exam tipThis is a resource-based policy. It lives on the function and says who may call it, the opposite of a policy attached to a role.
The app checks your signed session cookie and finds your user id,
u-123. This is the app's own login, not AWS.The database lives in a private subnet of a VPC, so the function is attached to that VPC. AWS gives it an ENI (a network card) in the private subnet.
Exam tipA Lambda ENI never gets a public IP, so a VPC-attached function can't reach the internet, even from a public subnet. It needs a NAT gateway. Classic exam trap.
The app sends SQL to RDS MySQL in the private subnet on port 3306. It logs in with a database username and password, not with IAM.
- 🛡Security group todo-db-sg: TCP 3306 from todo-lambda-sgAllowed
- 🗄MySQL MySQL user todo_app: SELECT on todoio.todosAllowed
Show me the real thing
The SQL (real code sends the values as parameters, never pasted into the string)
SELECT id, title, done FROM todos WHERE user_id = 'u-123' ORDER BY created_at;Exam tipA security group rule can use another security group as its source: "anything wearing todo-lambda-sg may connect". Exam favourite.
MySQL returns your 3 todos.
You get
200 OKwith your todos, and the list appears.Show me the real thing
The HTTP response
HTTP/1.1 200 OKLambda sends what the function printed to CloudWatch Logs, so Todo.io's engineers can see what happened.
Show me the real thing
The log line
2026-10-11T18:42:07Z INFO GET /todos user=u-123 status=200 14msExam tipLambda sends whatever your function prints to CloudWatch Logs automatically, as long as the execution role allows logs:PutLogEvents.
What to notice
- There is no server at all. API Gateway takes the request and Lambda runs your code only when one arrives.
- IAM never checked your SQL. MySQL has its own users; IAM only manages the database server itself.
- The database sits in a private subnet with no route to the internet. Only the security groups you allowed can reach it.
- The database password lives in the app config here. In production it belongs in Secrets Manager (Level 1).
- To reach a database in a VPC, the function had to be attached to that VPC.
- Every Lambda copy opens its own MySQL connection, and a traffic spike can exhaust them. RDS Proxy pools connections (Level 2).
- You, the customer, were never an IAM user. IAM controls the app, not its customers.