Moderation from a terminal: why you can't become an admin on the website
Part of my Krabber series, a Twitter clone in Go. The full source is on GitHub.
Intro
Any site where people can post needs moderation. Krabber has a console for it called Krabmin: a report queue, bans, warnings, removing and restoring molts, and a log of every action. But the part I want to focus on is a deliberate restriction: there is no way to become an admin through the website. The highest role can only be granted from a terminal. Let me explain the setup and why that line matters.
I. Two roles
Moderation runs on a role attribute on the account, which is either moderator or admin, checked by a requireModerator guard on the Krabmin routes. Moderators can work the queue: they see reports, remove and restore molts, warn and ban krabs. Admins can do all that and also appoint or remove moderators.
So day to day, an admin manages the moderators, and the moderators manage the content. Normal stuff. The interesting rule is how you get to be an admin in the first place.
II. Admins are made from a terminal, never the site
There is no button, anywhere on Krabber, that makes someone an admin. The only way to grant that role is a command-line tool, krabctl, run from my own machine with AWS credentials:
AWS_PROFILE=krabber-admin TABLE_NAME=krabber-prod \
go run ./cmd/krabctl role <username> admin
That’s how the first admin is created. After that, admins can appoint moderators inside Krabmin, but the top of the pyramid is only ever set by someone who can reach the database directly, which means someone with AWS access, which means me.
III. Why keep it off the web
This is a small decision with a big security payoff. Think about what it would mean if admin could be granted through the site. Then any bug that let an attacker call the “make admin” path, a missing permission check, a CSRF hole, a clever request, would be a full account takeover of the whole platform. The crown jewels would be reachable from the internet.
By making the top role grantable only from a terminal with AWS credentials, that whole category of attack disappears. There’s no web request that escalates to admin, so there’s no web request to find and abuse. An attacker would need my AWS access, not a flaw in my web app, and those are very different walls to climb. It’s the same instinct as not having a root login over the internet: the most dangerous capability shouldn’t live on the most exposed surface.
IV. The queue itself
The everyday work flows through the report queue. When a krab reports a molt, that writes a report item that shows up in Krabmin’s list, where a moderator can remove the molt, dismiss the report, or ban the author. Removing a molt is reversible, so a mistake can be undone, and every action, bans and warnings and removals, is written to a moderation log, so there’s an accountable trail of who did what.
None of that needs admin. It’s all moderator-level, which is exactly the point of splitting the roles: the people doing the daily moderating never need the one permission that can only come from a terminal.
Conclusion
Krabmin gives Krabber real moderation, a queue, reversible removals, bans, and an audit log, but the design choice I’d pass along is keeping the most powerful role off the website entirely. Grant admin only from a terminal with real credentials, let admins hand out the lesser role in-app, and a whole class of “attacker becomes god” bugs simply can’t exist, because the path isn’t there to exploit. Keep your crown jewels off your most exposed surface. Thanks for reading, and may your report queue stay short.