OTP service and WAF hardening on AWS
Built a new one-time passcode service on AWS end to end, from Terraform to CI/CD, and hardened the WAF of a high-traffic consumer platform without blocking real users.
- AWS
- Terraform
- Lambda
- ElastiCache Redis
- API Gateway
- WAF
- Kafka
- GitHub Actions
- Python
- environments
- 3
- environments
- requests an hour behind the WAF
- ~900k
- requests an hour behind the WAF
- fraud signal types
- 11
- fraud signal types
- stored AWS keys in CI
- 0
- stored AWS keys in CI
Infrastructure as code
- Full Terraform stack for a new OTP service (create, verify and resend) across integration, UAT and production: container-based Lambda on arm64, ElastiCache Redis with TLS and auth (Multi-AZ in UAT), Secrets Manager, security groups, CloudWatch, and optional NAT egress switched on per environment. Existing VPCs were reused rather than duplicated.
- Internal load balancer routing in the shared infrastructure repo: Lambda target groups, host-based listener rules and private Route 53 records, with isolated state per environment so nothing else is touched.
- Moved the service from per-account ECR repos to a shared, cross-account registry, including cross-account pull permissions for Lambda and a cutover with no downtime.
- Brought hand-made WAF web ACLs into Terraform by importing them, then added new rules as code.
- Found that an old integration VPC was effectively dead and moved the workload to the live one.
Serverless
- OTP Lambda shipped as a container image, with one handler that accepts both REST and HTTP API event formats.
- Fixed Lambda rejecting multi-arch image manifests, and added smoke tests on every deploy.
- Moved the API off the public internet to a private API Gateway endpoint, locked down with a resource policy.
- Integrated with a managed Kafka cluster over VPC peering or NAT egress, depending on the environment.
- WAF on Amplify-hosted frontends (CloudFront scope) for several web apps.
CI/CD
- GitHub Actions pipeline that builds the image, pushes it to the central ECR, deploys and runs a smoke test.
- Keyless pipeline auth through GitHub OIDC roles, with no stored AWS keys.
- Feature work shipped as code, such as test-account bypass lists for the OTP service.
DevSecOps
- Rate limiting on login, activation and account recovery pages, run in count mode first and then tuned.
- AWS managed rule sets for IP reputation, common exploits and known bad inputs, Bot Control on the most-abused login endpoint, and Account Takeover Protection on a separate portal's login.
- Admin access restricted to the corporate VPN with host-header and query-string WAF rules.
- Audited the live WAF against the code and found unmanaged console changes and rules missing from code.
- Every production change done safely: backups and reviewed dry-run diffs before each apply, lock-token and expected-state checks so nobody's console edits get overwritten, and before/after traffic comparisons to confirm no legitimate users were blocked.
- Found and fixed a case-sensitivity mismatch that meant a fraud rule had never matched half its URLs, and rules sharing a CloudWatch metric name that made their numbers impossible to tell apart.
- Kept UAT in step with production so WAF changes are tested before they ship.
- Reviewed findings from an external security assessment, separating real gaps from ones already covered by a layer the assessors couldn't see.
Fraud detection and observability
- Python tool that pulls 11 fraud signal types from application and WAF logs, including credential-stuffing patterns, suspicious IPs, activation velocity, card verification failures and device fingerprint spread.
- Showed that the 10k-row cap in CloudWatch Logs Insights meant some queries could miss results, and proposed fixes: pagination, tighter filters and input from the data and fraud teams.
- WAF logging, alarms and dashboards, including log-based dashboards where metrics weren't available.
Cost
- Moved Bot Control to the end of the rule order and scoped it to specific endpoints, so the paid inspection runs on less traffic.
- Flagged WAF log volume (about 2.8 TB stored) as a cost item, and weighed query cost and time in the fraud tooling.
Documentation
- DevOps handover doc for the OTP service: environments, image and ECR, deploys, Terraform, routing, logs and access.
- Evidence and change write-ups for every production change: before/after configs, test results and rollback steps.