Linux

Why PasswordAuthentication no does nothing on Ubuntu 24.04

You set PasswordAuthentication no. You restarted SSH. You tested it — and the password prompt still appears. Nothing in the logs suggests a problem, and the file plainly says no.

The setting is being read. It is just losing to another file you did not know existed.

The rule almost everyone gets backwards#

Here is the behaviour that causes this, straight from sshd_config(5): for most keywords, the first obtained value is used.

Not the last. The first.

Nearly every other configuration system on a Linux box — nginx, systemd drop-ins, shell profiles — works the other way, where later definitions override earlier ones. So the instinct to “add my setting at the bottom, it’ll take priority” is correct almost everywhere except here, and sshd is where it matters most.

Where the competing value comes from#

Open /etc/ssh/sshd_config on Ubuntu 24.04 and look at the top:

$ grep -n "^Include" /etc/ssh/sshd_config
12:Include /etc/ssh/sshd_config.d/*.conf

Line 12. Everything in that directory is read before the rest of the main file — and those files are read in alphabetical order.

Now look at what is in there on a typical cloud image:

$ ls /etc/ssh/sshd_config.d/
50-cloud-init.conf
60-cloudimg-settings.conf

$ grep -r PasswordAuthentication /etc/ssh/sshd_config.d/
50-cloud-init.conf:PasswordAuthentication yes
60-cloudimg-settings.conf:PasswordAuthentication no

Ubuntu’s own image ships a file that disables password authentication. Cloud-init ships one that enables it. 50 sorts before 60, first value wins, so passwords stay enabled — before you have changed anything at all.

Whatever you write in the main sshd_config, or in a 99- file, is read after both and discarded.

Stop reading files. Ask the daemon.#

This is the habit worth taking away from the whole problem. sshd will tell you its fully resolved configuration:

sudo sshd -T | grep -E 'passwordauthentication|permitrootlogin|pubkeyauthentication'

That output is the truth. It accounts for every include, every override, and the resolution order. A grep across config files tells you what is written; sshd -T tells you what is in effect. They disagree more often than people expect.

Use it before you change anything and after every reboot.

The fix#

Put your settings in a file that sorts before the cloud-init one:

sudo tee /etc/ssh/sshd_config.d/01-hardening.conf > /dev/null <<'EOF'
# Named 01- deliberately: sshd uses the FIRST value it finds, and
# 50-cloud-init.conf sets PasswordAuthentication yes. A 99- file
# would be read after it and silently ignored.
PasswordAuthentication no
PermitRootLogin no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
EOF

sudo sshd -t && sudo systemctl restart ssh

Always run sshd -t before restarting. It validates the configuration without applying it. A syntax error in a live restart can leave you unable to reconnect.

Do not skip this check#

Before disabling passwords, prove key authentication works — from a second terminal, with your current session still open:

ssh -o BatchMode=yes you@your-server 'echo ok'

BatchMode=yes suppresses any password prompt, so it only prints ok if the key genuinely works. If you disable password authentication without a working key, the only way back in is your provider’s console — or a rebuild.

Why “just edit 50-cloud-init.conf” is not enough#

The obvious move is to edit or delete cloud-init’s file. On some images it will be regenerated. Worse, on some providers a bootcmd rewrites SSH configuration on every boot, so your edit survives until the next restart and then quietly reverts.

Naming your own file 01- is more robust because it does not depend on anyone else’s file staying deleted. Let them write whatever they like — yours is read first.

This was raised upstream with cloud-init and closed as “not planned”. It is considered intended behaviour, so treat it as a permanent property of these images rather than a bug awaiting a fix.

Also check: is anything even listening the way you think?#

Ubuntu 24.04 moved SSH to socket activation, which changes two things people trip over:

systemctl is-enabled ssh.socket   # enabled
systemctl is-active  ssh.socket   # active

First, pkill -HUP sshd no longer reloads anything, because there is no persistent daemon — systemd spawns one per connection. Second, and more disruptive: the Port directive in sshd_config is ignored when socket activation is on. The socket unit decides the port. If you are moving SSH off port 22 and it is not taking effect, this is why:

sudo systemctl edit ssh.socket
# [Socket]
# ListenStream=
# ListenStream=2222

The empty ListenStream= is required — it clears the inherited value before setting the new one. Without it you end up listening on both ports.

A short checklist#

  1. sudo sshd -T | grep passwordauthentication — find out what is actually in effect
  2. ls /etc/ssh/sshd_config.d/ — see what else is competing
  3. Write your settings to 01-hardening.conf
  4. sudo sshd -t — validate before restarting
  5. Confirm key login from a second terminal with BatchMode=yes
  6. Restart, reboot, and run step 1 again

Step 6 is the one people skip, and it is the one that catches the boot-time rewrites.


security server-hardening ssh sshd ubuntu

Related