Who can talk to the database?
Your servers live in a VPC, a private network. Security groups are firewalls on each instance: inbound rules allow a protocol and port range from a CIDR block — or from *members of another group*. The classic layout: the internet reaches only the load balancer, the load balancer reaches the web servers, and only web servers reach the database.
Evaluating rules
const ipToInt = (ip) => ip.split(".").reduce((n, part) => n * 256 + Number(part), 0);
function inCidr(ip, cidr) {
const [base, bits] = cidr.split("/");
const size = 2 ** (32 - Number(bits));
return Math.floor(ipToInt(ip) / size) === Math.floor(ipToInt(base) / size);
}function ruleAllows(rule, { protocol, port, sourceIp, sourceGroups = [] }) {
if (rule.protocol !== "-1" && rule.protocol !== protocol) return false; // "-1" means every protocol
if (rule.protocol !== "-1" && (port < rule.fromPort || port > rule.toPort)) return false;
if (rule.cidr) return inCidr(sourceIp, rule.cidr);
return sourceGroups.includes(rule.sourceGroup); // traffic from members of another group
}
function canReach(instances, groups, from, to, { protocol = "tcp", port }) {
const src = instances[from];
const dst = instances[to];
const packet = { protocol, port, sourceIp: src.ip, sourceGroups: src.groups };
return dst.groups.some((g) => groups[g].inbound.some((rule) => ruleAllows(rule, packet)));
}const groups = {
"sg-lb": { inbound: [{ protocol: "tcp", fromPort: 443, toPort: 443, cidr: "0.0.0.0/0" }] },
"sg-web": { inbound: [{ protocol: "tcp", fromPort: 8080, toPort: 8080, sourceGroup: "sg-lb" }, { protocol: "tcp", fromPort: 22, toPort: 22, cidr: "10.0.9.0/24" }] },
"sg-db": { inbound: [{ protocol: "tcp", fromPort: 5432, toPort: 5432, sourceGroup: "sg-web" }] },
"sg-admin": { inbound: [{ protocol: "-1", cidr: "10.0.9.0/24" }] },
};
const instances = {
internet: { ip: "203.0.113.7", groups: [] },
lb: { ip: "10.0.1.10", groups: ["sg-lb"] },
web: { ip: "10.0.2.20", groups: ["sg-web"] },
db: { ip: "10.0.3.30", groups: ["sg-db", "sg-admin"] },
bastion: { ip: "10.0.9.5", groups: [] },
};