
Last topic I turned root login off on my node, which felt great for about ten minutes. Then I needed to install something and hit the obvious problem: if root can't log in, how does anyone do admin work? The answer is sudo, and it's a far better deal than logging in as root ever was.
It's also the first thing I check when I land on a Linux box in a lab. Not kernel exploits, nothing clever. Just sudo -l, because a good chunk of the time someone has left a rule in place that's more generous than they realised, and that single line is the whole privilege escalation. So this one covers both halves: how sudo works and how to set it up properly, then how a sloppy sudo rule quietly hands root to whoever goes looking.
What privilege escalation actually means
Privilege escalation is moving from a weaker account to a stronger one, nearly always root. Root is the account that can do anything on a Linux box: read any file, change any config, install anything, kill any process.
How it happens: two ways. The intended way, where you're allowed to and you ask politely with sudo. And the unintended way, where an attacker sitting on some low-privilege account finds a mistake in the setup and rides it up to root. Same destination, very different paperwork.
A normal user on a Kubernetes node is a nuisance for an attacker. Root on that node is a different story, because root can read the kubelet's config and credentials under /etc/kubernetes and /var/lib/kubelet, and those are the keys to talking to the cluster. On a node, escalation isn't just "they own this box", it's the step where one machine becomes a cluster-wide problem.
Escalation is the hinge. Everything before it is a foothold. Everything after it is an incident.
Sudo: borrowing root for one command
sudo (superuser do) runs one command as another user, and unless you say otherwise that user is root. You stay logged in as yourself throughout. You're borrowing the power for a single command, not moving in.
It does that in four steps, and they're worth knowing in order.
sudo apt install nginx
Are you in /etc/sudoers?
Yours, not root's
Who ran what, and when
Why it beats logging in as root: step three is the part people undersell. With sudo, the root password doesn't need to live in anyone's head or in a shared vault. Ten admins, ten separate passwords, and you revoke one by deleting one line. Compare that with a shared root password, where somebody leaves the company and you're rotating a credential across every box you own.
Step four gives you the audit trail. Every sudo command is logged with the user, the command and the time. If people just log in as root, all your logs say is "root did something", which is worth nothing at 2am when you're trying to work out who broke what.
The upshot is that sudo turns "who has root" into a list you control and a log you can actually read.
What it looks like without it
Fastest way to feel the difference. Try a package install as a normal user and you get stopped at the door, because the package manager needs to write to places only root owns.
One thing that confuses everyone once: after you type your password, sudo remembers you for a few minutes (15 by default), so the next few commands don't prompt. It isn't broken, it's a timer. sudo -k clears it if you want to test the prompt properly.
Reading /etc/sudoers without breaking it
/etc/sudoers is the rulebook. It decides who can run what, as whom. No rule covering you (directly or through a group) means sudo just says no.
Each rule is four fields, and once you read them in order the file stops looking cryptic:
who where=(as-whom) what
mark ALL=(ALL:ALL) ALL
A username, or a group with % in front. %sudo means everyone in the sudo group
Which hosts the rule covers. On a single server, nearly always ALL
In brackets: which user, and after the colon which group, the command may run as
Which commands are allowed. ALL means anything, and this is the field that gets people
So %sudo ALL=(ALL:ALL) ALL reads as "anyone in the sudo group, on any host, as any user or group, can run any command". That's the stock Ubuntu setup, and it's why adding someone to the sudo group is all it takes to make them an admin. A tighter rule names specific binaries instead, so a user can restart one service and nothing else:
# sarah can reboot the box, and that's it
sarah ALL=(root) /usr/sbin/reboot
# deploy can restart nginx without typing a password
deploy ALL=(root) NOPASSWD: /bin/systemctl restart nginx
That NOPASSWD is handy for scripts and CI, and it's also the flag I most often find over-applied. It's fine on one narrow command. It's a gift to an attacker on a broad one.
sudo visudo opens the file and syntax-checks it before saving. Get a typo into /etc/sudoers with a normal editor and sudo can stop working entirely. Pair that with root login disabled from last topic and you've locked every admin out of the box. I've done exactly this on a VM, and it's a grim five minutes even when the machine is disposable.Hands-on: grant sudo, then audit it
Let's create the rule, prove it works, then check it the way an attacker would. Four short steps.
Step 1, make a user with no privileges. This is our stand-in for a low-privilege account, the kind an attacker might land on through a web app or a stolen key.
sudo adduser testy
sudo -u testy sudo -l # what can testy do? nothing yet
Step 2, grant a narrow rule with visudo. Rather than dropping testy in the sudo group (which grants everything), give one specific command. Run sudo visudo and add this at the bottom:
testy ALL=(root) NOPASSWD: /bin/systemctl restart nginx
Step 3, check what the rule really grants. This is sudo -l, which lists everything the current user is allowed to run through sudo. It's the single most useful command in this whole post, and it reads the rules for you so you don't have to interpret the file by hand.
Step 4, verify the boundary holds. The allowed command should work, and anything else should be refused. If both are true, your rule is doing its job.
sudo systemctl restart nginx # allowed, runs
sudo cat /etc/shadow # refused: "not allowed to execute"
Where narrow rules stop being narrow
Now the bit I find genuinely interesting, and the reason I don't fully trust a restricted sudo rule on sight. Allowing one command is not the same as allowing one action. If the command you allowed can start a shell, run other programs, or write files wherever it likes, then it's really a rule that says "become root, via this one slightly awkward door".
Editors are the obvious case. Plenty of them can drop you to a shell from inside, and if the editor is running as root through sudo, so is the shell you get. Same story for anything with a built-in "run this command" feature, and for interpreters like Python or Perl, which exist precisely to run whatever code you hand them.
There's a well-known project called GTFOBins that catalogues exactly this: ordinary Linux binaries and the ways each one can be abused when it's available through sudo or with special permissions. It's maintained by the community and it's the reference I check whenever I see a restricted rule. If the binary in your sudoers line has a page there, treat the rule as "full root" and design accordingly.
The honest version of the lesson: when you write a sudo rule, don't ask "what do I want them to do". Ask "what is the most this binary can be made to do, running as root". Those two answers are the same far less often than you'd hope.
Auditing what you've already got
Most boxes have accumulated sudo rules over years, and nobody's read them since. Here's the sweep I do, and honestly the first two commands find most of it.
On the logging side, sudo writes to /var/log/auth.log on Debian and Ubuntu, or /var/log/secure on RHEL-family systems. Two patterns are worth alerting on. The first is a failed sudo attempt, which shows up as "user NOT in sudoers" and means someone tried something they shouldn't. The second is any successful sudo by an account that shouldn't be doing admin work at all, like a service account.
# someone tried and was refused
sudo grep "NOT in sudoers" /var/log/auth.log
# everything that ran through sudo, with who and what
sudo grep "COMMAND=" /var/log/auth.log | tail
That second one is the payoff for using sudo instead of root logins in the first place. It's an actual list of who did what. Ship those lines off the box to somewhere central, because an attacker with root can edit local logs, and the same logic applies here as with cluster audit logging.
| Check | Status | Note |
|---|---|---|
| NOPASSWD: ALL for CI account | FAIL | Passwordless root, scope it to real commands |
| Leaver still in sudo group | FAIL | Remove from the group today |
| Restricted rule on an editor | WARN | Shell escape possible, treat as full root |
| Rules edited via visudo | PASS | Syntax checked before save |
| sudo logs shipped off-host | PASS | Survives a local root compromise |
The shape I'd leave a node in
So the shape of it: root login stays off, admins get sudo, and every rule is as narrow as it can be while still being useful. Give people commands, not ALL. Be sparing with NOPASSWD. Use visudo every single time. And run sudo -l as your own users occasionally, because reading the rules as the system applies them beats reading the file and hoping you interpreted it right.
The thing I keep coming back to is that sudo isn't really a security control on its own, it's a delegation tool that's only as good as the rules you write. A tidy /etc/sudoers with two narrow entries is genuinely strong. The same file with one lazy NOPASSWD: ALL is a root shell with extra steps, and it'll pass a casual glance because it still looks like a restriction.
Where I'm still figuring things out: keeping this consistent across a fleet. Hand-editing sudoers on each node is fine for a lab and hopeless past about three machines, so it wants to live in config management alongside the SSH hardening from last topic. That's the piece I want to build next, and I haven't landed on the right approach yet, so if you've got a setup you like for managing sudo rules at scale, I'd like to hear it.
Further reading
The manual pages are the real source of truth here: man sudoers covers every option and the full rule syntax, and man sudo covers the flags. GTFOBins is the community reference for which binaries can be abused into a root shell, and it's worth a look before you write any restricted rule.
FAQ
What is privilege escalation in Linux?
Privilege escalation is going from a normal user to a more powerful one, usually root. Done on purpose it is just sudo letting you install a package. Done by an attacker it means turning a small foothold into full control of the machine, which on a Kubernetes node puts the whole cluster at risk.
What does sudo actually do?
Sudo runs a single command as another user, normally root. It checks the rules in /etc/sudoers to see if you are allowed, asks for your own password rather than the root password, runs that one command, and writes a log line saying who ran what and when.
How do I read a line in /etc/sudoers?
Every rule has four parts: who it applies to, which hosts it covers, which user the command runs as in brackets, and which commands are allowed. So mark ALL=(ALL:ALL) ALL means mark, on any host, as any user, can run anything. A percent prefix means a group, not a person.
Why should I edit sudoers with visudo?
Visudo checks your syntax before it saves. A single typo in /etc/sudoers can stop sudo working at all, and if root login is already disabled you have just locked everyone out of admin access on that box. Visudo catches the mistake and lets you fix it first.
Can a restricted sudo rule still give full root?
Often yes. If the allowed command can start a shell, run other programs or write files anywhere, an attacker escapes straight to root from it. Editors, interpreters and tools like find are the classic examples, catalogued by the GTFOBins project. Allowing one command is not the same as allowing one action.
Related reading
- Topic 20: SSH Hardening (turning root login off, which is what makes sudo necessary)
- Topic 19: Least Privilege (the same restraint, applied across the node and RBAC)
- Topic 18: Kubernetes Auditing (the cluster-side version of an audit trail)
- Browse the whole Kubernetes Journey