SSH: sshd hardening на FreeBSD і Linux, та інтеграція з 1Password

Автор |  28/12/2025
Click to rate this post!
[Total: 0 Average: 0]

Прийшов час трохи привести в порядок SSH на самому FreeBSD та на клієнтах – ноутбуках з Arch Linux, бо на домашніх машинках досі використовую парольну аутентифікацію.

Власне, описані нижче налаштування не специфічні ні для FreeBSD, ні для Linux, бо SSH server один і той самий на всіх системах (OpenSSH_9.9p2 на FreeBSD 14.3 і OpenSSH_10.2p1 на Arch Linux).

1Password користуюсь вже давно, класна інтеграція і GUI, хоча паралельно є локальний KeePassXC, в який до окремої бази періодично бекаплю дані із 1Password – див. How to export your data from the 1Password desktop app та Migrating from 1Password to KeePass, KeePassXC and KeePassium.

Це пост – частина серії по сетапу домашнього NAS на FreeBSD (див. початок у FreeBSD: Home NAS, part 1 – налаштування ZFS mirror), але вирішив його зробити окремою темою, бо тут виключно про SSH.

Що маю в поточному сетапі:

  • хост з FreeBSD/NAS: доступний тільки в локальній мережі і VPN, тому SSH brute force не очікується (але при параної або на публічно доступних серверах можна додати Fail2Ban чи SSHGuard)
  • pf firewall: як перша лінія захисту з лімітом того, звідки SSH доступний (див. FreeBSD: Home NAS, part 2 – знайомство з Packet Filter (PF) firewall)
  • sshd: друга лінія захисту, базові налаштування доступу

SSH та аутентифікація по ключам

Перше і основне – це налаштувати доступ по ключам замість парольної аутентифікації.

Зробимо це, потім доступ по паролям відключимо взагалі.

На клієнті, ноутбуці з Linux, створюємо ключі:

