A serverless design, end to end
API Gateway, Python Lambdas and a Cognito User Pool - provisioned entirely with Terraform. Here's exactly what gets deployed, what it costs, and the decisions behind it.
Architecture Overview
Request flow
Store-nothingObservability via CloudWatch logs + lambda warmers · least-privilege IAM role per function · 100% provisioned with Terraform (remote state in S3, locked with DynamoDB).
Deployed Resources
| Qty | Resource | Purpose |
|---|---|---|
| 1 | API Gateway (REST) | Exposes the 23 HTTP endpoints with CORS. A Cognito JWT authorizer gates only GET /v1/userinfo and DELETE /v1/users/{id}; the rest are open (add WAF/throttling + broader authorizers for production) |
| 1 | Cognito User Pool | Holds all users, enforces MFA, and issues JWTs |
| 1 | Cognito Identity Pool | Optional exchange of JWTs for scoped AWS credentials |
| 27 | Lambda Functions | Endpoint handlers (including 6 passkey handlers) plus 3 custom-auth triggers and the custom-message trigger |
| 2 | Lambda Layers | Shared dependencies (jsonschema, PyJWT) |
| 27 | CloudWatch Log Groups | Per-function logs, plus scheduled lambda warmers |
| 1 | ACM Certificate | TLS for the API custom domain |
| 2 | Route53 Records | ACM validation + API custom domain |
| 1 | S3 Bucket | Encrypted, versioned Terraform remote state |
| 1 | DynamoDB Table | Terraform state lock for safe collaboration |
Cost Estimation
Estimations based on the following parameters:
- Deployment region: eu-west-1
- User base: 50,000 active users
- Authentication pattern: 26 requests per user per day
- Lambda configuration: 256MB memory, ~1s duration per call
| Service | Monthly Cost | Notes |
|---|---|---|
| API Gateway | $35 | 1.3M requests daily |
| Lambda | $65 | 1.3M invocations daily |
| Cognito | $30 | 50K MAU |
| Other Services | $20 | S3, DynamoDB, Route53 |
| TOTAL | ~$150 | $0.003 per user/month |
Implementation Notes
Security First & store-nothing
TOTP MFA is mandatory and set up at enrollment. The secret is shown to the user exactly once and never persisted server-side - recovery is a custom-auth flow (emailed code + password), not a stored secret.
Terraform-Based
The main IAC tool choice was based on popularity and simplicity. Terraform has been reliable since its early releases.
Token Lifecycle
Access and ID tokens are valid for 1 hour; refresh tokens for 24 hours. Token revocation is enabled, and all values are customizable via variables.
Multi-Environment
The solution uses a Makefile to handle multi-environment deployments. Create configuration files in environments/MyEnvName/terraform.tfvars.MyEnvName.
Password Policy
14 characters minimum length with at least 1 number, 1 special character, 1 uppercase letter and 1 lowercase letter.
Recommendations
- •Use AWS WAF in production to protect your API against illegitimate traffic
- •Throttle the public endpoints with API Gateway per-method rate + burst limits to bound Lambda invocations (financial-DDoS defense)
- •There is no API key: authorize user endpoints with the Cognito JWT, and admin actions (user create/delete) with a machine-to-machine token kept in your backend