Infrastructure

Security groups should describe relationships, not addresses

A rule written against a CIDR block encodes an accident of your current network. A rule written against another security group encodes what you actually meant.

Most security group rules I have inherited are wrong in the same way. They are correct, they work, and they say the wrong thing.

Here is the shape. The application tier needs to reach the database. Somebody looks up the application subnet, finds 10.0.2.0/24, and writes an ingress rule on the database security group allowing port 5432 from 10.0.2.0/24. Traffic flows. The ticket closes.

What that rule actually claims

It claims that anything holding an address in 10.0.2.0/24 may reach the database on 5432.

That is not what anyone meant. What they meant was that the application may reach the database. The CIDR block was a proxy for the application, accurate on the afternoon it was written, and it degrades from there.

It degrades in two directions at once. It becomes too permissive, because a subnet is a container and things get added to containers. A batch worker deployed into the same subnet six months later inherits database access nobody granted it, silently, as a side effect of a placement decision. And it becomes too restrictive, because when the application scales into a third availability zone with a new subnet, connections fail, and the fix under pressure is to widen the rule to the whole VPC.

Both failures come from the same root: the rule describes topology, and topology changes for reasons that have nothing to do with access control.

Reference the group instead

AWS security groups can reference other security groups as a source. The rule becomes: allow 5432 from sg-application.

Read that out loud. The application tier may reach the database tier. That is the sentence the ticket was actually asking for.

What it buys you:

  • Adding a fourth availability zone changes nothing. New instances launch with the application security group and are covered.
  • The batch worker in the same subnet gets nothing unless someone explicitly attaches the application security group to it, which is a visible decision rather than an invisible consequence.
  • The rule survives re-addressing the VPC entirely.
  • An auditor reading the rule set learns the intended architecture. A rule set full of CIDR blocks teaches them your subnet layout, which is not the same information.

When a CIDR is the right answer

This is not absolute. Sometimes an address range is genuinely the thing you mean.

  • Traffic from outside AWS, such as an office network or a partner endpoint. There is no security group to reference.
  • VPC peering across accounts, where group references have constraints worth checking before you rely on them.
  • Deliberate public exposure. 0.0.0.0/80 on a load balancer for a public site is honest, and dressing it up achieves nothing.

The test I use: could the set of things on the other side of this rule change without anyone intending to change access? If yes, reference a group. If the range is a stable external fact, a CIDR is fine.

The migration is duller than it sounds

Rewriting an existing rule set is mechanical. For each rule, ask what it was trying to express, find the security group that expresses it, add the group-based rule, verify traffic, remove the CIDR rule.

The one genuinely awkward case is a rule that has drifted into carrying two meanings, where a single CIDR block now covers two workloads that were never meant to have identical access. There is no clean mechanical translation, because the rule was already wrong. Splitting it is the work, and discovering it needs splitting is the benefit.

Why this is worth caring about

Network segmentation fails in practice not because people disagree with it but because the rules stop meaning anything. A rule set of forty CIDR entries with no comments is unauditable, so nobody audits it, so it only ever grows.

A rule set that reads as a list of relationships between tiers stays legible. When it stays legible, someone notices the entry that should not be there.

Continue reading