Skip to content

Disable Root Login: Sudo-Only Linux Administration Done Right

Close every root entry point (SSH, console, su, Cockpit) without locking yourself out, then design sudoers rules that keep an audit trail and plan break-glass recovery.

●By 11 min read

"Set PermitRootLogin no" is the line every hardening guide includes, including our own SSH security guide. It is also only one of several ways to become root. The console, su, web consoles like Cockpit, and root's own SSH keys all stay open unless you close them, and a careless sudoers file can hand out root just as freely as a shared password did.

The goal of sudo-only administration is simple: every privileged action is tied to a named person, and there is no shared root credential in daily use. This guide covers the order of operations that avoids lockouts, every root entry point and how to close it, sudoers rules that do not leak shells, and the recovery path you need once root is locked.

Order of Operations: Do Not Lock Yourself Out

Build the replacement before removing root. Keep an existing root session open in a separate terminal until the final check passes; it is your undo button.

# 1. create a named admin account

$ sudo adduser alice # Debian/Ubuntu (interactive)

$ sudo useradd -m alice && sudo passwd alice # RHEL/Fedora

# 2. grant admin rights through the distribution's admin group

$ sudo usermod -aG sudo alice # Debian/Ubuntu

$ sudo usermod -aG wheel alice # RHEL/Fedora

# 3. install alice's public key

$ sudo install -d -m 700 -o alice -g alice /home/alice/.ssh

$ sudo install -m 600 -o alice -g alice alice.pub /home/alice/.ssh/authorized_keys

# 4. from a NEW terminal, prove the whole path works

$ ssh alice@web1

alice@web1:~$ sudo -v && sudo -l

User alice may run the following commands on web1:

(ALL : ALL) ALL

Give admins a password for sudo β€” an account that logs in with an SSH key still needs a local password for sudo to prompt for. That password never travels over SSH, and it means a stolen key alone is not root.

At least two admins β€” one named admin is a single point of failure: one lost key or one departure and nobody can get root without the recovery path. Add a second before locking root.

Automate the account setup β€” our SSH key setup tool generates the key and the authorized_keys commands for step 3.

Every Way to Become Root

Entry pointClosed byNotes
SSH as rootPermitRootLogin noUpstream default is prohibit-password, which still allows root keys. RHEL 8 shipped yes
root's SSH keysRemoving /root/.ssh/authorized_keysCloud images often put a key there with a forced command; remove it once named admins work
Console / serial loginpasswd -l rootConsole logins need root's password; a locked hash cannot match
su to rootLocked root password, plus pam_wheelpam_wheel limits who may even attempt su
Cockpit web console/etc/cockpit/disallowed-usersLists root by default on Fedora and RHEL; check it if you install Cockpit elsewhere
Other services with their own authPer-service configFTP daemons, control panels, IPMI and BMC consoles
sudo itselfA sudoers policy you have reviewedThe one door you keep, deliberately

# lock root's password (prepends ! to the hash in /etc/shadow)

$ sudo passwd -l root

$ sudo passwd -S root

root L 2026-09-30 0 99999 7 -1 # RHEL shows: root LK ... (Password locked.)

# root's keys

$ sudo cat /root/.ssh/authorized_keys

$ sudo mv /root/.ssh/authorized_keys /root/.ssh/authorized_keys.disabled

Locking is not deleting β€” passwd -l keeps the hash with a ! in front, so passwd -u root restores the old password. Do not delete the root account or change its UID; the system depends on both.

Ubuntu starts here already β€” the Ubuntu installer does not set a root password at all and makes the first user an admin through the sudo group. Check before assuming other distributions behave the same.

Locking does not block keys β€” a locked password stops password logins only. Key-based SSH for root is closed by sshd and by removing root's keys, which is why both steps are in the table.

sshd: Make the Setting Actually Apply

