init: ТЗ, правила copilot, планы от моделей (DeepSeek, Claude, GPT-5.4, Gemini)
This commit is contained in:
@@ -0,0 +1,529 @@
|
||||
# Полный план реализации — IP WhiteList Microservice
|
||||
|
||||
> Автор: GitHub Copilot (GPT-5.4)
|
||||
> Дата: 2026-05-29
|
||||
> Статус: рабочий план для реализации
|
||||
|
||||
## 1. Цель системы
|
||||
|
||||
Нужно реализовать внутренний веб-сервис, в котором клиенты облачного провайдера смогут самостоятельно управлять доверенными IPv4-адресами и подсетями. Эти записи должны исключаться из блокировки во время DDoS-митигции.
|
||||
|
||||
Сервис должен решать 3 задачи:
|
||||
|
||||
1. Дать клиенту self-service интерфейс для управления whitelist.
|
||||
2. Дать администраторам и сетевым инженерам централизованный просмотр и контроль.
|
||||
3. Отдавать агрегированный экспорт всех активных записей в текстовом формате для внешних систем фильтрации.
|
||||
|
||||
## 2. Что именно должно быть в первой рабочей версии
|
||||
|
||||
Первая версия должна включать:
|
||||
|
||||
1. Авторизацию через Keycloak OIDC.
|
||||
2. Разделение прав client/admin.
|
||||
3. Поддержку одной или нескольких компаний у пользователя.
|
||||
4. Таблицу whitelist-записей.
|
||||
5. Создание, редактирование и soft delete записей.
|
||||
6. Проверку лимитов по компаниям.
|
||||
7. Аудит всех изменяющих действий.
|
||||
8. Экспорт агрегированного списка активных CIDR в text/plain.
|
||||
9. Серверную валидацию IPv4 и CIDR по правилам ТЗ.
|
||||
10. Клиентскую валидацию формы для UX.
|
||||
|
||||
## 3. Обязательные уточнения до начала интеграции с Keycloak
|
||||
|
||||
До кодирования OIDC-части нужно получить точные ответы на 3 вопроса:
|
||||
|
||||
1. Какой claim или role означает администратора.
|
||||
Сейчас в ТЗ сказано: clientId = WZ01112 и отдельный чек-бокс. Нужно точно знать, во что это превращается в токене.
|
||||
|
||||
2. Как кодируется принадлежность к нескольким компаниям.
|
||||
В ТЗ упомянут мультикомпанейный сценарий, но в claims перечислен только clientID. Нужно уточнить, это строка, массив, groups или другой формат.
|
||||
|
||||
3. Где именно ограничивается внешний экспортный endpoint по IP.
|
||||
Нужно решить, это делает приложение, Nginx/Ingress, или оба уровня сразу.
|
||||
|
||||
Без этих 3 ответов можно делать каркас, БД, валидацию, CRUD и UI, но нельзя окончательно зафиксировать auth-слой.
|
||||
|
||||
## 4. Рекомендуемый стек
|
||||
|
||||
### Бэкенд
|
||||
|
||||
- Python 3.11+
|
||||
- FastAPI
|
||||
- Uvicorn
|
||||
|
||||
Причина: Python понятен команде, FastAPI даёт простой роутинг, типизацию, dependency injection и удобную основу для API и HTML-эндпоинтов.
|
||||
|
||||
### База данных
|
||||
|
||||
- PostgreSQL
|
||||
- psycopg2-binary
|
||||
- Alembic для миграций
|
||||
|
||||
Причина: нужны надёжные транзакции, аудит, индексы и понятный деплой. Здесь нет выгоды от тяжёлой ORM-магии, поэтому лучше простой и читаемый SQL.
|
||||
|
||||
### UI
|
||||
|
||||
- Jinja2
|
||||
- обычные HTML-формы
|
||||
- HTMX по желанию, только если реально упрощает частичные обновления
|
||||
- минимальный JS для inline-валидации и уведомлений
|
||||
|
||||
Причина: задача не требует SPA. Простая серверная отрисовка снизит сложность и упростит поддержку.
|
||||
|
||||
### Авторизация
|
||||
|
||||
- Keycloak OIDC
|
||||
- JWT-проверка по JWKS
|
||||
- отдельный dev-режим без Keycloak только для локальной разработки
|
||||
|
||||
### Работа с IP
|
||||
|
||||
- стандартный модуль ipaddress
|
||||
- netaddr только если стандартной библиотеки окажется недостаточно для агрегирования
|
||||
|
||||
Примечание: начать можно вообще без netaddr. Для суммаризации сначала стоит проверить, хватает ли ipaddress.collapse_addresses.
|
||||
|
||||
## 5. Архитектурные принципы
|
||||
|
||||
1. Синхронный код по умолчанию.
|
||||
Для этой системы async не нужен. Он только повысит стоимость поддержки.
|
||||
|
||||
2. Серверная валидация является источником истины.
|
||||
Клиентская валидация только помогает пользователю.
|
||||
|
||||
3. Аудит append-only.
|
||||
Записи аудита нельзя изменять и удалять.
|
||||
|
||||
4. Все проверки прав и лимитов выполняются на сервере внутри транзакций.
|
||||
|
||||
5. Soft delete обязателен для whitelist-записей.
|
||||
|
||||
6. Значение лимита по умолчанию должно меняться через конфиг без пересборки.
|
||||
|
||||
7. Dev-заглушка авторизации должна быть жёстко отключаемой в production.
|
||||
|
||||
## 6. Предлагаемая структура проекта
|
||||
|
||||
```text
|
||||
IPWhiteList/
|
||||
├── app/
|
||||
│ ├── main.py
|
||||
│ ├── config.py
|
||||
│ ├── db.py
|
||||
│ ├── security.py
|
||||
│ ├── validators.py
|
||||
│ ├── cidr_utils.py
|
||||
│ ├── services/
|
||||
│ │ ├── entries.py
|
||||
│ │ ├── companies.py
|
||||
│ │ ├── audit.py
|
||||
│ │ └── export.py
|
||||
│ ├── repositories/
|
||||
│ │ ├── entries.py
|
||||
│ │ ├── companies.py
|
||||
│ │ └── audit.py
|
||||
│ ├── routers/
|
||||
│ │ ├── ui.py
|
||||
│ │ ├── admin.py
|
||||
│ │ └── export.py
|
||||
│ ├── auth/
|
||||
│ │ ├── oidc.py
|
||||
│ │ ├── dev_stub.py
|
||||
│ │ └── deps.py
|
||||
│ └── templates/
|
||||
│ ├── base.html
|
||||
│ ├── index.html
|
||||
│ ├── entry_form.html
|
||||
│ ├── login_error.html
|
||||
│ └── admin/
|
||||
│ ├── audit.html
|
||||
│ └── limits.html
|
||||
├── static/
|
||||
│ └── style.css
|
||||
├── migrations/
|
||||
│ └── versions/
|
||||
├── tests/
|
||||
│ ├── test_validators.py
|
||||
│ ├── test_entries_service.py
|
||||
│ ├── test_export.py
|
||||
│ └── test_auth_mapping.py
|
||||
├── docs/
|
||||
│ ├── plan.md
|
||||
│ ├── plan-v2.md
|
||||
│ └── plan-gpt54.md
|
||||
├── requirements.txt
|
||||
├── .env.example
|
||||
├── alembic.ini
|
||||
├── docker-compose.yml
|
||||
├── Dockerfile
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## 7. Модель данных
|
||||
|
||||
### Таблица companies
|
||||
|
||||
Назначение: хранение компаний и переопределённых лимитов.
|
||||
|
||||
Поля:
|
||||
|
||||
1. id
|
||||
2. client_id
|
||||
3. name
|
||||
4. custom_limit
|
||||
5. created_at
|
||||
6. updated_at
|
||||
|
||||
Правила:
|
||||
|
||||
1. client_id уникален.
|
||||
2. custom_limit может быть null, тогда используется глобальный лимит.
|
||||
|
||||
### Таблица whitelist_entries
|
||||
|
||||
Назначение: активные и удалённые whitelist-записи.
|
||||
|
||||
Поля:
|
||||
|
||||
1. id
|
||||
2. company_id
|
||||
3. value_cidr
|
||||
4. comment
|
||||
5. created_by
|
||||
6. created_at
|
||||
7. updated_by
|
||||
8. updated_at
|
||||
9. deleted_by
|
||||
10. deleted_at
|
||||
|
||||
Правила:
|
||||
|
||||
1. value_cidr хранится только в нормализованном виде.
|
||||
2. deleted_at is null означает активную запись.
|
||||
3. comment ограничен 255 символами.
|
||||
|
||||
### Таблица audit_log
|
||||
|
||||
Назначение: неизменяемый журнал действий.
|
||||
|
||||
Поля:
|
||||
|
||||
1. id
|
||||
2. user_email
|
||||
3. company_id
|
||||
4. action
|
||||
5. old_value
|
||||
6. new_value
|
||||
7. created_at
|
||||
|
||||
Дополнительно желательно хранить:
|
||||
|
||||
1. target_entry_id
|
||||
2. request_id
|
||||
3. actor_role
|
||||
|
||||
Это не противоречит ТЗ и упростит разбор инцидентов.
|
||||
|
||||
## 8. Правила авторизации и ролей
|
||||
|
||||
### Клиент
|
||||
|
||||
1. Видит только записи своей активной компании.
|
||||
2. Может создавать, редактировать и удалять записи только в допустимом контексте компании.
|
||||
3. Может переключать активную компанию, если в токене действительно есть доступ к нескольким компаниям.
|
||||
|
||||
### Администратор
|
||||
|
||||
1. Видит записи всех компаний.
|
||||
2. Может менять записи всех компаний.
|
||||
3. Может видеть удалённые записи.
|
||||
4. Может смотреть аудит.
|
||||
5. Может менять custom_limit для компании.
|
||||
|
||||
### Что нужно реализовать в коде
|
||||
|
||||
1. Унифицированную модель текущего пользователя.
|
||||
2. Отдельную функцию маппинга claims в внутреннюю роль.
|
||||
3. Жёсткие проверки прав на уровне service-слоя, не только роутеров.
|
||||
|
||||
## 9. Валидация IPv4 и CIDR
|
||||
|
||||
Эта часть критична. Её нужно делать одной из первых и сразу покрывать тестами.
|
||||
|
||||
### Поддерживаемый ввод
|
||||
|
||||
1. Одиночный IPv4 адрес, который трактуется как /32.
|
||||
2. IPv4 подсеть в CIDR нотации.
|
||||
|
||||
### Запрещённый ввод
|
||||
|
||||
1. IPv6.
|
||||
2. Доменное имя.
|
||||
3. Маска шире допустимой.
|
||||
4. Любые private или special ranges из приложения А.
|
||||
|
||||
### Правила маски
|
||||
|
||||
Допустимы только /22 ... /32.
|
||||
|
||||
### Нормализация
|
||||
|
||||
Если пользователь ввёл адрес с host-битами, сервис должен:
|
||||
|
||||
1. Нормализовать значение до адреса сети.
|
||||
2. Сохранить нормализованное значение.
|
||||
3. Вернуть пользователю явное сообщение, что адрес был нормализован.
|
||||
|
||||
### Проверки в пределах компании
|
||||
|
||||
1. Запрет полного дубликата активной записи.
|
||||
2. Запрет любого пересечения активной записи с существующими активными записями той же компании.
|
||||
3. Между разными компаниями пересечения допускаются.
|
||||
|
||||
### Список запрещённых диапазонов
|
||||
|
||||
Нужно захардкодить как конфигурацию приложения и покрыть тестами:
|
||||
|
||||
1. 10.0.0.0/8
|
||||
2. 172.16.0.0/12
|
||||
3. 192.168.0.0/16
|
||||
4. 100.64.0.0/10
|
||||
5. 127.0.0.0/8
|
||||
6. 169.254.0.0/16
|
||||
7. 192.0.0.0/24
|
||||
8. 192.0.2.0/24
|
||||
9. 198.51.100.0/24
|
||||
10. 203.0.113.0/24
|
||||
11. 198.18.0.0/15
|
||||
12. 224.0.0.0/4
|
||||
13. 240.0.0.0/4
|
||||
14. 255.255.255.255/32
|
||||
|
||||
## 10. Лимиты и конкурентность
|
||||
|
||||
Это важное место, которого обычно недооценивают.
|
||||
|
||||
### Правила лимитов
|
||||
|
||||
1. Есть глобальный DEFAULT_LIMIT, по умолчанию 15.
|
||||
2. Для компании может быть custom_limit.
|
||||
3. При снижении лимита ниже текущего количества записей существующие записи не удаляются.
|
||||
4. Пока число активных записей больше лимита, новые записи создавать нельзя.
|
||||
|
||||
### Риск гонок
|
||||
|
||||
Если два запроса одновременно создают записи в одной компании, возможны:
|
||||
|
||||
1. Пробитие лимита.
|
||||
2. Пропуск пересечения.
|
||||
3. Пропуск дубликата.
|
||||
|
||||
### Что делать
|
||||
|
||||
Операцию создания и обновления записи нужно делать в транзакции с сериализацией логики на уровне компании. Практически это можно решить так:
|
||||
|
||||
1. Брать advisory lock по company_id перед проверками и записью.
|
||||
2. Либо делать SELECT ... FOR UPDATE по строке компании, если этого достаточно для вашей схемы доступа.
|
||||
|
||||
Для первой версии я бы выбрал advisory lock по company_id. Это проще и надёжнее для бизнес-ограничений, которые нельзя полностью выразить обычным unique index.
|
||||
|
||||
## 11. Экспорт агрегированного списка
|
||||
|
||||
### Требования
|
||||
|
||||
1. В экспорт попадают только активные записи.
|
||||
2. Данные берутся по всем компаниям.
|
||||
3. Пересечения между компаниями допустимы на уровне хранения, но в export должны агрегироваться в минимальный набор CIDR.
|
||||
4. Формат ответа: text/plain.
|
||||
5. Одна строка = один CIDR.
|
||||
|
||||
### Что нужно зафиксировать реализационно
|
||||
|
||||
1. Результат должен быть отсортирован для стабильности.
|
||||
2. В ответе должен быть завершающий перевод строки.
|
||||
3. Content-Type должен быть text/plain; charset=utf-8.
|
||||
4. Желательно отдавать Content-Disposition с понятным именем файла.
|
||||
|
||||
### Защита endpoint
|
||||
|
||||
Если endpoint на старте работает без auth, то доступ надо ограничить минимум одним из способов:
|
||||
|
||||
1. Проверка client IP в приложении.
|
||||
2. Ограничение на reverse proxy.
|
||||
3. Оба сразу.
|
||||
|
||||
## 12. UI-потоки
|
||||
|
||||
### Экран клиента
|
||||
|
||||
Должны быть:
|
||||
|
||||
1. Селектор активной компании, если компаний несколько.
|
||||
2. Таблица записей.
|
||||
3. Индикатор использовано X из N.
|
||||
4. Форма создания записи.
|
||||
5. Возможность редактирования.
|
||||
6. Возможность soft delete.
|
||||
|
||||
### Экран администратора
|
||||
|
||||
Должны быть:
|
||||
|
||||
1. Таблица по всем компаниям.
|
||||
2. Фильтр по компании.
|
||||
3. Фильтр показа удалённых записей.
|
||||
4. Просмотр журнала аудита.
|
||||
5. Управление лимитами компании.
|
||||
|
||||
### UX-детали, которые обязательно сделать
|
||||
|
||||
1. Понятные сообщения об ошибках валидации.
|
||||
2. Явное сообщение о нормализации адреса.
|
||||
3. Явное сообщение о превышении лимита.
|
||||
4. Явное сообщение о пересечении с существующей записью.
|
||||
|
||||
## 13. Пошаговый план реализации
|
||||
|
||||
### Этап 1. Каркас проекта
|
||||
|
||||
1. Создать структуру каталогов.
|
||||
2. Подготовить requirements.txt.
|
||||
3. Подготовить .env.example.
|
||||
4. Подключить FastAPI, Jinja2, static.
|
||||
5. Подготовить docker-compose.yml с PostgreSQL.
|
||||
|
||||
Результат этапа: приложение стартует, открывается базовая страница, есть подключение к БД.
|
||||
|
||||
### Этап 2. Схема БД и миграции
|
||||
|
||||
1. Настроить Alembic.
|
||||
2. Создать initial migration.
|
||||
3. Поднять таблицы companies, whitelist_entries, audit_log.
|
||||
4. Добавить нужные индексы.
|
||||
|
||||
Результат этапа: схема БД фиксирована и воспроизводима.
|
||||
|
||||
### Этап 3. Валидатор CIDR
|
||||
|
||||
1. Реализовать разбор IPv4 и CIDR.
|
||||
2. Реализовать проверку маски.
|
||||
3. Реализовать нормализацию.
|
||||
4. Реализовать проверку запрещённых диапазонов.
|
||||
5. Написать тесты на валидатор.
|
||||
|
||||
Результат этапа: независимый, протестированный модуль бизнес-валидации.
|
||||
|
||||
### Этап 4. Сервисный слой для записей
|
||||
|
||||
1. Реализовать list.
|
||||
2. Реализовать create.
|
||||
3. Реализовать update.
|
||||
4. Реализовать soft delete.
|
||||
5. Реализовать проверки лимитов, дубликатов и пересечений.
|
||||
6. Добавить транзакционную защиту от гонок.
|
||||
|
||||
Результат этапа: бизнес-операции работают без UI.
|
||||
|
||||
### Этап 5. Аудит
|
||||
|
||||
1. Добавить запись CREATE.
|
||||
2. Добавить запись UPDATE со старым и новым состоянием.
|
||||
3. Добавить запись DELETE.
|
||||
4. Добавить интерфейс чтения для admin.
|
||||
|
||||
Результат этапа: все изменяющие действия фиксируются.
|
||||
|
||||
### Этап 6. Авторизация
|
||||
|
||||
1. Реализовать dev-заглушку.
|
||||
2. Реализовать чтение и валидацию JWT из Keycloak.
|
||||
3. Реализовать преобразование claims в current user.
|
||||
4. Реализовать проверки client/admin.
|
||||
5. Реализовать переключение компании.
|
||||
|
||||
Результат этапа: права и контекст пользователя работают сквозным образом.
|
||||
|
||||
### Этап 7. HTML-интерфейс
|
||||
|
||||
1. Реализовать страницу списка.
|
||||
2. Реализовать формы создания и редактирования.
|
||||
3. Реализовать soft delete из UI.
|
||||
4. Реализовать админские экраны.
|
||||
|
||||
Результат этапа: сервис пригоден для ручной эксплуатации.
|
||||
|
||||
### Этап 8. Экспорт
|
||||
|
||||
1. Реализовать сбор всех активных CIDR.
|
||||
2. Реализовать агрегацию.
|
||||
3. Реализовать endpoint export.
|
||||
4. Реализовать сетевое ограничение.
|
||||
|
||||
Результат этапа: внешняя система может забирать текстовый агрегированный whitelist.
|
||||
|
||||
### Этап 9. Финализация
|
||||
|
||||
1. Написать README.
|
||||
2. Подготовить Dockerfile.
|
||||
3. Подготовить пример systemd unit при необходимости.
|
||||
4. Прогнать ручной smoke-test.
|
||||
|
||||
Результат этапа: сервис можно разворачивать и передавать коллегам.
|
||||
|
||||
## 14. Тестовая стратегия
|
||||
|
||||
Минимально обязательные тесты:
|
||||
|
||||
1. Валидный одиночный IPv4 превращается в /32.
|
||||
2. Валидная подсеть принимается.
|
||||
3. Host-биты нормализуются.
|
||||
4. Маски шире допустимой границы отклоняются.
|
||||
5. IPv6 отклоняется.
|
||||
6. Все запрещённые диапазоны отклоняются.
|
||||
7. Дубликат в одной компании запрещён.
|
||||
8. Пересечение в одной компании запрещено.
|
||||
9. Тот же CIDR в другой компании разрешён.
|
||||
10. Soft delete освобождает лимит.
|
||||
11. Export не включает soft-deleted записи.
|
||||
12. Export агрегирует CIDR корректно.
|
||||
13. Client не видит чужие компании.
|
||||
14. Admin видит все компании.
|
||||
15. Аудит создаётся для create, update, delete.
|
||||
|
||||
## 15. Что можно отложить после первой версии
|
||||
|
||||
Это не нужно тащить в MVP:
|
||||
|
||||
1. Полноценный SPA.
|
||||
2. Сложная ORM.
|
||||
3. WebSocket.
|
||||
4. Фоновая очередь.
|
||||
5. Исторические версии записей кроме audit log.
|
||||
6. Автоматическое уведомление по email.
|
||||
|
||||
## 16. Главные риски проекта
|
||||
|
||||
1. Неясный формат claims из Keycloak.
|
||||
2. Гонки при одновременном создании записей.
|
||||
3. Ошибки в трактовке пересечений CIDR.
|
||||
4. Неправильная нормализация адресов без понятного сообщения пользователю.
|
||||
5. Слишком раннее усложнение фронтенда.
|
||||
|
||||
## 17. Что я бы делал первым
|
||||
|
||||
Если начинать реализацию прямо сейчас, порядок такой:
|
||||
|
||||
1. Каркас проекта.
|
||||
2. Схема БД.
|
||||
3. Валидатор и тесты.
|
||||
4. Сервис create/update/delete с транзакциями.
|
||||
5. Только потом UI и Keycloak.
|
||||
|
||||
Это самый безопасный путь: сначала фиксируется ядро бизнес-логики, потом уже внешний слой.
|
||||
|
||||
## 18. Итоговое решение
|
||||
|
||||
За основу реализации стоит брать простой Python/FastAPI сервис с PostgreSQL, синхронной серверной логикой, жёсткой серверной валидацией, транзакционной защитой от гонок и минималистичным HTML UI.
|
||||
|
||||
Главная мысль: сложность здесь не во фронтенде и не в фреймворке, а в корректной реализации правил CIDR, лимитов, ролей и аудита. План должен защищать именно эти части, а не раздувать стек.
|
||||
Reference in New Issue
Block a user