Зачем
SSH, основной вектор атак на Linux-сервера. Бот-сети брутфорсят
его круглосуточно: на любом publicly-routable IP с открытым 22 портом
через сутки в auth.log, тысячи попыток. Дефолтная конфигурация
OpenSSH для прода слишком открытая:
- Разрешён root-login по паролю
- Пароли разрешены в принципе
- Все пользователи могут подключаться
- Нет rate-limit на попытки
- X11 forwarding включён
Этот документ, рецепты "по умолчанию выключить".
Минимальный hardening, что менять в sshd_config
/etc/ssh/sshd_config (или drop-in /etc/ssh/sshd_config.d/00-hardening.conf):
# ===== Аутентификация =====
PermitRootLogin no # никогда root напрямую
PasswordAuthentication no # только ключи
ChallengeResponseAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey # только ключ; для 2FA: publickey,keyboard-interactive
# ===== Кто пускается =====
AllowUsers alice bob carol # whitelist
# ИЛИ через группу
AllowGroups ssh-users
# ===== Ограничение попыток =====
MaxAuthTries 3
MaxSessions 5
LoginGraceTime 30 # отключить если не аутентифицировался за 30s
# ===== Идентификация сервера =====
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
# ===== Cipher / KEX =====
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com
# ===== Forwarding =====
X11Forwarding no
AllowAgentForwarding no # включить только где надо
AllowTcpForwarding no # для bastion-host'ов yes
PermitTunnel no
GatewayPorts no
# ===== Прочее =====
PermitEmptyPasswords no
ClientAliveInterval 300
ClientAliveCountMax 2 # 10 минут idle = disconnect
Banner /etc/issue.net # legal warning
PrintLastLog yes
UseDNS no # ускоряет login (не делать reverse-DNS)
Применить:
sshd -t # синтаксис-чек
systemctl reload sshd
Не закрывай сразу свою активную сессию! Открой второй SSH-терминал и проверь, что новые подключения проходят.
Ключи only
Сгенерируй сильный ключ:
ssh-keygen -t ed25519 -a 100 -C "alice@laptop"
# ed25519 - современный, короткий, быстрый
# -a 100 - 100 KDF rounds для защиты passphrase'ом
Скопируй на сервер:
ssh-copy-id alice@server # автоматически
# или вручную:
cat ~/.ssh/id_ed25519.pub | ssh alice@server 'cat >> ~/.ssh/authorized_keys'
Права обязательно:
ssh -o LogLevel=DEBUG alice@server # покажет если authorized_keys mode 644 + group/other = drop
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
SSH Certificate Authority, масштабирование ключей
Раздавать ключи 100 серверам каждому юзеру, не масштабируется. SSH-CA подписывает короткоживущие сертификаты:
# На CA-машине (изолированной)
ssh-keygen -t ed25519 -f ssh_ca_key
# Раздать публичный ключ CA на все сервера в /etc/ssh/ca.pub
# В sshd_config:
TrustedUserCAKeys /etc/ssh/ca.pub
# Подписать ключ юзера
ssh-keygen -s ssh_ca_key -I "alice-2026-05-01" -n alice -V +1d ~/.ssh/id_ed25519.pub
▸создаст id_ed25519-cert.pub
Сервера принимают любого, чей ключ подписан CA. Срок действия
встроен в сертификат. Revocation через RevokedKeys.
Используется в Facebook, Netflix, Uber. Для 1-2 серверов overkill, для 100+, must-have.
Match-блоки
Условные правила:
# SFTP-only юзеры
Match Group sftponly
ChrootDirectory /var/sftp/%u
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
# Bastion: разрешить TCP-forwarding только из определённой сети
Match Address 10.0.0.0/24
AllowTcpForwarding yes
PermitTunnel yes
# Запретить login от deploy-юзера снаружи corp-сети
Match User deploy Address !10.0.0.0/8,!172.16.0.0/12
DenyUsers *
Нестандартный порт, security through obscurity?
Изменение Port 22 → Port 2222 не делает SSH защищённее.
Бот'ы сканируют все 65535 портов. Но уменьшает мусор в логах:
Port 2222
Не забудь:
- Открыть 2222 в фаерволе
- Закрыть 22
- Обновить SELinux на RHEL:
semanage port -a -t ssh_port_t -p tcp 2222 - Обновить fail2ban-jail
- Сообщить клиентам (
~/.ssh/configилиPort 2222в команде)
Я бы оставил 22 + fail2ban, а нестандартный порт, для bastion-host'ов где много автоматики.
fail2ban-jail для sshd
fail2ban читает auth.log, после N failed-попыток баннит IP в iptables/nftables.
/etc/fail2ban/jail.local:
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
banaction = nftables
backend = systemd
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = %(sshd_log)s
maxretry = 3
systemctl restart fail2ban
fail2ban-client status sshd
fail2ban-client unban 1.2.3.4 # разбанить вручную
2FA через PAM
Сделать sshd требующим Google Authenticator или Yubikey помимо ключа.
Внимание: baseline-конфиг выше отключает KbdInteractiveAuthentication
и ChallengeResponseAuthentication. Для 2FA эти строки надо убрать
(или поставить yes), иначе keyboard-interactive ступень не сработает:
# sshd_config
AuthenticationMethods publickey,keyboard-interactive
KbdInteractiveAuthentication yes # отменяет запрет из baseline
ChallengeResponseAuthentication yes
UsePAM yes
В /etc/pam.d/sshd:
auth required pam_google_authenticator.so nullok
И каждый юзер запускает google-authenticator для генерации QR.
Аудит существующего конфига
Утилиты:
ssh-audit example.com # внешняя проверка cipher/kex/host-key
sshd -T # эффективный конфиг (после Match)
sshd -T | grep -iE 'permitroot|password|kex|cipher|mac|maxauth'
Когда что-то пошло не так
Permission denied (publickey), ключ не вauthorized_keys, либо неверные mode на~/.ssh(нужно 700) иauthorized_keys(600).- Закрыл себе SSH меняя конфиг, поставь второй активный SSH-сеанс ДО reload. Если уже поздно, console/IPMI/ILO/cloud-консоль. На облаках есть serial-console через CLI.
no matching host key type found, отключил RSA, у клиента только RSA. ДобавьHostKey /etc/ssh/ssh_host_rsa_keyобратно или попроси клиента обновить openssh.no matching cipher found: client offers, старый клиент, cipher не в твоём whitelist. Проверьsshd -T | grep cipher.fail2banбаннит самого себя, твой IP попал в jail. Whitelist черезignoreip = 127.0.0.1/8 10.0.0.0/24 my.public.ip/32.- GSSAPI/Kerberos handshake тормозит login, выключи
GSSAPIAuthentication noесли не используешь kerberos. ТакжеUseDNS no. - Match-блок не применяется, Match parsed по порядку, первый match выигрывает. И Match-блок заканчивается следующим Match или EOF.
Чек-лист
- PermitRootLogin no
- PasswordAuthentication no
- AllowUsers/Groups whitelist
- MaxAuthTries ≤ 3
- X11Forwarding no (если не нужен)
- fail2ban-jail включён
- ed25519 host-key и client-key
- Modern KEX/Cipher/MAC, без legacy
- Banner с legal-warning
- sshd -T → проверка эффективной конфигурации
- Сертификаты SSH-CA если 5+ серверов
- auditd-watch на sshd_config