add edit and all in one menu for hosts and services

This commit is contained in:
redlineo committed 2026-07-22 15:54:44 +03:00
1 parent 8c1b93c14e
commit e39ad275b5
15 files changed
+1136 -675

No files matched your search

+99 -81
View File
@@ -22,74 +22,85 @@ sudo ssh-access-tui
есть созданные, но ни разу не экспортированные пользователи (у них ещё нет
ключа) — можно выйти всё равно (`enter`/`y`) или вернуться (`esc`/`n`).
Любое деструктивное действие (блокировка/удаление пользователя, удаление
хоста или сервиса) сначала показывает отдельный экран подтверждения с
пояснением последствий — ничего не происходит до `enter`/`y`; `esc`/`n`
отменяет без каких-либо изменений.
**Любое деструктивное действие** (блокировка/удаление пользователя,
удаление хоста/сервиса/группы, перевыпуск уже выданного ключа) требует не
`enter`/`y`, а **набрать вручную короткую случайную строку**, которую
инструмент показывает на экране подтверждения (например `kqzvm-482`) — она
каждый раз новая. Неверный ввод просто откатывает к полю ввода с пояснением
«не совпадает», ничего не меняя; `esc` отменяет действие полностью в любой
момент. Это защита именно от «промахнулся мимо enter» — набрать чужую
случайную строку по ошибке невозможно.
## Главное меню
```
Пользователи — создать / заблокировать / разблокировать / удалить
Группы и хосты — какие внутренние хосты кому разрешены
Хосты и сервисы — общий каталог адресов и портов (один раз на всех)
Группы — какие хосты из каталога входят в каждую группу
Экспорт архивов — сгенерировать ключи и .7z для доставки
Аудит / кто в сети — активные сессии и журнал подключений
Выход
```
Имена групп, хостов и сервисов должны быть без пробелов (латиница, цифры,
Имена хостов, сервисов и групп должны быть без пробелов (латиница, цифры,
`. _ -`) — они попадают в конфиг и в `authorized_keys`; инструмент откажет с
понятной ошибкой, если ввести имя с пробелом.
## Модель: каталог → группы → пользователи
Хосты и их сервисы (порты) описываются **один раз** в общем каталоге
(«Хосты и сервисы»), а не заново для каждой группы. Группа — это просто
отметка галочками, какие хосты каталога в неё входят (все сервисы такого
хоста включаются целиком). Если у вас в разных группах фигурируют одни и те
же хосты/сервисы — их не нужно набивать повторно, только отметить нужные
для очередной группы. Пользователь состоит в одной или нескольких группах;
его реальный доступ — объединение сервисов всех хостов всех его групп.
## Сценарий 1: новый сотрудник, у которого уже есть роль/группа доступа
Обычно сначала настраивают группу (один раз), потом заводят пользователей в
неё пачками. Иерархия: **группа** → **хосты** → **сервисы (порты) на хосте**
— на одном хосте может быть несколько сервисов (например, `ssh` на 22 и
`web-api` на 7888), каждый добавляется отдельно.
Обычно каталог и группы настраивают заранее (или один раз добавляют то,
чего не хватает), потом заводят пользователей пачками.
1. **Группы и хосты** → `n` → ввести имя группы (например `team-billing`) →
`enter`.
2. Выбрать группу → `enter`, попасть в список хостов группы (изначально
пуст).
3. `n` → заполнить: имя хоста (короткое, например `db-prod-1`), адрес (как
виден с jump-хоста) → `tab` между полями → `enter`. Сразу после этого
попадаете в список сервисов этого хоста (тоже изначально пуст).
4. `n` → заполнить сервис: имя (например `ssh` или `web-api`), порт на
хосте (например `22` или `7888`), описание (необязательно) → `enter`.
Повторите `n` столько раз, сколько сервисов есть на этом хосте.
5. `esc` — назад к списку хостов группы; повторите шаги 3-4 для остальных
хостов группы, затем `esc` дважды — назад в главное меню.
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` нужные хосты из каталога →
`enter` сохранить. Список сервисов этих хостов достаётся группе целиком.
6. **Пользователи** → `n` → имя пользователя (латиницей, будущий Linux-логин)
и комментарий (например ФИО) → `enter`.
7. Отметить `space` нужные группы (можно несколько — эффективный доступ
пользователя = объединение сервисов всех хостов всех отмеченных групп) →
`enter`.
7. Отметить `space` нужные группы (можно несколько) → `enter`.
Это уже создаёт системный Linux-аккаунт (без пароля, без интерактивного
шелла) и запись в состоянии. **Ключ ещё не выдан** — статус в списке
пользователей покажет «ключ не выдан».
8. **Экспорт архивов** → отметить `space` только что созданного пользователя
(или `a` — отметить всех, удобно при пакетном найме) → `enter`. Список
сразу показывает у каждого пользователя, будет ли выдан новый ключ или
существующий будет **перевыпущен** (актуально, если случайно попадёт в
выборку уже работающий пользователь).
9. Экран подтверждения: для тех, у кого ключ уже был, явно предупредит, что
старый архив перестанет работать — только после `enter`/`y` (либо `esc`/`n`
для отмены, тогда не создаётся и не меняется вообще ничего) инструмент
сгенерирует ключ, пропишет `permitopen=` под текущие сервисы группы и
соберёт `.7z`, показав **один общий пароль на всю партию** — он
показывается один раз, запишите/скопируйте сразу.
10. Передайте каждому пользователю его архив (файл, путь показан на экране,
лежит в `export_dir`) любым каналом, а пароль от архива — **отдельным**
каналом (голосом, в личку) и по возможности не всем одним и тем же
сообщением в общем чате.
11. Пользователь распаковывает архив на Windows по инструкции
`INSTRUCTIONS.txt` внутри архива — она уже на простом русском языке,
без технических терминов: просто список "локальный адрес → какой это
сервис → куда он реально ведёт", составленный под конкретные разрешённые
сервисы этого пользователя.
(или `a` — отметить всех, удобно при пакетном найме) → `enter`. Для
пользователей без ключа архив генерируется сразу, без лишних вопросов —
это не деструктивное действие. Инструмент сгенерирует ключ, пропишет
`permitopen=` под текущие сервисы группы и соберёт `.7z`, показав **один
общий пароль на всю партию** — он показывается один раз,
запишите/скопируйте сразу.
9. Передайте каждому пользователю его архив (файл, путь показан на экране,
лежит в `export_dir`) любым каналом, а пароль от архива — **отдельным**
каналом (голосом, в личку) и по возможности не всем одним и тем же
сообщением в общем чате.
10. Пользователь распаковывает архив на Windows по инструкции
`INSTRUCTIONS.txt` внутри архива — она на простом русском языке, без
технических терминов: положить файлы в папку, ввести одну команду и
держать окно открытым, дальше список «такой адрес у вас локально → что
это → где реально находится», составленный под конкретные сервисы этого
пользователя.
## Сценарий 1а: изменить группы уже существующего пользователя
@@ -100,42 +111,49 @@ sudo ssh-access-tui
(изменение групп никогда не ротирует ключ).
Если хотите, чтобы у пользователя появился ещё и обновлённый клиентский
`config` с новыми `LocalForward` для новых сервисов (иначе он про них
просто не узнает, хотя доступ уже есть) — **Пользователи** → выбрать
пользователя → `c` («обновить конфиг»). Это генерирует маленький архив
только с `config` + `INSTRUCTIONS.txt` (без ключа — ключ у пользователя уже
есть и остаётся тем же), пользователю нужно только подменить файл `config`.
Не требует подтверждения — ключ и доступ этим действием не меняются, это не
`config` с новыми адресами для новых сервисов (иначе он про них просто не
узнает, хотя доступ уже есть) — **Пользователи** → выбрать пользователя →
`c` («обновить конфиг»). Это генерирует маленький архив только с `config` +
`INSTRUCTIONS.txt` (без ключа — ключ у пользователя уже есть и остаётся тем
же), пользователю нужно только подменить файл `config`. Не требует
подтверждения — ключ и доступ этим действием не меняются, это не
деструктивно.
Полный экспорт (со сценария 1, шаги 8-9) тоже сработает и даст то же самое
плюс заново выпустит ключ — используйте `c`, когда переиздание ключа не
нужно (обычный случай при простом изменении групп).
Полный экспорт (сценарий 1, шаги 8-9) тоже сработает и даст то же самое
плюс заново выпустит ключ (с подтверждением строкой, раз это перевыпуск) —
используйте `c`, когда переиздание ключа не нужно.
## Сценарий 2: добавили новый сервис/хост существующей группе
## Сценарий 2: добавили новый сервис/хост, поменялся адрес или порт
1. **Группы и хосты** → выбрать группу → `enter`.
2. Либо `n` — новый хост (затем добавить ему хотя бы один сервис), либо
выбрать существующий хост → `enter` → `n` — новый сервис на нём.
- Новый сервис на существующем хосте: **Хосты и сервисы** → выбрать хост →
`enter` → `n`.
- Новый хост: **Хосты и сервисы** → `n`, затем добавить ему сервисы.
- Хост сменил адрес, сервис — порт, нужно поправить описание, или
переименовать: `e` на нужной записи. Переименование хоста автоматически
обновляет ссылки на него во всех группах, которые его используют — группы
не «отваливаются» молча.
Это сразу обновляет `permitopen=` в `authorized_keys` **всех активных
пользователей** этой группы — доступ появляется немедленно, без каких-либо
действий на стороне пользователя. Клиентский конфиг пользователя (его
`~/.ssh/config`) при этом не обновляется автоматически — если хотите, чтобы
у пользователя появилась готовая строка `LocalForward` для нового сервиса, а
не только "голый" доступ на сервере, используйте **Пользователи** → `c`
(«обновить конфиг») — ключ при этом не меняется (см. сценарий 1а).
Любое из этих изменений сразу обновляет `permitopen=` в `authorized_keys`
**всех активных пользователей всех групп**, ссылающихся на этот хост, —
доступ появляется немедленно, без каких-либо действий на стороне
пользователя. Клиентский конфиг пользователя (его `~/.ssh/config`) при этом
не обновляется автоматически — для этого используйте **Пользователи** → `c`
(«обновить конфиг», см. сценарий 1а).
Удаление сервиса или целого хоста (`d` в соответствующем списке) — оба
действия **деструктивны** (мгновенно отбирают доступ у всех пользователей
группы) и требуют подтверждения: экран покажет, что именно удаляется и
скольких пользователей это коснётся, `enter`/`y` подтверждает, `esc`/`n`
отменяет без каких-либо изменений.
**Группы** → выбрать группу → `enter` — там же можно снять/добавить
привязку группы к хостам каталога (не создавая и не удаляя сами хосты).
Удаление хоста из каталога, сервиса на хосте или целой группы (`d` в
соответствующем списке) — все три действия **деструктивны** (мгновенно
отбирают доступ у всех затронутых пользователей) и требуют набрать
случайную строку подтверждения: экран покажет, что именно удаляется,
сколько пользователей это коснётся, и в каких группах используется
(для хоста/сервиса).
## Сценарий 3: сотрудник уволился
1. **Пользователи** → выбрать пользователя → `l` (заблокировать) → экран
подтверждения объяснит, что произойдёт → `enter`/`y`.
1. **Пользователи** → выбрать пользователя → `l` (заблокировать) → набрать
строку подтверждения, которую покажет экран → `enter`.
Блокировка — это одновременно: блокирует пароль аккаунта, устанавливает
немедленный срок истечения аккаунта (`chage -E 1`) и комментирует его ключ в
@@ -148,10 +166,10 @@ sudo ssh-access-tui
требует, срабатывает сразу.
Полное удаление аккаунта (`d`) — **необратимо** (`userdel -r`, домашняя папка
стирается) и тоже требует подтверждения (экран явно предупредит, что это
необратимо и что для временного отключения лучше использовать блокировку).
Используйте удаление только для окончательного оффбординга, не для
временной блокировки.
стирается) и тоже требует подтверждения строкой (экран явно предупредит,
что это необратимо и что для временного отключения лучше использовать
блокировку). Используйте удаление только для окончательного оффбординга, не
для временной блокировки.
## Сценарий 4: проверить, кто сейчас подключён / посмотреть историю
@@ -171,12 +189,12 @@ sudo ssh-access-tui
## Сценарий 5: перенос на новый хост / хост умер
См. подробности в [ARCHITECTURE.md](ARCHITECTURE.md#бэкап-и-аварийное-восстановление).
Коротко: состояние (`groups`, `users`, публичные ключи, статусы) —
git-репозиторий, бэкапится часовым таймером в удалённый git. На новом хосте:
поднять `ssh-access-tui`, влить `state.yaml` из бэкапа, создать системные
Linux-аккаунты для активных пользователей, выпустить им новые ключи через
**Экспорт архивов** (старые приватные ключи специально нигде не хранятся —
это не баг, см. архитектурный документ).
Коротко: состояние (каталог хостов/сервисов, группы, пользователи,
публичные ключи, статусы) — git-репозиторий, бэкапится часовым таймером в
удалённый git. На новом хосте: поднять `ssh-access-tui`, влить `state.yaml`
из бэкапа, создать системные Linux-аккаунты для активных пользователей,
выпустить им новые ключи через **Экспорт архивов** (старые приватные ключи
специально нигде не хранятся — это не баг, см. архитектурный документ).
## Что не делает эта версия (нужно руками)