sshd uses the first value it reads for most keywords, and current Debian, Ubuntu and RHEL configs start with Include /etc/ssh/sshd_config.d/*.conf. A drop-in with a low number therefore beats both the main file and the files cloud-init or the installer add later.

$ echo 'PermitRootLogin no' | sudo tee /etc/ssh/sshd_config.d/10-no-root.conf

# validate syntax, then print the effective value

$ sudo sshd -t

$ sudo sshd -T | grep -i '^permitrootlogin'

permitrootlogin no

# evaluate Match blocks for a specific connection

$ sudo sshd -T -C user=root,host=bastion,addr=10.0.0.5 | grep -i '^permitrootlogin'

# apply (existing sessions are not dropped)

$ sudo systemctl reload ssh # Debian/Ubuntu

$ sudo systemctl reload sshd # RHEL/Fedora

# test from a new terminal

$ ssh root@web1

root@web1: Permission denied (publickey).

Grep the effective config, not the file β€” a PermitRootLogin yes left in an earlier drop-in, or inside a Match block, silently wins over what you added. sshd -T is the only reliable answer.

Restrict who can log in at all β€” AllowGroups sshusers turns the question around: only listed groups get in, so new service accounts are excluded by default. Our SSH config generator builds these files.

sponsored

Sudoers Rules That Do Not Leak Root

Sudo-only administration is only as good as its policy. The distribution default is a single line that gives the admin group everything, which is fine for a small team of real admins. Problems start when you add narrower rules for other people and those rules turn out to be shells in disguise.

# always edit through visudo: it locks the file and checks syntax before saving

$ sudo visudo -f /etc/sudoers.d/10-admins

# /etc/sudoers.d/10-admins

Defaults use_pty

Defaults logfile="/var/log/sudo.log"

Defaults timestamp_timeout=5

Defaults log_output

%sudo ALL=(ALL:ALL) ALL # Debian/Ubuntu default (in /etc/sudoers)

# %wheel ALL=(ALL) ALL # RHEL/Fedora default

# a narrow rule for the deploy team

Cmnd_Alias WEB_SVC = /usr/bin/systemctl reload nginx, /usr/bin/systemctl restart app

%deployers ALL=(root) WEB_SVC

%deployers ALL=(root) sudoedit /etc/nginx/conf.d/app.conf

$ sudo visudo -c

/etc/sudoers: parsed OK

/etc/sudoers.d/10-admins: parsed OK

Looks narrowWhy it is rootInstead
vim /etc/nginx/nginx.confvim runs shell commands with :!shsudoedit, which edits a copy as the user and writes it back
less /var/log/*less runs !sh; the wildcard also matches extra argumentsGroup read access to the logs (adm on Debian), or journalctl permissions
systemctl status *The wildcard matches any unit and extra arguments; before systemd 247 its pager could also spawn a shell (CVE-2023-26604)List exact units and actions
find, tar, rsync, awk-exec, --checkpoint-action, -e and system() run commandsA wrapper script owned by root that takes validated arguments
NOPASSWD: ALLAnyone with the account, or a stolen SSH key, is root instantlyPasswords for humans; NOPASSWD only for one exact command for automation
/home/deploy/bin/fix.shThe user can edit the script they may run as rootScripts in a root-owned path like /usr/local/sbin, mode 0755

Silent ignores in sudoers.d β€” sudo skips files in /etc/sudoers.d whose names contain a dot or end in ~. A file called admins.conf is never read, and nothing warns you. Use names like 10-admins, mode 0440.

Avoid sudo -i as a habit β€” sudo -i, sudo -s and sudo su - all open a root shell, and the log then shows only that a shell started. Running individual commands with sudo keeps a per-command trail. log_output records sessions for sudoreplay when a shell is unavoidable.

Restrict su too β€” uncomment auth required pam_wheel.so use_uid in /etc/pam.d/su. On Debian/Ubuntu, which have no wheel group, add group=sudo to the line.

Break-Glass Recovery With Root Locked

Locking root changes how you recover a broken host. If /etc/fstab has a typo, the system drops to emergency mode, which normally asks for the root password, and a locked password cannot be entered. Decide the recovery path before you need it.

# emergency mode with a locked root account (util-linux sulogin)

Cannot open access to console, the root account is locked.

See sulogin(8) man page for more details.

# option A: allow a passwordless emergency shell on the console

$ sudo systemctl edit emergency.service

[Service]

Environment=SYSTEMD_SULOGIN_FORCE=1

# repeat for rescue.service

# option B: boot-time override from the GRUB menu (press e, edit the linux line)

init=/bin/bash # any distribution

rd.break # RHEL/Fedora: stop in the initramfs

Physical access is root either way β€” both options give root to whoever reaches the console. On shared or untrusted hardware, set a GRUB password and encrypt the disk; in the cloud, the provider's serial console access is the control to protect.

A sealed root password is a valid choice β€” some teams set a long random root password, store it in a vault with access logging, and rotate it after every use. Root is then usable only on the console, and SSH and su stay closed by the other controls.

Write the procedure down β€” test recovery on a VM before rolling the change out, and record the steps where the on-call engineer will find them.

Verify and Audit

Re-run these checks after every image build and configuration change; drift usually comes from a new drop-in or a fresh cloud image, not from a person. They also fit naturally into the account checks in our server hardening checklist.

# root login closed?

$ sudo sshd -T | grep -i '^permitrootlogin'

$ sudo passwd -S root

$ sudo ls -la /root/.ssh/

# who can become root, and how?

$ getent group sudo wheel

$ sudo grep -rhE '^[^#].*(ALL|NOPASSWD)' /etc/sudoers /etc/sudoers.d/

# what did they do?

$ sudo journalctl _COMM=sudo --since today

Oct 02 10:14:03 web1 sudo[4121]: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/systemctl reload nginx

# classic log files

$ sudo grep sudo /var/log/auth.log # Debian/Ubuntu

$ sudo grep sudo /var/log/secure # RHEL/Fedora

Ship the logs off the host β€” a user with full sudo can edit local logs. Forwarding the journal or syslog to a central server keeps the trail trustworthy.

Alert on the rare events β€” a successful root SSH login, passwd -u root, or a write to /etc/sudoers.d should never happen silently. An auditd watch such as -w /etc/sudoers.d -p wa -k sudoers records who did it.

Frequently Asked Questions

Is PermitRootLogin no enough to disable root login?

No. It only closes SSH. Root can still log in on the console, through su, and through other services such as Cockpit if their own settings allow it. Lock root's password with passwd -l root, remove /root/.ssh/authorized_keys, restrict su with pam_wheel, and verify with sshd -T and passwd -S root.

What is the difference between PermitRootLogin no and prohibit-password?

prohibit-password, the OpenSSH default since 7.0, refuses password and keyboard-interactive logins for root but still accepts public keys. no refuses root over SSH entirely. For sudo-only administration use no, so that every login is tied to a named account.

Will locking the root password break sudo?

No. sudo asks for the invoking user's own password by default, not root's, so admins keep working after passwd -l root. What does change is emergency and rescue mode, which normally need the root password; plan that recovery path before locking root.

Should admin accounts use NOPASSWD in sudoers?

Not for humans. With NOPASSWD, anyone who gets the account, for example through a stolen SSH key, is root immediately. Give admins a local password that is only used for sudo. Reserve NOPASSWD for automation accounts, limited to the exact commands they need.

How do I get root access if I lock myself out?

Use the console. With a locked root account, emergency mode will refuse to open a shell unless SYSTEMD_SULOGIN_FORCE=1 is set for emergency.service and rescue.service, so the usual route is editing the kernel command line in GRUB: init=/bin/bash works on any distribution, and rd.break on RHEL and Fedora. In the cloud, use the provider's serial console or attach the disk to another instance.

sponsored

Related Tools

See also