Skip to content
Categoria: Hardening8 min read

SSH Hardening 2026: Algorithms, Certificates and Bastion Hosts

Por Lucas Andrade ·

Modern SSH configuration with an internal CA, resistant algorithms and auditable bastion hosts to shrink the attack surface in corporate environments.

SSH Hardening 2026: Algorithms, Certificates and Bastion Hosts

Every time we open shodan.io and filter by port:22 we still find hundreds of thousands of servers accepting ssh-rsa with SHA-1, password authentication exposed straight to the internet and MACs like hmac-sha1. In 2026 that is not forgotten legacy configuration: it is technical debt paying interest in the form of incidents. SSH hardening stopped being a six-line checklist in sshd_config and became a small subsystem covering an internal certificate authority, an auditable bastion, short-lived key material and centralized telemetry. This guide walks the whole stack the way the Basilisk team builds it in a lab before shipping to production, with concrete configuration, real commands and the failure modes we keep hitting.

Why SSH is still the attacker's favorite door

SSH is the remote-management protocol for essentially all of Linux and most network gear, which makes it the highest-value credential in the estate. Attackers love it because a single working key or password grants an interactive shell with the privileges of the target account, no exploit chain required. The three recurring root causes are: reused or never-rotated keys that outlive the employee who created them, password authentication brute-forced from botnets, and downgrade to weak algorithms that let a network attacker tamper with the handshake. Treat SSH as an identity system, not a utility. Every design decision below reduces one of those three classes, and the sequence matters: fix authentication before you fix telemetry, because logging a breach you cannot prevent only tells you when you lost.

Baseline sshd_config that is not negotiable

Start with the server daemon. In a modern /etc/ssh/sshd_config force PasswordAuthentication no, KbdInteractiveAuthentication no, PermitRootLogin no, UsePAM yes and PermitEmptyPasswords no. Add MaxAuthTries 3, LoginGraceTime 20 and ClientAliveInterval 300 so half-open sessions die. Constrain reach with AllowGroups ssh-users instead of allowing every local account. Validate the file before reloading with sshd -t, and never edit the live port without a second session open, because a typo in a Match block can lock you out. These directives are the floor; none of them cost anything and all of them remove an attack primitive.

Modern algorithms and post-quantum key exchange

Restrict KexAlgorithms to sntrup761x25519-sha512@openssh.com,curve25519-sha256, Ciphers to chacha20-poly1305@openssh.com,aes256-gcm@openssh.com and MACs to hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com. The sntrup761 hybrid has shipped post-quantum resistance since OpenSSH 9.0, and in 2026 there is no reason not to enable it: it protects today's captured traffic against tomorrow's quantum decryption, the harvest-now-decrypt-later problem. Run ssh-audit against the host before and after. The gap between a C+ and an A grade is essentially removing diffie-hellman-group14-sha1, CBC ciphers and truncated MACs. Prefer etm (encrypt-then-MAC) variants because they authenticate the ciphertext, not the plaintext. Treat passing ssh-audit as a prerequisite, not a deliverable.

Replace scattered keys with an internal SSH CA

The real maturity jump comes when you retire authorized_keys files and issue certificates. Generate a CA keypair (ssh-keygen -t ed25519 -f ssh_user_ca) whose private half lives only in an HSM or an offline signer, then sign user certificates with a short TTL of 4 to 12 hours: ssh-keygen -s ssh_user_ca -I alice@corp -n alice -V +8h user_key.pub. On every server you distribute only the CA public key via TrustedUserCAKeys /etc/ssh/ca.pub. Users authenticate with a certificate issued by step-ca, HashiCorp Vault SSH or Teleport, bound to corporate SSO. Revoking a former employee stops being a hunt for keys across 400 hosts and becomes simply not reissuing the certificate. In internal pentests this single change breaks roughly half the lateral-movement paths that rely on orphaned keys, because the stolen key is worthless once its certificate has expired.

The bastion as an identity proxy, not a jump box

A hardened bastion is not just any Linux box with SSH open. Treat it as an identity proxy: it accepts the user connection, validates the certificate against the CA, records the full session (input and output) and opens a second SSH to the target via ProxyJump. Teleport, HashiCorp Boundary and the step-ca + auditd + tlog combination all cover this. In a typical fintech setup the bastion lived in an isolated VPC whose Security Group allowed only port 22 from the corporate VPN, and internal servers rejected any SSH not originating from the bastion CIDR. That collapses the attack surface from hundreds of internet-reachable IPs to a single monitored chokepoint where every keystroke is logged and every session is attributable to a human identity.

