Тунельні сервіси, які обіцяють один пристрій на абонента, рідко отримують цю обіцянку від MaxSessions, і перший тест зазвичай це доводить. Абонент відкриває другий процес ssh, перший сеанс продовжує працювати, і обидва тунелі несуть трафік. Кожен параметр конфігурації рахує щось інше, і жоден з них не рахує пристрої. Саме найменування обіцянки першим робить вибір між ними очевидним.

Що насправді рахує кожен параметр

MaxSessions обмежує кількість відкритих сеансів, які несе одне автентифіковане мережеве з'єднання. Сеанс тут означає оболонку, запит exec, підсистему на кшталт SFTP або схожий канал, мультиплексований у одному транспорті SSH. Другий виклик ssh відкриває другий транспорт, знову автентифікується і отримує власний дозвіл. Кількість сеансів першого з'єднання для нього не має значення.

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

Правило реєстрації пристрою зовсім не є параметром sshd. Воно належить будь-якій системі, яка видає облікові дані й відстежує, який пристрій їх зберігає, а отже, потребує реєстрації, інвентаризації та відкликання замість лічильника. Змішування цієї вимоги з конфігурацією sshd — це місце, де більшість таких проєктів застрягає.

Де MaxSessions перестає бути квотою

Блок Match User змінює, які значення конфігурації застосовуються до цього користувача, тож це природне місце, щоб задати суворіший MaxSessions для службового облікового запису. Чого він не може — агрегувати між з'єднаннями, бо параметр оцінюється для кожного транспорту. Два транспорти отримують кожен свій ліміт, і користувач зрештою має вдвічі більше, ніж дозволяє блок.

Переспрямування — окремий сюрприз. Переспрямуванню TCP не потрібен канал сеансу, тому MaxSessions 0 може заборонити оболонки й підсистеми, але дозволяти тунелі -L і -R. Сервіс, який лише переспрямовує і вважає кількість сеансів своєю квотою на тунель, не вимірює нічого. Ця поведінка задокументована в довіднику з конфігурації сервера OpenSSH, і його варто прочитати, перш ніж проєктувати навколо назви параметра.

Виведіть чинну конфігурацію, а не файл, який, на вашу думку, завантажено. Включення та каталоги drop-in часто означають, що чинне значення — не те, яке ви редагували.

MaxStartups захищає демон, а не абонента

Тричастинна форма MaxStartups описує, скільки неавтентифікованих з'єднань може існувати, перш ніж демон почне відкидати відсоток нових. Його форма за замовчуванням існує тому, що неавтентифіковане з'єднання SSH дешево відкрити й дорого утримувати. Це контроль захисту ресурсів для сервера, і він діє для всіх одночасно.

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

Коли входи відхиляються хвилями, подивіться в журналі демона повідомлення до автентифікації, перш ніж торкатися будь-якого з двох параметрів. Повідомлення називає, який вартовий спрацював, і вартові не взаємозамінні.

Слот на користувача потребує спільного стану

Справжня політика одного активного транспорту потребує резервування, яке зберігається десь поза sshd. Крок допуску має атомарно зайняти слот облікового запису, звільнити його після закриття з'єднання, дати йому спливти, коли клієнт зникає без закриття, і вирішити, чи нова спроба відхиляється, чи замінює стару. Це останнє рішення — продуктове, а не технічна деталь, бо заміна активного тунелю відключає когось.

Резервування має бути спільним і для кожного сервера, який приймає обліковий запис. Два хости з незалежними локальними лічильниками застосовують два окремі ліміти, і абонент, який перепідключається через інший шлюз, безкоштовно отримує другий слот. Те, що зберігає стан, потребує власної поведінки при збої, адже недоступне сховище не повинно блокувати всіх абонентів.

Для обіцянки одного пристрою видавайте окремі облікові дані для кожного зареєстрованого пристрою та керуйте реєстрацією і відкликанням на цьому рівні. Скопійований закритий ключ усе одно автентифікується звідусіль, тому видача одного ключа на користувача не є доказом того, скільки машин його зберігають.

Перевірте політику двома реальними з'єднаннями

Напишіть приймальні тести як команди, перш ніж писати політику. П'ять випадків — це другий транспорт, відкритий, коли перший активний, кілька каналів у одному транспорті, клієнт, який лише переспрямовує порти, перепідключення після обриву зв'язку і той самий обліковий запис, що приходить на інший шлюз.

Спершу прочитайте чинні ліміти, потім відкрийте з'єднання, які політика має відхиляти. Обидві половини цього тесту важливі, і жодна не замінює іншу.

sshd -T | grep -iE "maxsessions|maxstartups|allowtcpforwarding|permitopen"
ss -tn state established '( sport = :22 )' | head
ssh -N -L 8080:127.0.0.1:80 [email protected]

Запустіть команду тунелю двічі в двох терміналах і порахуйте встановлені з'єднання на порту 22. Якщо обидва несуть трафік, поки ваша політика стверджує один активний транспорт, політика — це документація, а не примусове виконання. Усуньте цю прогалину на рівні допуску, а не знижуючи MaxSessions у надії, що другий транспорт це помітить.

Схожі статті