Security group / firewall open to the world — exposed service
Port 22 or 5432 reachable from any public IP
Focused incident mode — strips away everything but this runbook.
Symptoms
- Port 22 or 5432 reachable from any public IP
- Security scanning flags an ingress rule of 0.0.0.0/0
- A database or admin UI is accidentally public
Many AWS incidents start with an SSRF pivot to metadata, then a wide-open SG. Review ingress for 0.0.0.0/0 during every incident and on a schedule.
Evidence to grab
Collect these artifacts before you change anything — they prove (or rule out) each cause.
Open ingress rules
aws ec2 describe-security-groups --group-ids <SG-ID> --query 'SecurityGroups[].IpPermissions'Public reachability
nc -zv <PUBLIC-IP> 22 # then 5432
Diagnostic flow
Run the steps in order, marking each claim confirmed or refuted. The evidence you gather feeds the ranked causes below.
Guided decision tree is ready.
Steps with commands, expected output, and pass/fail branches.
Ranked root causes
Evidence checklist
- 0.0.0.0/0 on a management or DB port
- No description/justification tag on the rule
Confirm before fixing
aws ec2 describe-security-groups --group-ids <SG-ID> --region <REGION> --query 'SecurityGroups[].IpPermissions[*].IpRanges[].CidrIp'List the CIDRs
Fix
aws ec2 revoke-security-group-ingress --group-id <SG-ID> --ip-permissions file://deny-all.jsonRevoke the 0.0.0.0/0 rule after authorizing office/bastion CIDRs
Expected: REVOKE success
Resolution runbook
Apply from top to bottom after the cause is confirmed. Review every command before running it — risk tags are shown on each.
aws ec2 describe-security-groups --group-ids <SG-ID> --region <REGION>Identify the exposed rule
nc -zv <PUBLIC-IP> <PORT>Confirm the blast radius
aws ec2 revoke-security-group-ingress --group-id <SG-ID> --ip-permissions file://deny-all.jsonImmediately block 0.0.0.0/0 (authorize bastion/office CIDRs first)
Prevention
- Track SG changes with Terraform/CloudFormation and review PRs.
- Run periodic scanners (Scout Suite / Prowler) alerting on 0.0.0.0/0 ingress.
- SSH through a bastion/jump host with IP allowlists; never open the DB port publicly.
Related runbooks
Same stack, same failure family — worth a skim.
A leaked API key keeps working for months
kubectl returns 'could not get token: AccessDeniedException' for a role
Commands marked READ CHANGE DESTRUCTIVE — never run DESTRUCTIVE commands against production data you cannot restore. Copy → verify → execute.