Client-side hardening and hardware-backed keys

Do not forget the client. Enforce ~/.ssh/config with HashKnownHosts yes, VerifyHostKeyDNS yes where applicable, and generate a hardware-backed key with ssh-keygen -t ed25519-sk so the private half never leaves a YubiKey and every authentication needs a physical touch. Run ssh-agent with confirmation (ssh-add -c) so a compromised workstation cannot silently reuse the agent socket. Disable options you do not need: AllowAgentForwarding no and AllowTcpForwarding no at the server unless a documented flow requires them, because agent forwarding to an untrusted host lets that host hijack your agent for as long as the socket is live.

CI/CD and service keys without long-lived secrets

Machine identities are where hardened human access usually leaks back in. Ban static keys in CI. Instead, issue short certificates via GitHub Actions or GitLab OIDC against your Vault, so a pipeline receives a certificate valid for minutes, scoped to the exact host it must reach. This eliminates the whole class of incidents where a key leaked in a build log stays valid for years. For deploy targets, use Match blocks that pin a service certificate to a single command with ForceCommand and PermitOpen, turning a general shell into a narrow, auditable action that cannot be repurposed into interactive access.

Centralized logging and detections that actually fire

Logging closes the loop. Set LogLevel VERBOSE in sshd so key fingerprints are recorded, ship /var/log/auth.log through journald-remote or Fluent Bit into Elastic or Loki, and write Sigma rules for the patterns that matter: repeated failures followed by a success from the same source, a login with a certificate expiring in under an hour, a certificate principal that does not match the SSO user, or suspicious commands captured by session recording. In one red-team simulation it took 11 minutes to get caught reusing a stolen key precisely because the certificate principal did not match the SSO identity, and the correlation rule alerted. Without that correlation it would have been days. SSH is one of the richest and most underused telemetry sources you own.

Common pitfalls that quietly undo your hardening

The recurring mistakes: leaving PermitRootLogin prohibit-password and calling it done while a shared root key still exists; hardening the daemon but leaving ~/.ssh/authorized_keys writable by the user so any code execution re-adds a key; forgetting that Match blocks are evaluated top-down and a broad early match shadows a strict later one; and rotating host keys without updating known_hosts distribution, which trains users to click through host-key warnings. Another silent killer is an unbounded MaxStartups that lets a connection flood exhaust the daemon. Audit these explicitly; none of them show up as an error, they just leave the door ajar.

Hardening checklist

Before you call a host hardened, verify: ssh-audit grade A; password and keyboard-interactive auth disabled; root login off; only modern KEX, cipher and MAC; CA-issued certificates with TTL under 12 hours; TrustedUserCAKeys set and no stray authorized_keys; bastion-only ingress enforced at the network layer; session recording on; VERBOSE logs shipped and at least three Sigma rules live; hardware-backed client keys; no static keys in CI; and an emergency runbook that can revoke and reissue the entire fleet in under an hour. If any line is unchecked, the host is not done.

FAQ: Is certificate-based SSH overkill for a small team?

No. Even at five engineers, an internal CA removes the single worst operational risk, orphaned keys, and takes an afternoon with step-ca. The break-even is not fleet size, it is the moment a second person needs access to a second host, because that is when manual authorized_keys management starts drifting. Start with an 8-hour TTL tied to your identity provider and grow from there.

FAQ: Does enabling sntrup761 break older clients?

Clients on OpenSSH older than 9.0 will not negotiate the hybrid KEX and simply fall back to curve25519-sha256, which is why you keep it in the list. The practical answer is to upgrade clients: any workstation still on an OpenSSH that predates 9.0 is overdue for patching for unrelated reasons. Keep the post-quantum KEX first in preference order so modern clients get it automatically.

Practical takeaway: build a lab with three VMs (CA, bastion, target) using step-ca, set an 8-hour TTL, force the modern algorithms, run ssh-audit until you hit A, then try to log in with an old key. If you get in, the config is not hardened yet. Repeat quarterly, rotate the CA key annually, and keep the emergency runbook tested. SSH remains the favorite door for attackers in 2026 precisely because we treat it as invisible infrastructure. Stop treating it that way.

Related posts

Nenhum comentário ainda

Seja o primeiro a comentar.

Deixe seu comentário

Entre com sua conta Canverly para comentar. Você pode usar a mesma conta em qualquer site da rede.

Entrar com Canverly