PRACTITIONER GUIDE | LINUX SECURITY
Practitioner GuideUpdated 12 min read

SSH Hardening Guide: The sshd_config Settings That Actually Matter for Enterprise Linux Security

PermitRootLogin no
is the single highest-value SSH setting change. Root login via SSH means a successful brute force or key compromise gives an attacker immediate root access with no privilege escalation step required
PasswordAuthentication no
eliminates credential brute force and password spray as attack vectors against SSH. Requires all users to have a configured authorized_keys or a valid SSH certificate before this can be enforced safely
ClientAliveInterval + MaxSessions
together enforce session timeouts. Without these, an SSH session left open on an unattended workstation or after a user's account is disabled remains connected and fully authorized indefinitely
SSH certificates
issued by an internal SSH CA scale trust management to thousands of hosts without distributing individual public keys. Each server trusts the CA, not individual user keys -- revoking access means removing the certificate, not hunting down authorized_keys files across every host

SponsoredRetool

Retool's new app builder is where AI-generated code ships safely

Building apps with AI is easy. Getting them to production safely is another story.

Start building for free today

SSH is the remote administration protocol for nearly every Linux server in existence. A misconfigured sshd is one of the most reliable initial access and lateral movement paths in an enterprise Linux environment: password auth means credential stuffing works, root login means no privilege escalation is needed, and weak algorithms mean connections can be monitored or downgraded. The good news is all of it is configurable in one file: /etc/ssh/sshd_config. This guide covers the settings in order of impact.

The Core sshd_config Hardening Settings

Edit /etc/ssh/sshd_config (or drop a file in /etc/ssh/sshd_config.d/ on distributions that support include directories):

# Disable root login -- use sudo from a named account
PermitRootLogin no

# Disable password authentication -- keys or certificates only
PasswordAuthentication no
ChallengeResponseAuthentication no
KbdInteractiveAuthentication no

# Disable empty passwords (should be default but make it explicit)
PermitEmptyPasswords no

# Limit SSH to protocol 2 only (protocol 1 has cryptographic flaws)
Protocol 2

# Restrict to specific groups or users
AllowGroups ssh-users admins
# Or by user:
# AllowUsers alice bob carol

# Set idle session timeout
ClientAliveInterval 300
ClientAliveCountMax 2
# Disconnects idle sessions after 300 seconds * 2 = 10 minutes of no activity

# Limit authentication attempts per connection
MaxAuthTries 3

# Limit open sessions per connection
MaxSessions 4

# Disable X11 forwarding unless required
X11Forwarding no

# Disable TCP forwarding if not needed (blocks SSH tunneling abuse)
AllowTcpForwarding no
GatewayPorts no

# Disable agent forwarding to prevent credential forwarding attacks
AllowAgentForwarding no

# Log at verbose level for forensics
LogLevel VERBOSE

# Banner for legal notice
Banner /etc/ssh/banner.txt

After editing, validate syntax before reloading:

sshd -t && systemctl reload sshd
# sshd -t exits 0 on no errors, non-zero on syntax errors
# Never restart sshd without -t check -- a syntax error will lock you out

Algorithm Hardening: Remove Weak Ciphers and MACs

Older OpenSSH versions enable weak algorithms for backward compatibility. Remove them:

# Restrict key exchange algorithms to modern elliptic curve methods
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512

# Restrict symmetric ciphers to AES-GCM and ChaCha20 (AEAD ciphers, no separate MAC needed)
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr

# Restrict MACs to HMAC-SHA2 (remove MD5 and SHA1 variants)
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256

# Restrict host key types
HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,rsa-sha2-512,rsa-sha2-256

# Restrict public key algorithms accepted from clients
PubkeyAcceptedAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,rsa-sha2-512,rsa-sha2-256

Verify active algorithms from the client:

ssh -vvv user@host 2>&1 | grep 'kex:'
# Should show only the algorithms from your configured list

For RSA host keys, ensure minimum key size is 4096 bits. Regenerate if needed:

rm /etc/ssh/ssh_host_rsa_key*
ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N ''
# Prefer Ed25519 for new keys:
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ''
Free daily briefing

Briefings like this, every morning before 9am.

Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.

Set Up an SSH Certificate Authority for Scalable Key Management

