Files
ssh-access-tui/docs/ADMIN_GUIDE.md
T
2026-07-22 17:13:35 +03:00

247 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Руководство администратора
Практическое руководство по экранам `ssh-access-tui` и типовым сценариям.
Архитектурные решения и модель угроз — в [ARCHITECTURE.md](ARCHITECTURE.md).
## Запуск
```sh
sudo ssh-access-tui
```
Требует root (создаёт/блокирует системных пользователей, правит
`authorized_keys`). Инструмент рассчитан на **одного** администратора
одновременно на хосте — если кто-то ещё уже открыл TUI, вторая сессия
получит ошибку про занятую блокировку состояния (`state.lock`), а не молча
перезапишет чужие изменения.
Навигация везде: стрелки/`j`/`k` — перемещение по списку, `enter` —
выбрать/подтвердить, `esc` — назад, `ctrl+c` — жёсткий выход в любой момент
(без каких-либо предупреждений — только для аварийных случаев). `q` как
быстрый выход работает **только в главном меню** (на остальных экранах он
ничего не делает — «esc» уводит назад). Обычный выход (пункт «Выход» или
`q` в главном меню) предупредит, если есть:
- пользователи, для которых ни разу не сгенерирован ключ (не были в
«Экспорт архивов»);
- пользователи, у которых **изменился доступ, но конфиг у них старый**
(кто-то поменял группы/каталог после их последнего экспорта или
обновления конфига) — им нужно прислать новый `config` через «Обновить
конфиги», иначе их локальный конфиг не соответствует их реальным правам.
В обоих случаях можно выйти всё равно (`enter`/`y`) или вернуться
(`esc`/`n`). Главное меню всегда показывает актуальное количество таких
пользователей под списком пунктов, если оно не нулевое — не нужно ждать
выхода, чтобы это заметить.
**Любое деструктивное действие** (блокировка/удаление пользователя,
удаление хоста/сервиса/группы, перевыпуск уже выданного ключа) требует не
`enter`/`y`, а **набрать вручную короткую случайную строку**, которую
инструмент показывает на экране подтверждения (например `kqzvm-482`) — она
каждый раз новая. Неверный ввод просто откатывает к полю ввода с пояснением
«не совпадает», ничего не меняя; `esc` отменяет действие полностью в любой
момент. Это защита именно от «промахнулся мимо enter» — набрать чужую
случайную строку по ошибке невозможно.
## Главное меню
```
Пользователи — создать / заблокировать / разблокировать / удалить
Хосты и сервисы — общий каталог адресов и портов (один раз на всех)
Группы — какие сервисы из каталога входят в каждую группу
Экспорт архивов — сгенерировать ключи и .7z для доставки
Обновить конфиги — перевыпустить config (без ключа) тем, у кого изменился доступ
Аудит / кто в сети — активные сессии и журнал подключений
Выход
```
Имена хостов, сервисов и групп должны быть без пробелов (латиница, цифры,
`. _ -`) — они попадают в конфиг и в `authorized_keys`; инструмент откажет с
понятной ошибкой, если ввести имя с пробелом.
## Модель: каталог → группы → пользователи
Хосты и их сервисы (порты) описываются **один раз** в общем каталоге
(«Хосты и сервисы»), а не заново для каждой группы. Доступ раздаётся **по
конкретным сервисам**, не по хосту целиком: группа выбирает нужные сервисы
из дерева «хост → его сервисы» — можно взять только `ssh` этого хоста, не
трогая его же `web-admin`. Если у вас в разных группах фигурируют одни и те
же хосты/сервисы — их не нужно набивать повторно, только отметить нужные
для очередной группы. Пользователь состоит в одной или нескольких группах;
его реальный доступ — объединение сервисов, выбранных во всех его группах.
## Сценарий 1: новый сотрудник, у которого уже есть роль/группа доступа
Обычно каталог и группы настраивают заранее (или один раз добавляют то,
чего не хватает), потом заводят пользователей пачками.
1. **Хосты и сервисы** → `n` → имя хоста (например `db-prod-1`), адрес (как
виден с jump-хоста), описание (необязательно) → `enter`. Сразу
открывается список сервисов этого хоста (изначально пуст).
2. `n` → имя сервиса (например `ssh` или `web-api`), порт на хосте
(например `22` или `7888`), описание (необязательно) → `enter`. Повторите
`n` для каждого сервиса на этом хосте.
3. `esc` — назад к списку хостов; повторите шаги 1-2 для остальных хостов,
затем `esc` — в главное меню. Если хост/сервис уже существует и нужно
только поправить адрес/порт/описание — `e` вместо `n` на нужной записи
(можно поменять и имя — все группы, которые ссылались на старое имя,
автоматически обновятся).
4. **Группы** → `n` → имя группы (например `team-billing`), описание
(необязательно) → `enter`.
5. Выбрать группу → `enter` — откроется дерево «хост → его сервисы».
`space` на строке сервиса отмечает именно его; `space` на строке хоста
(заголовок) отмечает/снимает сразу все его сервисы — удобно, когда нужен
весь хост, но при желании можно оставить только часть его сервисов.
`[x]` — выбрано всё, `[~]` — выбрано частично, `[ ]` — ничего. `enter`
сохранить.
6. **Пользователи** → `n` → имя пользователя (латиницей, будущий Linux-логин)
и комментарий (например ФИО) → `enter`.
7. Отметить `space` нужные группы (можно несколько) → `enter`.
Это уже создаёт системный Linux-аккаунт (без пароля, без интерактивного
шелла) и запись в состоянии. **Ключ ещё не выдан** — статус в списке
пользователей покажет «ключ не выдан».
8. **Экспорт архивов** → отметить `space` только что созданного пользователя
(или `a` — отметить всех, удобно при пакетном найме) → `enter`. Для
пользователей без ключа архив генерируется сразу, без лишних вопросов —
это не деструктивное действие. Инструмент сгенерирует ключ, пропишет
`permitopen=` под текущие сервисы группы и соберёт `.7z`, показав **один
общий пароль на всю партию** — он показывается один раз,
запишите/скопируйте сразу.
9. Передайте каждому пользователю его архив (файл, путь показан на экране,
лежит в `export_dir`) любым каналом, а пароль от архива — **отдельным**
каналом (голосом, в личку) и по возможности не всем одним и тем же
сообщением в общем чате.
10. Пользователь распаковывает архив на Windows по инструкции
`INSTRUCTIONS.txt` внутри архива — она на простом русском языке, без
технических терминов: положить файлы в папку, ввести одну команду и
держать окно открытым, дальше список «такой адрес у вас локально → что
это → где реально находится», составленный под конкретные сервисы этого
пользователя.
## Сценарий 1а: изменить группы уже существующего пользователя
**Пользователи** → выбрать пользователя → `g` → отметить/снять `space`
нужные группы → `enter`. Если у пользователя уже выдан ключ, инструмент
сразу пересоберёт его `permitopen=` под новый набор сервисов — доступ
меняется немедленно, без переотправки архива и **без замены ключа**
(изменение групп никогда не ротирует ключ).
Если хотите, чтобы у пользователя появился ещё и обновлённый клиентский
`config` с новыми адресами для новых сервисов (иначе он про них просто не
узнает, хотя доступ уже есть) — **Пользователи** → выбрать пользователя →
`c` («обновить конфиг»), либо (то же самое, но сразу для многих)
**Обновить конфиги** в главном меню. Это генерирует архив только с
`config` + `INSTRUCTIONS.txt` (без ключа — ключ у пользователя уже есть и
остаётся тем же), пользователю нужно только подменить файл `config`. Не
требует подтверждения — ключ и доступ этим действием не меняются, это не
деструктивно.
**Обновить конфиги** в главном меню — то же самое, что `c`, но пакетно:
список покажет каждого уже выпущенного пользователя с пометкой «конфиг
актуален» или «конфиг устарел — доступ изменился» (см. ниже, как это
отслеживается), можно отметить `space` только устаревших или `a` — всех, и
получить один пароль на всю партию, как при обычном экспорте.
Инструмент сам запоминает, для какого набора сервисов последний раз
выдавался config каждому пользователю (полным экспортом или через
«обновить конфиг»), и сравнивает с тем, что должно быть сейчас — отсюда и
берётся статус «устарел». Полный экспорт (сценарий 1, шаги 8-9) тоже
обновляет этот статус (и заодно перевыпускает ключ, с подтверждением
строкой) — используйте `c`/«Обновить конфиги», когда переиздание ключа не
нужно.
## Сценарий 2: добавили новый сервис/хост, поменялся адрес или порт
- Новый сервис на существующем хосте: **Хосты и сервисы** → выбрать хост →
`enter` → `n`.
- Новый хост: **Хосты и сервисы** → `n`, затем добавить ему сервисы.
- Хост сменил адрес, сервис — порт, нужно поправить описание, или
переименовать: `e` на нужной записи. Переименование хоста или сервиса
автоматически обновляет ссылки на него во всех группах, которые его
используют — группы не «отваливаются» молча и не теряют доступ из-за
простого переименования.
Любое из этих изменений сразу обновляет `permitopen=` в `authorized_keys`
**всех активных пользователей всех групп**, ссылающихся на этот сервис, —
доступ появляется немедленно, без каких-либо действий на стороне
пользователя. Их клиентский конфиг (`~/.ssh/config`) при этом не
обновляется автоматически — их локальный файл начинает отставать от
реального доступа (инструмент это заметит и покажет как «конфиг устарел»,
см. выше); чтобы прислать актуальный конфиг — **Обновить конфиги** или `c`
(см. сценарий 1а).
**Группы** → выбрать группу → `enter` — то же дерево «хост → сервисы», там
же можно снять/добавить сервисы группе (не создавая и не удаляя сами
хосты/сервисы в каталоге).
Удаление хоста из каталога, сервиса на хосте или целой группы (`d` в
соответствующем списке) — все три действия **деструктивны** (мгновенно
отбирают доступ у всех затронутых пользователей) и требуют набрать
случайную строку подтверждения: экран покажет, что именно удаляется,
сколько пользователей это коснётся, и в каких группах используется
(для хоста/сервиса). Удаление хоста снимает с групп все его сервисы разом;
удаление одного сервиса снимает только его, остальные сервисы того же
хоста в группах остаются.
## Сценарий 3: сотрудник уволился
1. **Пользователи** → выбрать пользователя → `l` (заблокировать) → набрать
строку подтверждения, которую покажет экран → `enter`.
Блокировка — это одновременно: блокирует пароль аккаунта, устанавливает
немедленный срок истечения аккаунта (`chage -E 1`) и комментирует его ключ в
`authorized_keys` — три независимых механизма, чтобы блокировка не зависела
от одного из них. Статус в списке сменится на `locked`. Это **обратимо**.
Если сотрудник вернулся — `u` (разблокировать) на том же пользователе:
снимает блокировку аккаунта и восстанавливает его ключ в `authorized_keys`
с текущими правами групп. Разблокировка не деструктивна — подтверждения не
требует, срабатывает сразу.
Полное удаление аккаунта (`d`) — **необратимо** (`userdel -r`, домашняя папка
стирается) и тоже требует подтверждения строкой (экран явно предупредит,
что это необратимо и что для временного отключения лучше использовать
блокировку). Используйте удаление только для окончательного оффбординга, не
для временной блокировки.
## Сценарий 4: проверить, кто сейчас подключён / посмотреть историю
**Аудит / кто в сети** показывает:
- «Сейчас в сети» — список активных SSH-сессий (по процессам `sshd:
user [priv]`, а не по `who`, потому что форвардинг-сессии без
интерактивного терминала не создают обычных login-записей);
- «Последние события» — журнал подключений/отключений, который в фоне
собирает `ssh-access-tui-audit.service` из `journalctl`, независимо от
ротации системного журнала.
`r` — обновить оба списка. Если журнал подключений пуст, хотя пользователи
явно заходили — проверьте, что фоновый сервис запущен:
`systemctl status ssh-access-tui-audit.service`.
## Сценарий 5: перенос на новый хост / хост умер
См. подробности в [ARCHITECTURE.md](ARCHITECTURE.md#бэкап-и-аварийное-восстановление).
Коротко: состояние (каталог хостов/сервисов, группы, пользователи,
публичные ключи, статусы) — git-репозиторий, бэкапится часовым таймером в
удалённый git. На новом хосте: поднять `ssh-access-tui`, влить `state.yaml`
из бэкапа, создать системные Linux-аккаунты для активных пользователей,
выпустить им новые ключи через **Экспорт архивов** (старые приватные ключи
специально нигде не хранятся — это не баг, см. архитектурный документ).
## Что не делает эта версия (нужно руками)
- Не удаляет `.7z` из `export_dir` после доставки — сделайте это сами,
когда получатель подтвердил, что распаковал архив (это касается и
архивов от «обновить конфиг», хоть они и не содержат ключ).
- Не обновляет клиентский `~/.ssh/config` пользователя автоматически при
появлении нового сервиса/хоста в его группе — это ручной шаг («Обновить
конфиги», сценарий 1а), хоть инструмент и отслеживает, кому именно он
нужен (главное меню и предупреждение при выходе). Права доступа на
сервере при этом обновляются немедленно и без участия администратора
(см. сценарий 2).
- Не поддерживает одновременную работу нескольких администраторов —
рассчитан на одного за раз (см. «Конкурентность» в ARCHITECTURE.md).