tech, developers, and the code underneath

issue 225· essay·

Least privilege, actually applied

Everyone agrees with the principle. Almost nobody has checked what their service can actually reach.

Least privilege is one of those principles nobody argues with and few implement, because implementing it means doing the tedious work of finding out what permissions are actually used.

Here is the tedious work, in a manageable order.

the audit, in one afternoon#

For each service, answer four questions. Write the answers down.

1. What identity does it run as? Not "a service account" — which one. A surprising number of services run as something shared, or as a human's credentials that were used for the initial deploy and never replaced.

2. What can that identity do? Enumerate the actual permissions. In most cloud platforms this is one API call. The answer is usually much broader than anyone expects, because permissions accumulate and nothing removes them.

3. What does it actually use? This is the gap. Cloud providers log every authorised call — CloudTrail, audit logs, equivalents elsewhere. Ninety days of logs tell you precisely which permissions were exercised.

4. What is the delta? Everything granted and never used is a candidate for removal, and that set is typically most of the grant.

That fourth number is the finding. In every audit I have seen, a service uses somewhere between 5% and 20% of what it is permitted to do.

the specific over-grants to look for#

Wildcards. s3:* on *. Almost always the result of "it wasn't working so I broadened it until it did," which is a debugging technique that becomes a permanent security posture.

Write access where only read is used. Extremely common for anything reading configuration or reference data.

Access to everything of a type. A service that needs one bucket having access to all buckets. Scope to the resource, and where possible to a prefix within it.

Permissions for a feature that was removed. The code went; the grant stayed.

Human roles used by machines. A deploy pipeline running as a role designed for an engineer's console access — which usually includes the ability to change permissions, and that is the one that turns a compromise into a takeover.

iam:* or its equivalent. The permission to grant permissions. Anything with this is effectively an administrator regardless of what else it has. Treat it as its own category and audit it separately.

the direction to move#

Short-lived over long-lived. Workload identity — the container proves what it is and receives a token that expires in minutes — removes the stealable credential entirely. This is the single highest-value change on this list, and it is architectural rather than a matter of tightening a policy.

Scoped over broad. One bucket and one prefix, not the account.

Read over write. Split the identity if the same service does both, so the read path cannot write.

Deny at the boundary. A service in a network that cannot reach the internet cannot exfiltrate, whatever its IAM permissions say. Network policy and identity policy are independent layers and both matter.

the thing that makes it stick#

An audit is a snapshot. Permissions creep back the next time something does not work at 6 p.m. on a Friday.

Two mechanisms hold the line:

Permissions in code, reviewed like code. If a grant requires a pull request, the broad one gets a comment. If it is a console click, it does not.

A scheduled review. Quarterly, using the same used-versus-granted delta. Twenty minutes per service, and it catches both the emergency grant nobody reverted and the feature that was deleted.

the honest framing for a sceptical audience#

Least privilege does not prevent compromise. It bounds what a compromise costs.

That is the argument to make when someone asks why it is worth the effort: the question is not whether a credential will leak — a dependency, a laptop, a log file, a misconfigured bucket, eventually one will. The question is whether the answer to "what could they do with it" is "read one bucket" or "anything."

Those two answers are the difference between an incident report and a breach notification, and the work that separates them is an afternoon per service.

get README in your inbox

One dispatch, no noise. Tech and developer news, plus the occasional long piece on the craft.

subscribe →