22 KiB
Полный план реализации — IP WhiteList Microservice
Автор: GitHub Copilot (GPT-5.4) Дата: 2026-05-29 Статус: рабочий план для реализации
1. Цель системы
Нужно реализовать внутренний веб-сервис, в котором клиенты облачного провайдера смогут самостоятельно управлять доверенными IPv4-адресами и подсетями. Эти записи должны исключаться из блокировки во время DDoS-митигции.
Сервис должен решать 3 задачи:
- Дать клиенту self-service интерфейс для управления whitelist.
- Дать администраторам и сетевым инженерам централизованный просмотр и контроль.
- Отдавать агрегированный экспорт всех активных записей в текстовом формате для внешних систем фильтрации.
2. Что именно должно быть в первой рабочей версии
Первая версия должна включать:
- Авторизацию через Keycloak OIDC.
- Разделение прав client/admin.
- Поддержку одной или нескольких компаний у пользователя.
- Таблицу whitelist-записей.
- Создание, редактирование и soft delete записей.
- Проверку лимитов по компаниям.
- Аудит всех изменяющих действий.
- Экспорт агрегированного списка активных CIDR в text/plain.
- Серверную валидацию IPv4 и CIDR по правилам ТЗ.
- Клиентскую валидацию формы для UX.
3. Обязательные уточнения до начала интеграции с Keycloak
До кодирования OIDC-части нужно получить точные ответы на 3 вопроса:
-
Какой claim или role означает администратора. Сейчас в ТЗ сказано: clientId = WZ01112 и отдельный чек-бокс. Нужно точно знать, во что это превращается в токене.
-
Как кодируется принадлежность к нескольким компаниям. В ТЗ упомянут мультикомпанейный сценарий, но в claims перечислен только clientID. Нужно уточнить, это строка, массив, groups или другой формат.
-
Где именно ограничивается внешний экспортный 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. Архитектурные принципы
-
Синхронный код по умолчанию. Для этой системы async не нужен. Он только повысит стоимость поддержки.
-
Серверная валидация является источником истины. Клиентская валидация только помогает пользователю.
-
Аудит append-only. Записи аудита нельзя изменять и удалять.
-
Все проверки прав и лимитов выполняются на сервере внутри транзакций.
-
Soft delete обязателен для whitelist-записей.
-
Значение лимита по умолчанию должно меняться через конфиг без пересборки.
-
Dev-заглушка авторизации должна быть жёстко отключаемой в production.
6. Предлагаемая структура проекта
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
Назначение: хранение компаний и переопределённых лимитов.
Поля:
- id
- client_id
- name
- custom_limit
- created_at
- updated_at
Правила:
- client_id уникален.
- custom_limit может быть null, тогда используется глобальный лимит.
Таблица whitelist_entries
Назначение: активные и удалённые whitelist-записи.
Поля:
- id
- company_id
- value_cidr
- comment
- created_by
- created_at
- updated_by
- updated_at
- deleted_by
- deleted_at
Правила:
- value_cidr хранится только в нормализованном виде.
- deleted_at is null означает активную запись.
- comment ограничен 255 символами.
Таблица audit_log
Назначение: неизменяемый журнал действий.
Поля:
- id
- user_email
- company_id
- action
- old_value
- new_value
- created_at
Дополнительно желательно хранить:
- target_entry_id
- request_id
- actor_role
Это не противоречит ТЗ и упростит разбор инцидентов.
8. Правила авторизации и ролей
Клиент
- Видит только записи своей активной компании.
- Может создавать, редактировать и удалять записи только в допустимом контексте компании.
- Может переключать активную компанию, если в токене действительно есть доступ к нескольким компаниям.
Администратор
- Видит записи всех компаний.
- Может менять записи всех компаний.
- Может видеть удалённые записи.
- Может смотреть аудит.
- Может менять custom_limit для компании.
Что нужно реализовать в коде
- Унифицированную модель текущего пользователя.
- Отдельную функцию маппинга claims в внутреннюю роль.
- Жёсткие проверки прав на уровне service-слоя, не только роутеров.
9. Валидация IPv4 и CIDR
Эта часть критична. Её нужно делать одной из первых и сразу покрывать тестами.
Поддерживаемый ввод
- Одиночный IPv4 адрес, который трактуется как /32.
- IPv4 подсеть в CIDR нотации.
Запрещённый ввод
- IPv6.
- Доменное имя.
- Маска шире допустимой.
- Любые private или special ranges из приложения А.
Правила маски
Допустимы только /22 ... /32.
Нормализация
Если пользователь ввёл адрес с host-битами, сервис должен:
- Нормализовать значение до адреса сети.
- Сохранить нормализованное значение.
- Вернуть пользователю явное сообщение, что адрес был нормализован.
Проверки в пределах компании
- Запрет полного дубликата активной записи.
- Запрет любого пересечения активной записи с существующими активными записями той же компании.
- Между разными компаниями пересечения допускаются.
Список запрещённых диапазонов
Нужно захардкодить как конфигурацию приложения и покрыть тестами:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
- 100.64.0.0/10
- 127.0.0.0/8
- 169.254.0.0/16
- 192.0.0.0/24
- 192.0.2.0/24
- 198.51.100.0/24
- 203.0.113.0/24
- 198.18.0.0/15
- 224.0.0.0/4
- 240.0.0.0/4
- 255.255.255.255/32
10. Лимиты и конкурентность
Это важное место, которого обычно недооценивают.
Правила лимитов
- Есть глобальный DEFAULT_LIMIT, по умолчанию 15.
- Для компании может быть custom_limit.
- При снижении лимита ниже текущего количества записей существующие записи не удаляются.
- Пока число активных записей больше лимита, новые записи создавать нельзя.
Риск гонок
Если два запроса одновременно создают записи в одной компании, возможны:
- Пробитие лимита.
- Пропуск пересечения.
- Пропуск дубликата.
Что делать
Операцию создания и обновления записи нужно делать в транзакции с сериализацией логики на уровне компании. Практически это можно решить так:
- Брать advisory lock по company_id перед проверками и записью.
- Либо делать SELECT ... FOR UPDATE по строке компании, если этого достаточно для вашей схемы доступа.
Для первой версии я бы выбрал advisory lock по company_id. Это проще и надёжнее для бизнес-ограничений, которые нельзя полностью выразить обычным unique index.
11. Экспорт агрегированного списка
Требования
- В экспорт попадают только активные записи.
- Данные берутся по всем компаниям.
- Пересечения между компаниями допустимы на уровне хранения, но в export должны агрегироваться в минимальный набор CIDR.
- Формат ответа: text/plain.
- Одна строка = один CIDR.
Что нужно зафиксировать реализационно
- Результат должен быть отсортирован для стабильности.
- В ответе должен быть завершающий перевод строки.
- Content-Type должен быть text/plain; charset=utf-8.
- Желательно отдавать Content-Disposition с понятным именем файла.
Защита endpoint
Если endpoint на старте работает без auth, то доступ надо ограничить минимум одним из способов:
- Проверка client IP в приложении.
- Ограничение на reverse proxy.
- Оба сразу.
12. UI-потоки
Экран клиента
Должны быть:
- Селектор активной компании, если компаний несколько.
- Таблица записей.
- Индикатор использовано X из N.
- Форма создания записи.
- Возможность редактирования.
- Возможность soft delete.
Экран администратора
Должны быть:
- Таблица по всем компаниям.
- Фильтр по компании.
- Фильтр показа удалённых записей.
- Просмотр журнала аудита.
- Управление лимитами компании.
UX-детали, которые обязательно сделать
- Понятные сообщения об ошибках валидации.
- Явное сообщение о нормализации адреса.
- Явное сообщение о превышении лимита.
- Явное сообщение о пересечении с существующей записью.
13. Пошаговый план реализации
Этап 1. Каркас проекта
- Создать структуру каталогов.
- Подготовить requirements.txt.
- Подготовить .env.example.
- Подключить FastAPI, Jinja2, static.
- Подготовить docker-compose.yml с PostgreSQL.
Результат этапа: приложение стартует, открывается базовая страница, есть подключение к БД.
Этап 2. Схема БД и миграции
- Настроить Alembic.
- Создать initial migration.
- Поднять таблицы companies, whitelist_entries, audit_log.
- Добавить нужные индексы.
Результат этапа: схема БД фиксирована и воспроизводима.
Этап 3. Валидатор CIDR
- Реализовать разбор IPv4 и CIDR.
- Реализовать проверку маски.
- Реализовать нормализацию.
- Реализовать проверку запрещённых диапазонов.
- Написать тесты на валидатор.
Результат этапа: независимый, протестированный модуль бизнес-валидации.
Этап 4. Сервисный слой для записей
- Реализовать list.
- Реализовать create.
- Реализовать update.
- Реализовать soft delete.
- Реализовать проверки лимитов, дубликатов и пересечений.
- Добавить транзакционную защиту от гонок.
Результат этапа: бизнес-операции работают без UI.
Этап 5. Аудит
- Добавить запись CREATE.
- Добавить запись UPDATE со старым и новым состоянием.
- Добавить запись DELETE.
- Добавить интерфейс чтения для admin.
Результат этапа: все изменяющие действия фиксируются.
Этап 6. Авторизация
- Реализовать dev-заглушку.
- Реализовать чтение и валидацию JWT из Keycloak.
- Реализовать преобразование claims в current user.
- Реализовать проверки client/admin.
- Реализовать переключение компании.
Результат этапа: права и контекст пользователя работают сквозным образом.
Этап 7. HTML-интерфейс
- Реализовать страницу списка.
- Реализовать формы создания и редактирования.
- Реализовать soft delete из UI.
- Реализовать админские экраны.
Результат этапа: сервис пригоден для ручной эксплуатации.
Этап 8. Экспорт
- Реализовать сбор всех активных CIDR.
- Реализовать агрегацию.
- Реализовать endpoint export.
- Реализовать сетевое ограничение.
Результат этапа: внешняя система может забирать текстовый агрегированный whitelist.
Этап 9. Финализация
- Написать README.
- Подготовить Dockerfile.
- Подготовить пример systemd unit при необходимости.
- Прогнать ручной smoke-test.
Результат этапа: сервис можно разворачивать и передавать коллегам.
14. Тестовая стратегия
Минимально обязательные тесты:
- Валидный одиночный IPv4 превращается в /32.
- Валидная подсеть принимается.
- Host-биты нормализуются.
- Маски шире допустимой границы отклоняются.
- IPv6 отклоняется.
- Все запрещённые диапазоны отклоняются.
- Дубликат в одной компании запрещён.
- Пересечение в одной компании запрещено.
- Тот же CIDR в другой компании разрешён.
- Soft delete освобождает лимит.
- Export не включает soft-deleted записи.
- Export агрегирует CIDR корректно.
- Client не видит чужие компании.
- Admin видит все компании.
- Аудит создаётся для create, update, delete.
15. Что можно отложить после первой версии
Это не нужно тащить в MVP:
- Полноценный SPA.
- Сложная ORM.
- WebSocket.
- Фоновая очередь.
- Исторические версии записей кроме audit log.
- Автоматическое уведомление по email.
16. Главные риски проекта
- Неясный формат claims из Keycloak.
- Гонки при одновременном создании записей.
- Ошибки в трактовке пересечений CIDR.
- Неправильная нормализация адресов без понятного сообщения пользователю.
- Слишком раннее усложнение фронтенда.
17. Что я бы делал первым
Если начинать реализацию прямо сейчас, порядок такой:
- Каркас проекта.
- Схема БД.
- Валидатор и тесты.
- Сервис create/update/delete с транзакциями.
- Только потом UI и Keycloak.
Это самый безопасный путь: сначала фиксируется ядро бизнес-логики, потом уже внешний слой.
18. Итоговое решение
За основу реализации стоит брать простой Python/FastAPI сервис с PostgreSQL, синхронной серверной логикой, жёсткой серверной валидацией, транзакционной защитой от гонок и минималистичным HTML UI.
Главная мысль: сложность здесь не во фронтенде и не в фреймворке, а в корректной реализации правил CIDR, лимитов, ролей и аудита. План должен защищать именно эти части, а не раздувать стек.