Synopsis #
OpenBSD includes OpenSSH in the base system. Its defaults are maintained with the operating system and should not be replaced by copied cipher lists or generic hardening templates. A conservative remote-access setup uses a tested administrator account, public-key authentication, deliberate forwarding policy, Packet Filter exposure, configuration validation, and an independent recovery console.
This guide changes authentication only after a key-based administrator session succeeds. Keep the original session and console access available until a second connection works under the final policy.
Establish the Administrator Account #
Complete Create an Administrator Account with doas and SSH Keys first. Verify the account from a separate client session:
$ ssh -o IdentitiesOnly=yes -o PreferredAuthentications=publickey \
-o PasswordAuthentication=no -o KbdInteractiveAuthentication=no \
-i ~/.ssh/id_ed25519 admin@server.example.com
# Test the intended private key
$ doas id
# Confirm that the account can perform administrative work
Do not continue if either command fails.
Inspect the Effective Server Configuration #
The server configuration is sshd_config(5)
at /etc/ssh/sshd_config. Many defaults do not appear as active lines in that file. Inspect the effective settings with sshd(8)
:
# sshd -T | grep -E '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|allowtcpforwarding|x11forwarding) '
OpenBSD currently defaults PermitRootLogin to prohibit-password, PasswordAuthentication to yes, and KbdInteractiveAuthentication to yes. The final policy should reflect the host’s actual access requirements rather than assumptions about defaults.
Apply a Minimal Authentication Policy #
After key-based administration has been tested, add the following explicit policy to /etc/ssh/sshd_config:
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
Place these global directives before the first Match block. This policy disables all remote root login, password authentication, and keyboard-interactive authentication. It does not affect console login.
Do not add algorithm lists merely to make the configuration look stricter. OpenSSH removes weak defaults and introduces new algorithms through supported system updates. A local list can preserve obsolete choices or prevent future improvements.
Decide Whether Forwarding Is Required #
SSH can forward agents, TCP connections, Unix-domain sockets, X11 connections, and tunnel devices. These features are useful administrative tools, but they should match the host’s role.
For an account that needs only an interactive shell and file transfer, a Match block can restrict forwarding:
Match User admin
DisableForwarding yes
Do not apply this restriction when the account requires port forwarding, agent forwarding, X11 forwarding, or tunnel creation. A Match block continues until another Match or the end of the file, so place global settings above it.
Validate and Reload #
Check the syntax and inspect the effective result before changing the running daemon:
# sshd -t
# Reject syntax or key-file errors
# sshd -T -C user=admin,addr=198.51.100.25,host=client.example.com | \
grep -E '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|disableforwarding) '
# Confirm the effective settings for the administrator connection
# sshd -T -C user=root,addr=198.51.100.25,host=client.example.com | \
grep -E '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication) '
# Confirm that the global root-login policy was not placed inside a Match block
# rcctl reload sshd
# Apply the validated configuration without ending established sessions
Keep the existing session open. Start another connection with verbose client logging:
$ ssh -v -o IdentitiesOnly=yes -o PreferredAuthentications=publickey \
-o PasswordAuthentication=no -o KbdInteractiveAuthentication=no \
-i ~/.ssh/id_ed25519 admin@server.example.com
Confirm login and doas again. Only then close the recovery session.
Limit Network Exposure with PF #
If the host uses a default-block pf.conf(5)
policy, allow SSH on the intended interface and address. This example permits TCP port 22 on the address assigned to the egress interface group:
pass in on egress proto tcp to (egress) port ssh
Validate the complete ruleset with pfctl(8) before loading it:
# pfctl -nf /etc/pf.conf
# Parse the file without changing the active ruleset
# pfctl -f /etc/pf.conf
# Load the validated ruleset
Restrict the source address when administration always comes from a stable management network. A changed SSH port may reduce log noise, but it is not an authentication control.
Verify Host Identity #
On first connection, verify the server host-key fingerprint through an independent channel. Display fingerprints on the server with ssh-keygen(1) :
# ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
If a known-hosts warning appears after a legitimate server rebuild, verify the new fingerprint before removing the old entry.
Monitor Authentication #
Follow authentication events in /var/log/authlog:
# tail -f /var/log/authlog
Use last(1) to review successful sessions:
$ last
Repeated failed attempts from the Internet are expected on a public SSH service. Strong authentication, supported software, limited accounts, and accurate logs matter more than reactive address lists built from short-lived scans.
Recovery #
If the new session fails, use the still-open session or console to:
- inspect
/var/log/authlog; - run
sshd -t; - inspect the account’s home,
.ssh, andauthorized_keysownership and modes; - compare
sshd -Twith the intended policy; - revert the last configuration change and reload
sshd.
If every administrative credential is lost, use Recover Access and Reset the Root Password . Maintain at least one independent recovery credential. A FIDO-backed key can improve key protection but does not replace that recovery path.