# SSH hardening - закрытие сервера _Безопасность · LinuxLab Knowledge Base_ **TL;DR:** SSH hardening: ключи only (PasswordAuthentication no), отключить root-login, AllowUsers/AllowGroups, MaxAuthTries, fail2ban-jail на sshd. Опционально - нестандартный порт + Match-блоки для гостей. ## Зачем 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`): ```ini # ===== Аутентификация ===== 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) ``` Применить: ```bash sshd -t # синтаксис-чек systemctl reload sshd ``` **Не закрывай сразу свою активную сессию!** Открой второй SSH-терминал и проверь, что новые подключения проходят. ## Ключи only Сгенерируй сильный ключ: ```bash ssh-keygen -t ed25519 -a 100 -C "alice@laptop" # ed25519 - современный, короткий, быстрый # -a 100 - 100 KDF rounds для защиты passphrase'ом ``` Скопируй на сервер: ```bash ssh-copy-id alice@server # автоматически # или вручную: cat ~/.ssh/id_ed25519.pub | ssh alice@server 'cat >> ~/.ssh/authorized_keys' ``` Права обязательно: ```bash 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 подписывает короткоживущие сертификаты: ```bash # На 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-блоки Условные правила: ```ini # 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 портов. Но **уменьшает мусор в логах**: ```ini 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](/kb/fail2ban.md) читает auth.log, после N failed-попыток баннит IP в iptables/nftables. `/etc/fail2ban/jail.local`: ```ini [DEFAULT] bantime = 1h findtime = 10m maxretry = 5 banaction = nftables backend = systemd [sshd] enabled = true port = ssh filter = sshd logpath = %(sshd_log)s maxretry = 3 ``` ```bash 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 ступень не сработает: ```ini # 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. ## Аудит существующего конфига Утилиты: ```bash 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](/kb/kerberos.md). Также `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 ## Команды ```bash sshd -t ``` Синтаксис-проверка конфига перед reload - всегда ДО systemctl ```bash sshd -T | grep -iE 'permitroot|password|kex' ``` Эффективный конфиг с учётом Match-блоков и defaults ```bash ssh-keygen -t ed25519 -a 100 -C 'alice@laptop' ``` Сгенерить современный ключ с защитой passphrase'ом 100 раундов ```bash ssh-copy-id -i ~/.ssh/id_ed25519.pub alice@server ``` Скопировать pub-ключ в authorized_keys с правильными mode ```bash fail2ban-client status sshd ``` Кто сейчас в бане - для отладки 'не могу войти после смены IP' ```bash ssh-keygen -s ca_key -I 'alice-$(date +%F)' -n alice -V +24h pubkey.pub ``` Подписать ключ юзера CA на сутки - SSH-CA workflow ```bash journalctl -u sshd --since '10 min ago' ``` Логи sshd - failed-попытки, ключевые события, GSSAPI-ошибки ## См. также - [SSH - secure shell](/kb/ssh.md) - [fail2ban - автобан по логам](/kb/fail2ban.md) - [PAM - Pluggable Authentication Modules](/kb/pam.md) - [auditd - syscall и file audit](/kb/auditd.md) - [Kerberos - сетевой single sign-on](/kb/kerberos.md) - [TLS-сертификаты - X.509, цепочка доверия, Let's Encrypt](/kb/tls-certificates.md) - [Управление секретами - Vault, k8s Secrets, sealed-secrets](/kb/secrets-management.md) - [CIS Benchmark и system hardening (lynis, OpenSCAP)](/kb/cis-benchmark-hardening.md) - [GPG/PGP - подпись, шифрование, web of trust](/kb/gpg-pgp.md)