Distributing individual user public keys to authorized_keys files across hundreds of servers does not scale and creates a key sprawl problem -- former employees' keys persist until manually removed.

SSH certificates solve this: users present a certificate signed by a trusted CA; servers trust the CA. To revoke a user's access, you stop issuing them certificates. No authorized_keys cleanup required.

Create the SSH CA (keep the CA private key offline or in a vault):

# Generate the CA key pair (do this on an offline/secure machine)
ssh-keygen -t ed25519 -f /secure/ssh-ca -C 'Enterprise SSH CA'
# Store /secure/ssh-ca (private) in your vault
# Distribute /secure/ssh-ca.pub to all servers

Configure servers to trust the CA:

# On each server, copy the CA public key
cp ssh-ca.pub /etc/ssh/trusted_user_ca_keys
# Add to sshd_config:
TrustedUserCAKeys /etc/ssh/trusted_user_ca_keys
# Remove AuthorizedKeysFile if migrating fully to certificates:
# AuthorizedKeysFile none

Issue a certificate for a user:

# Sign the user's public key with the CA
ssh-keygen -s /secure/ssh-ca \
    -I 'alice@company.com' \
    -n alice \
    -V +8h \
    /home/alice/.ssh/id_ed25519.pub
# Creates id_ed25519-cert.pub with 8-hour validity
# -n sets the principal (username the cert is valid for)
# Short validity forces re-issuance, acting as implicit revocation

For enterprise scale, use a certificate signing service (HashiCorp Vault SSH Secrets Engine, Teleport, or a custom signing endpoint) rather than signing certificates manually.

Audit and Enforce sshd Configuration Across the Fleet

After hardening, verify that the settings are actually active and have not drifted:

On a single host:

# Dump all active sshd settings
sshd -T | grep -E 'permitrootlogin|passwordauthentication|allowgroups|clientaliveinterval|maxauthtries|x11forwarding|allowtcpforwarding'
# sshd -T shows the full compiled config including defaults -- use this, not grep on sshd_config

Across a fleet (Ansible):

- name: Verify SSH hardening settings
  command: sshd -T
  register: sshd_config

- name: Assert PermitRootLogin is no
  assert:
    that: "'permitrootlogin no' in sshd_config.stdout"

- name: Assert PasswordAuthentication is no
  assert:
    that: "'passwordauthentication no' in sshd_config.stdout"

CIS Benchmark check with Lynis:

lynis audit system
# Lynis checks all CIS SSH configuration requirements and reports pass/fail
# Focus on the SSH section of the lynis report output

Monitor for unauthorized sshd_config changes:

# File integrity monitoring rule (auditd)
auditctl -w /etc/ssh/sshd_config -p wa -k sshd_config_change
auditctl -w /etc/ssh/sshd_config.d/ -p wa -k sshd_config_change
# Alert on Event: key=sshd_config_change in your SIEM

The bottom line

The four settings that eliminate the majority of SSH attack surface: PermitRootLogin no, PasswordAuthentication no, AllowGroups restricting to the minimum necessary group, and ClientAliveInterval with MaxAuthTries for session and brute-force limits. Add algorithm hardening to eliminate weak cipher negotiation. For environments with more than 50 servers, SSH certificate authorities provide scalable key management that makes access revocation immediate and auditable. Always validate with sshd -t before reloading, and use sshd -T to audit the compiled active configuration rather than grep on the config file.

Frequently asked questions

What is the most important sshd_config setting to change first?

PermitRootLogin no is the highest priority because it eliminates the scenario where a brute force or key compromise immediately grants root access. However, make sure you have a working sudo-capable user account before disabling root login or you will lock yourself out. The second most important setting is PasswordAuthentication no, which eliminates brute force and credential stuffing as viable attack vectors. Ensure every user who needs SSH access has an authorized key in place before enabling this, or you will also lock yourself out.

Should I change the SSH port from 22 to something else?

This is security through obscurity and is a low-value control. Changing the port reduces automated scanner noise (Shodan and similar scan port 22 continuously) but any targeted attacker will find your SSH port with a simple port scan. The time investment is better spent on key-only authentication and AllowGroups configuration. If you do change the port as an additional noise reducer, update your firewall rules and document it clearly -- non-standard SSH ports frequently cause self-inflicted outages during incidents when responders cannot reach systems. If you change the port, use a number above 1024 that is not assigned to another service.