[setevoy@setevoy-work ~] $ ssh-keygen -t ed25519 -C "setevoy@setevoy"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/setevoy/.ssh/id_ed25519): /home/setevoy/.ssh/freebsd-nas
Enter passphrase for "/home/setevoy/.ssh/freebsd-nas" (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/setevoy/.ssh/freebsd-nas
Your public key has been saved in /home/setevoy/.ssh/freebsd-nas.pub

Копіюємо на хост з FreeBSD:

[setevoy@setevoy-work ~] $ ssh-copy-id -i /home/setevoy/.ssh/freebsd-nas [email protected]
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/setevoy/.ssh/freebsd-nas.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
([email protected]) Password for setevoy@setevoy-nas:

Number of key(s) added: 1

Now try logging into the machine, with: "ssh -i /home/setevoy/.ssh/freebsd-nas '[email protected]'"
and check to make sure that only the key(s) you wanted were added.

Перевіряємо файл ~/.ssh/authorized_keys на FreeBSD у юзера setevoy:

root@setevoy-nas:/home/setevoy # cat .ssh/authorized_keys 
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILb2zkJzflngGx0qY71xYyHVvKI8A2GTAGTqppS0yVz2 setevoy@setevoy

Пробуємо підключення з Linux:

[setevoy@setevoy-work ~]  $ ssh -i /home/setevoy/.ssh/freebsd-nas '[email protected]'
Last login: Sat Dec 27 09:01:47 2025 from 192.168.0.4
FreeBSD 14.3-RELEASE (GENERIC) releng/14.3-n271432-8c9ce319fef7

Welcome to FreeBSD!

...
[setevoy@setevoy-nas ~]$ 

Все працює – можна налаштувати SSH Agent.

FreeBSD та 1Password client

Тут просто для приклада – установка і підключення клієнта 1Password на FreeBSD.

Встановлюємо:

root@setevoy-nas:/home/setevoy # pkg install -y 1password-client2

Додаємо акаунт:

root@setevoy-nas:/home/setevoy # op account add
Enter your sign-in address (example.1password.com): my.1password.com            
Enter the email address for your account on my.1password.com: <ACCOUNT_EMAIL>
Enter the Secret Key for [email protected] on my.1password.com: <SECRET_KEY>
Enter the password for [email protected] at my.1password.com: 
Enter your six-digit authentication code: <OTP_CODE>
Now run 'eval $(op signin)' to sign in.

Перевіряємо акаунти:

root@setevoy-nas:/home/setevoy # op account list
SHORTHAND    URL                         EMAIL            USER ID
my           https://my.1password.com    [email protected]     7BS***KMM

Логінимось:

root@setevoy-nas:/home/setevoy # eval $(op signin)
Enter the password for [email protected] at my.1password.com:

І маємо доступ до сікретів.

Наприклад, отримати ключ, який додамо далі:

root@setevoy-nas:/home/setevoy # op item get "FreeBSD NAS SSH"
ID:          ulz***4ce
Title:       FreeBSD NAS SSH
Vault:       Personal (wb7***guq)
Created:     1 week ago
Updated:     1 week ago by Arseny
Favorite:    false
Tags:        FreeBSD,SSH
Version:     1
Category:    LOGIN
Fields:
  password:    [use 'op item get ulz***4ce --reveal' to reveal]
  username:    setevoy

Linux, 1Password та SSH Agent

Колись більш детально писав в пості SSH: RSA-ключи и ssh-agent – управление SSH-ключами и их паролями (2019 рік), але так як зараз активно користуюсь 1Password, який вміє як зберігати самі ключі – так і виступати в ролі SSH Agent.

Документація – 1Password SSH agent та Get started with 1Password for SSH.

Отримуємо приватний ключ:

[setevoy@setevoy-work ~] $ cat .ssh/freebsd-nas
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
...
vKI8A2GTAGTqppS0yVz2AAAAD3NldGV2b3lAc2V0ZXZveQECAwQFBg==
-----END OPENSSH PRIVATE KEY-----

Копіюємо, і додаємо новий ключ в 1Password (хоча він може генерувати ключі сам):

Переходимо в Settings:

Переходимо в Developer – Set up the SSH Agent:

1Password покаже зміст файлу ~/.ssh/config і навіть запропонує оновити його:

Але в мене зараз в конфігу вже є трохи налаштувань:

# GitHub.com
Host github.com
  PreferredAuthentications publickey
  IdentityFile /home/setevoy/.ssh/setevoy_main_priv_openssh

ExitOnForwardFailure yes

Тому додаємо в кінець файлу вручну.

Вказуємо два хости – nas.setevoy та, на випадок, якщо Unbound недоступний, то IP-адресу хоста з FreeBSD:

...

Host nas.setevoy 192.168.0.2
  IdentityAgent ~/.1password/agent.sock

Виконуємо ssh nas.setevoy, 1Password запросить підтвердження – пароль самого 1Password:

І тепер все працює через його SSH Agent:

[setevoy@setevoy-work ~] $ ssh nas.setevoy
...
Last login: Sat Dec 27 09:03:15 2025 from 192.168.0.4
FreeBSD 14.3-RELEASE (GENERIC) releng/14.3-n271432-8c9ce319fef7

Welcome to FreeBSD!

...
[setevoy@setevoy-nas ~]$ 

Як працює SSH Agent

При підключені SSH-клієнт:

  • читає конфігурацію (~/.ssh/config, опції CLI)
  • підключається до SSH-агента (у нашому випадку 1Password) і отримує список доступних публічних ключів
  • по черзі пропонує серверу публічні ключі, які в нього є (з агента і, за відсутності обмежень, з ~/.ssh/)
  • sshd на сервері дивиться в ~/.ssh/authorized_keys конкретного юзера і перевіряє, чи є там запропонований публічний ключ
  • коли сервер знаходить збіг, він приймає цей публічний ключ і надсилає клієнту дані для підпису (випадковий набір чисел)
  • клієнт передає ці дані SSH-агенту, який володіє відповідним приватним ключем
  • агент створює криптографічний підпис приватним ключем і повертає його клієнту
  • сервер перевіряє підпис публічним ключем і завершує аутентифікацію

Глянути це можемо з ssh -v user@host:

[setevoy@setevoy-work ~] $ ssh -v [email protected]
debug1: OpenSSH_10.2p1, OpenSSL 3.6.0 1 Oct 2025
debug1: Reading configuration data /home/setevoy/.ssh/config
...
debug1: Connecting to nas.setevoy [192.168.0.2] port 22.
debug1: Connection established.
...
debug1: Authenticating to nas.setevoy:22 as 'setevoy'
...
debug1: Will attempt key: RTFM RSA SHA256:nedb3Qgpkxgu57MRP7/eXShHgw6N6b7SjZ3S1rNyFb4 agent
debug1: Will attempt key: FreeBSD-NAS ED25519 SHA256:ZuJ77z6BNMwra41BiTKDrJSSQrDJ0/u+4wZRCvGJMpA agent
debug1: Will attempt key: /home/setevoy/.ssh/id_rsa 
debug1: Will attempt key: /home/setevoy/.ssh/id_ecdsa 
debug1: Will attempt key: /home/setevoy/.ssh/id_ecdsa_sk 
debug1: Will attempt key: /home/setevoy/.ssh/id_ed25519 ED25519 SHA256:X8L1lCBQz8Bk7K5rMGqiE+tlSthCbgaqK7ryLZ6gVWU
debug1: Will attempt key: /home/setevoy/.ssh/id_ed25519_sk 
debug1: Offering public key: RTFM RSA SHA256:nedb3Qgpkxgu57MRP7/eXShHgw6N6b7SjZ3S1rNyFb4 agent
debug1: Authentications that can continue: publickey
debug1: Offering public key: FreeBSD-NAS ED25519 SHA256:ZuJ77z6BNMwra41BiTKDrJSSQrDJ0/u+4wZRCvGJMpA agent
debug1: Server accepts key: FreeBSD-NAS ED25519 SHA256:ZuJ77z6BNMwra41BiTKDrJSSQrDJ0/u+4wZRCvGJMpA agent
Authenticated to nas.setevoy ([192.168.0.2]:22) using "publickey".
...
Last login: Sun Dec 28 13:44:51 2025 from 192.168.0.4
FreeBSD 14.3-RELEASE (GENERIC) releng/14.3-n271432-8c9ce319fef7

Welcome to FreeBSD!
...

[setevoy@setevoy-nas ~]$

І для ключів “Will attempt key: RTFM RSA [...] та FreeBSD-NAS [...] як раз бачимо, що вони були отримані від agent.

SSH Agent та помилка “Too many authentication failures”

Вище бачили, що передається ціла пачка ключів, і якщо їх багато – то сервер може відкинути подальшу аутентифікацію.

Кількість спроб задається на сервері параметром MaxAuthTries (дефолт “6”) в /etc/ssh/sshd_config. Тобто, якщо маємо 7 ключів, і перші 6 не підійшли – то підключитись не зможемо.

Аби вказати SSH клієнту який конкретно приватний ключ з агента використовувати – вказуємо публічний ключ та задаємо IdentitiesOnly:

...

Host nas.setevoy 192.168.0.2
  IdentityAgent ~/.1password/agent.sock
  IdentityFile ~/.ssh/freebsd-nas.pub
  IdentitiesOnly yes

І тепер під час підключення клієнт буде передавати тільки цей ключі:

[setevoy@setevoy-work ~] $ ssh -v [email protected]
...
debug1: get_agent_identities: agent returned 2 keys
debug1: Will attempt key: /home/setevoy/.ssh/freebsd-nas.pub ED25519 SHA256:ZuJ77z6BNMwra41BiTKDrJSSQrDJ0/u+4wZRCvGJMpA explicit agent
debug1: Offering public key: /home/setevoy/.ssh/freebsd-nas.pub ED25519 SHA256:ZuJ77z6BNMwra41BiTKDrJSSQrDJ0/u+4wZRCvGJMpA explicit agent
debug1: Server accepts key: /home/setevoy/.ssh/freebsd-nas.pub ED25519 SHA256:ZuJ77z6BNMwra41BiTKDrJSSQrDJ0/u+4wZRCvGJMpA explicit agent
Authenticated to nas.setevoy ([192.168.0.2]:22) using "publickey".
...

Last login: Sun Dec 28 13:44:57 2025 from 192.168.0.4
FreeBSD 14.3-RELEASE (GENERIC) releng/14.3-n271432-8c9ce319fef7

Welcome to FreeBSD!
...

[setevoy@setevoy-nas ~]$

Basic SSH Server Hardening

Див. sshd_config.

Перевірити поточну конфігурацію можна з sshd -T:

root@setevoy-nas:/home/setevoy # sshd -T 
port 22
addressfamily any
listenaddress 0.0.0.0:22
...

Наприклад, чи дозволений логін root:

root@setevoy-nas:/home/setevoy # sshd -T | grep root
permitrootlogin no

Редагуємо конфіг /etc/ssh/sshd_config, задаємо мінімальні параметри, і нехай буде PermitRootLogin no вказаний тут явно.

Плюс явно вказуємо дозвіл на PubkeyAuthentication та PasswordAuthentication – парольну аутентифікацію відключимо пізніше, коли впевнимось, що все працює:

PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication yes

Перевіряємо синтаксис з sshd -t, якщо все добре – то команда просто нічого не виведе:

root@setevoy-nas:/home/setevoy # sshd -t; echo $?
0

Виконуємо reload конфігу:

root@setevoy-nas:/home/setevoy # service sshd reload
Performing sanity check on sshd configuration.

Перевіряємо чи працює доступ з Linux:

[setevoy@setevoy-work ~]  $ ssh nas.setevoy
...
[setevoy@setevoy-nas ~]$

pf вже налаштований, див. FreeBSD: Home NAS, part 2 – знайомство з Packet Filter (PF) firewall:

...

# allow SSH from Office LAN (192.168.0.0/24) to FreeBSD host
pass in log on em0 proto tcp from 192.168.0.0/24 to (em0) port 22 keep state

# allow SSH from Home network (192.168.100.0/24) to FreeBSD host
pass in log on em0 proto tcp from 192.168.100.0/24 to (em0) port 22 keep state

# allow SSH from VPN clients to FreeBSD host
pass in on wg0 proto tcp from 10.8.0.0/24 to (wg0) port 22 keep state
...

Можна мережі вказати як { 192.168.0.0/24, 192.168.100.0/24, 10.8.0.0/24 }, але для SSH вирішив залишити в такому вигляді, аби було явно видно.

Далі можна додати ще трохи параметрів:

  • PermitRootLogin no: заборона підключення root, це вже є
  • PubkeyAuthentication yes: аутентифікація по ключам, теж вже є
  • PasswordAuthentication yes: пароль аутентифікація, поки залишаємо включеною
  • ChallengeResponseAuthentication no: вимикаємо keyboard-interactive аутентифікацію через PAM, яка не потрібна без 2FA
    • тут ще нюанс в тому, що навіть якщо відключити PasswordAuthentication, але ChallengeResponseAuthentication буде “yes” і при UsePAM = “yes” – то система все одно може запросити парольну аутентифікацію
  • UsePAM yes: залишаємо включеним для логування, обліку сесій, політик доступу (див. Practical Effects of Setting “UsePAM yes” on SSH in Linux)
  • AllowUsers setevoy або AllowGroups wheel: яким юзерам або групам можна підключатись по SSH
  • X11Forwarding no: блокуємо форвард X11 – графічного серверу тут все одно нема
  • AllowAgentForwarding no: забороняємо можливість використання локальних SSH-ключів клієнта з сервера через SSH-агент клієнта
  • AllowTcpForwarding no: забороняємо SSH-тунелі – на домашньому NAS це точно не треба (див. SSH-туннели в примерах – мій пост за 2013 рік, OMG… та SSH Tunnels: Secure Remote Access and Port Forwarding)
  • AuthorizedKeysFile .ssh/authorized_keys: це дефолтне значення, але задамо явно

Перевіряємо ще раз з sshd -t, виконуємо reload, перевіряємо підключення з ключем з клієнта.

Якщо все ОК – то додаємо ще трохи тюнингу:

  • PasswordAuthentication no: тепер відключаємо парольну аутентифікацію
  • AuthenticationMethods publickey: явно заборонити всі механізми окрім ключів
  • MaxSessions 2: максимальна кількість активних сесій на одне TCP-підключення
  • LoginGraceTime 30: кількість секунд, за яку клієнт має пройти аутентифікацію

Для ще більшої безпеки – можна налаштувати інший порт замість 22 (наприклад, задати Port 2222), обмежити IP, на яких слухає sshd (параметр ListenAddress 192.168.0.2), і навіть налаштувати Two-factor Authentication For SSH – але для домашнього сервера з доступом тільки з локальних мереж це вже overkill.