The subnets are laid out correctly, but the security groups are lazy — each tier allows ingress from the entire VPC. That means a foothold anywhere gives an attacker lateral access to everything.
Apply least privilege so each tier accepts traffic only from its immediate upstream:
- ALB internet-facing, web ← ALB, app ← web, data ← app, and
- the database must not be reachable from the internet.