What is the difference between authorized_keys and SSH certificates?

authorized_keys files list specific public keys that are allowed to authenticate to a given account. They must be distributed and maintained on every server for every user. SSH certificates are time-limited credentials signed by a CA -- servers trust the CA, not individual keys. Certificates can include expiry times (8 hours, 24 hours) and principals (which accounts the certificate is valid for). When a user leaves, you stop issuing them certificates and any existing certificates expire -- no need to remove authorized_keys entries from every server. For small environments with a handful of servers and stable users, authorized_keys is simpler. For environments with more than 20 servers or frequent user turnover, certificate authorities reduce operational overhead significantly.

Will AllowGroups break sudo or system service SSH access?

Yes, if not configured carefully. AllowGroups restricts which users can establish interactive SSH sessions. System service accounts that connect via SSH (backup agents, monitoring tools, automated deployment systems) must be in an allowed group or their SSH connections will fail. Before enabling AllowGroups, audit which accounts are used for automated SSH connections using the SSH auth log (grep Accepted /var/log/auth.log or journalctl -u sshd). Add service accounts to a dedicated group (ssh-services) and include that group in AllowGroups alongside your human user groups.

How do I detect SSH brute force attempts in logs?

The primary log source is /var/log/auth.log (Debian/Ubuntu) or /var/log/secure (RHEL/CentOS), or journalctl -u sshd on systemd systems. Alert on: five or more 'Failed password' or 'Invalid user' log entries from the same source IP in a five-minute window (brute force). Also alert on 'Accepted publickey' from a new source IP or unusual time (legitimate authentication from unexpected location). If you have MaxAuthTries set to 3 and the log shows 50 failed attempts from one IP, sshd disconnected and they reconnected 17 times -- also worth alerting on, as it indicates an automated tool.

How do I implement SSH certificate-based authentication and why is it better than SSH key pairs?

SSH certificates are signed public keys that include metadata: the principal (username or host) the certificate is valid for, a validity period, and the signing CA's identity. Unlike static key pairs, certificates expire automatically and carry authorization scope within the certificate itself. Setup: generate a CA key pair (`ssh-keygen -t ed25519 -f ssh_ca`), distribute the CA public key to all servers via sshd_config (`TrustedUserCAKeys /etc/ssh/trusted_ca.pub`), and issue certificates to users by signing their public keys (`ssh-keygen -s ssh_ca -I username -n username -V +8h ~/.ssh/id_ed25519.pub`). Advantages over key pairs: certificates expire automatically (no stale keys accumulate on servers), revocation is immediate (update the CRL or set a short validity period), access scope is embedded in the certificate (a certificate signed for 'developer' principal cannot be used as 'admin' even on the same server), and onboarding/offboarding does not require distributing keys to individual servers. Hashicorp Vault's SSH secrets engine automates certificate signing with configurable role-based principals and validity periods, integrating with your identity provider for authentication before issuing certificates.

Sources & references

  1. OpenSSH: sshd_config man page
  2. CIS: Linux Benchmark SSH configuration section
  3. NIST SP 800-53: AC-17 Remote Access controls

Free resources

25
Free download

Critical CVE Reference Card 2025–2026

25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.

No spam. Unsubscribe anytime.

Free download

Ransomware Incident Response Playbook

Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.

No spam. Unsubscribe anytime.

Free newsletter

Get threat intel before your inbox does.

50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.

Unsubscribe anytime. We never sell your data.

Eric Bang
Author

Founder & Cybersecurity Evangelist, Decryption Digest

Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.

Black Hat Giveaway

Win a $2,495 Black Hat pass.

Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.

Joins Decryption Digest daily briefing. Unsubscribe anytime.

Giveaway: Black Hat USA 2026 Full-Access Pass ($2,495 value)

Details →
Daily Briefing

Subscribe to enter the giveaway

Every subscriber is automatically entered. You also get daily threat intel every morning: zero-days, ransomware, and nation-state campaigns. Free. No spam.

Already subscribed? You're already entered.

Giveaway

Win a $2,495 Black Hat USA 2026 pass.