# Exercise 1: Audit and Redesign Security Groups

## Current State

```
sg-web   (attached to: ALB, all EC2 app instances, the RDS instance, ElastiCache)
  ingress: tcp 22    0.0.0.0/0
           tcp 80    0.0.0.0/0
           tcp 443   0.0.0.0/0
           tcp 3000  0.0.0.0/0
           tcp 5432  10.0.0.0/16
           tcp 6379  0.0.0.0/0
           all       sg-web
  egress:  all       0.0.0.0/0
```

Architecture: internet-facing ALB (443, redirect 80→443) → app instances on port 3000 in private subnets → RDS PostgreSQL (5432) and ElastiCache Redis (6379) in private subnets. Admins currently SSH into app instances for debugging. App instances call Stripe's API over HTTPS. A nightly migration job runs on a separate ECS task and needs DB access.

## Deliverables

1. **Findings**: list every problem with `sg-web` (at least 7), each with the risk.
2. **New design**: one SG per role (`sg-alb`, `sg-app`, `sg-db`, `sg-cache`, `sg-migrations`), with complete ingress **and** egress rules in a table, using SG references wherever possible.
3. **CLI** for the `sg-app` and `sg-db` rules.
4. **Admin access**: replace SSH with a mechanism that needs no inbound rule at all; explain what's required (IAM, agent, VPC endpoints for a private subnet without NAT?).
5. **Migration plan**: how to switch from `sg-web` to the new groups without downtime (order of operations, verification).
6. **Incident question**: an attacker has an open reverse shell on an app instance through port 3000. You remove the 3000 rule from `sg-app`. Does the shell drop? Why, and what do you do instead?

## Requirements Checklist

- [ ] Findings include: SSH open to the world; port 3000 public (ALB bypass); Redis open to the world; DB open to the whole VPC CIDR; one SG for all tiers + self-referencing "all" rule (lateral movement); allow-all egress; port 80 unnecessary on instances.
- [ ] `sg-app` ingress only `3000 from sg-alb`; `sg-db` ingress `5432 from sg-app` and `from sg-migrations`; `sg-cache` `6379 from sg-app`; `sg-alb` 443 (and 80 for the redirect) from the internet.
- [ ] Egress tightened: ALB → app 3000; app → db 5432, cache 6379, 443 to the internet for Stripe (via NAT).
- [ ] SSM Session Manager (instance role with `AmazonSSMManagedInstanceCore`, SSM agent, and `ssm`, `ssmmessages`, `ec2messages` VPC endpoints if there's no NAT) replaces SSH; no port 22.
- [ ] Migration attaches new SGs alongside the old one, verifies traffic, then detaches `sg-web`.
- [ ] Established, tracked connections survive rule removal → isolate with a NACL deny or by replacing/stopping the instance (and forensics snapshot).
