A Temporary Permission Needs An Expiry Date

Granting broad permissions to get a deployment pipeline working is a perfectly good move. Leaving them there is the mistake, and the way you avoid it is to decide, at the moment you grant them, what event will take them away. "We'll tighten it later" is not an event. It is a hope, and hopes have no owner, no date and no alarm.
I did this again recently. A new host sat in a private network with no public address, and the pipeline needed a way to reach it and run a deployment. Rather than guess at the exact list of API calls involved, we attached wide, full-access policies to the role, watched the path work end to end, and agreed to replace them with least-privilege ones once we knew what the pipeline actually asked for. I still think that order is right. What I want to argue is that the agreement itself is the fragile part.
Why start broad at all
The instinct to write the narrowest possible policy up front sounds disciplined, and it often produces the opposite of discipline. You cannot know the exact calls a tool will make until it has made them. So you guess, the pipeline fails on a missing permission, you add one, it fails on the next, and an hour disappears into a loop whose only output is a longer policy document. Worse, the failure messages from a half-configured permission model often look like problems with the network, the agent or the trust relationship. You end up debugging four things at once.
Granting broad access first separates those concerns. If the deployment works with everything allowed, then the network path, the identity and the tooling are fine, and any later failure is purely about permissions. That is real information, and it is cheap to get. I have come to prefer proving the path first and deriving the policy from evidence second, because a policy written from observed behaviour is almost always tighter and more accurate than one written from memory of the documentation.
Where it goes wrong
The trouble begins the moment the pipeline goes green. Everyone's attention moves to the next failure, the next environment, the next person waiting on the result. The broad policy is now doing its job quietly, and nothing about it is broken, which is exactly why nobody looks at it. Security debt rarely announces itself. It sits in a role that works.
There is also a subtle reversal of incentives. While the permissions are too narrow, something fails loudly and someone fixes it. While they are too broad, nothing fails at all. The system gives you immediate feedback for under-granting and none for over-granting, so left alone it will drift towards generous. Six months later the role still has full access to a whole service, and the justification is a message in a chat thread that nobody can find.
The cost is not abstract. A pipeline identity with wide rights is a very attractive thing to compromise, and it is trusted by design, so its actions look legitimate. If that identity can reach systems holding data that customers trusted you with, the blast radius of a leaked token is set by whatever you granted on a busy afternoon to get unblocked.
Make the tightening part of the work
The practical fix is dull, which is probably why it gets skipped. Treat the broad grant as a task with an owner, and make the closing condition observable rather than aspirational. The trigger I like best is "the first successful run". The moment the pipeline succeeds, the next action is to read the record of what it actually called and write the narrow policy from that, while the details are still fresh and the person who knows why each call matters is still in the room.
Where the platform supports it, let the platform help. Access logs and policy analysis tools can show which permissions were used and which never were, which turns "what does this need?" from a guessing game into a reading exercise. If there is a way to set the broad grant to lapse on its own, use it. A permission that expires by default flips the incentive: now it is the lack of attention that causes a loud failure, and loud failures get fixed.
If you cannot do either, put the replacement in the same change that introduces the shortcut, as a tracked item with a name against it. Infrastructure that is defined in code makes this easier, because the broad policy is a visible line in a repository, and a line in a repository can carry a comment, a ticket and a review. A console click carries nothing.
The commercial argument
I do not make this case out of purism. Engineering time is finite and a team that insists on perfect policies before anything runs will ship late and learn nothing sooner. Starting broad is a rational trade of short-term risk for speed of learning. The deal only holds if the risk really is short-term.
That is the whole difference between a shortcut and a debt. A shortcut has a known end. A debt is a shortcut whose end nobody wrote down. The first costs you a few minutes of tidying on a good day. The second turns up later, usually during an audit or an incident, when the people who remember why it exists have moved on and the tidy-up has become an investigation.
So when you reach for the wide permission to get unstuck, go ahead. Just finish the sentence before you do: this stays until the first green run, then I replace it with what the logs show. Say it aloud, put a name on it, and let the pipeline go green.


Share your thoughts