Телеком-инвентаризация - переход от Excel к PostgreSQL, FastAPI и ZTP
05 сентября 2026
В жизни любого сетевого инженера наступает момент, когда количество обслуживаемых маршрутизаторов, стыков трансмиссии и протокольных параметров перешагивает критическую отметку. Обычно этот рубеж встречают во всеоружии: десятком таблиц Excel с говорящими названиями вроде Nodes_Final_v3_исправлено_ЮГ(копия).xlsx. Какое-то время эта система даже кажется рабочей, пока масштабы сети и требования к защите данных не заставляют взглянуть правде в глаза.
Реальность такова, что когда база сетевого оборудования разрастается до тысячи узлов, хранить её в Excel становится не просто неудобно, а откровенно небезопасно. Десятки разрозненных файлов, разбросанных по разным макрорегионам, пересылаемые в чатах таблицы и общие сетевые папки — прямой путь к утечке конфиденциальной топологии всей сети. Оставлять данные критической инфраструктуры в открытом доступе или доверять их неконтролируемым локальным копиям на десятках рабочих станций больше не представлялось возможным.
Excel — отличный инструмент для быстрых расчётов, но когда речь заходит о корпоративном телекоме, всегда можно сделать лучше. Возникла острая необходимость собрать единую точку правды и переехать на полноценную реляционную базу данных. Теперь она крутится на выделенном локальном сервере прямо у меня под столом: с жестким разграничением доступа, изоляцией сетевого контура и постоянным аудитом действий. И только сейчас, когда критические данные закрыты от посторонних глаз и защищены строгими декларативными правилами, появилось настоящее ощущение безопасности :)
Помимо закрытия вопросов безопасности, задача стояла сугубо практическая: создать централизованный инструмент технического учёта оборудования с инлайн-редактированием, валидацией адресного пространства, автоматической привязкой сетевых профилей и мгновенной генерацией боевых конфигураций.
Архитектура решения
Система построена по классической трехзвенной схеме с акцентом на производительность и минимальные задержки:
- Фронтенд & UI: SPA на базе Tabulator 6.2. Позволяет отображать и фильтровать 47 параметров оборудования в реальном времени, поддерживает inline-редактирование ячеек, автоподстановку фамилий инженеров, контекстное меню для быстрых действий (генерация
.cfg, очистка, вызов CLI) и переключение темы (☀️ / 🌙). - Транспорт & Интеграции: Прямые переходы по протоколу
ssh://сразу в сессии SecureCRT/PuTTY, интеграция с внешними скриптами автоматизации через REST API. - Веб-сервер: Nginx в роли реверс-прокси и SSL-терминатора, отдающий статику (CSS, JS вендоров, SVG Favicon) и пересылающий запросы в локальный Unix-сокет приложения.
- Бэкенд: FastAPI + Uvicorn. Асинхронное ядро с пулом соединений через SQLAlchemy к СУБД.
- Хранилище данных: PostgreSQL со строгой схемой данных, внешними ключами и таблицами аудита.
Логическая схема взаимодействия
+----------------------------------------------------------------------------------------------------------------------+
| ВХОДНЫЕ КАНАЛЫ И ПОЛЬЗОВАТЕЛИ |
+----------------------------------------------------------------------------------------------------------------------+
| | |
[ Инженеры / Web UI / exe для Windows ] [ Внешние интеграции / CLI ] [ SecureCRT / SSH ]
(Браузер, Рабочие места, Приложение) (Python / cURL / REST API) (Прямой переход ssh://)
| | |
+-------------------------------------------------+--------------------------------------------------+
| (HTTP / HTTPS / 443)
v
+----------------------------------------------------------------------------------------------------------------------+
| ВЕБ-СЕРВЕР И ПРОКСИ (Nginx) |
| • SSL Termination + HTTP Reverse Proxy |
| • Проксирование запросов на ASGI-сервер Uvicorn через сокет (/var/www/html/app/environment_inventory.sock) |
| • Статическая отдача CSS, SVG Favicon и JS вендоров |
+----------------------------------------------------------------------------------------------------------------------+
|
v
+----------------------------------------------------------------------------------------------------------------------+
| ЯДРО ПРИЛОЖЕНИЯ (FastAPI / Uvicorn / Python) |
| |
| +---------------------------------------+ +---------------------------------------------------------------------+ |
| | ФРОНТЕНД & UI (Tabulator 6.2) | | API & BACKEND ENDPOINTS | |
| |---------------------------------------| |---------------------------------------------------------------------| |
| | • 47 параметров оборудования | | • / - Главный SPA-интерфейс (index.html) | |
| | • Inline-редактирование ячеек | | • /api/v1/me - Авторизация и профиль пользователя | |
| | • Автоподстановка Фамилий инженеров | | • /api/v1/nodes - CRUD узлов, фильтрация по макрорегионам | |
| | • Контекстное меню (CLI, .cfg, Clear) | | • /api/v1/config/... - Генерация / скачивание .cfg конфигов узла | |
| | • Фильтры 5 округов (Юг, Поволжье..) | | • /api/v1/import/... - Парсинг и импорт Excel данных | |
| | • Переключение Темы (☀️ / 🌙) | | • /api/v1/export/... - Выгрузка таблицы в .xlsx файл | |
| +---------------------------------------+ +---------------------------------------------------------------------+ |
| |
| ------------------------------------------------------------------------------------------------------------------ |
| МОДУЛЬ БИЗНЕС-ЛОГИКИ И БЕЗОПАСНОСТИ |
| |
| • Аутентификация и RBAC: HTTP Basic Auth (Bcrypt), роли (admin / engineer / viewer с ограниченным списком |
| редактируемых колонок VIEWER_ALLOWED_FIELDS: СМР, ПНР, Миграция, BMC) в связке с мультирегиональным доступом |
| (allowed_macro) |
| • Контроль уникальности: декларативная валидация уникальности Hostname_env и Loopback IP в базе данных |
| • Авторасчет статусов узла: В плане -> СМР -> ПНР -> МИГР (на основе заполнения цепочки дат) |
| • L1/L3 авто-связывание: автоматическое заполнение L1 портов на основе данных трансмиссии |
| • Региональные профили: автоматическая привязка параметров (BGP AS, ISIS Area, MTU, Lo pairs, RR1..RR4, TimeZone) |
| • Сквозной аудит: перехват всех изменений и автоматическая запись в таблицу audit_logs |
| ------------------------------------------------------------------------------------------------------------------ |
|
| (SQLAlchemy / asyncpg Connection Pool)
v
+----------------------------------------------------------------------------------------------------------------------+
| БАЗА ДАННЫХ (PostgreSQL 17) |
| |
| [ 1. Таблица узлов: environment_nodes (47 полей) ] |
| • Идентификация: seq_num, hostname_env, site_name, address, model_env, loopback_ip, ptp_address, node_status |
| • Трансмиссия & L1/L3: cross_environment_*, l1_*, l3_*, rrl_* |
| • Интеграция & Сеть: integration_*, isis_area, bgp_as, lo_pairs, bgp_rr1..rr4 |
| • СМР / ПНР: cmr_date, pnr_date, init_version, executor, cmr_pnr_note |
| • Миграция & BMC: migration_date, migrator, migration_note, bmc_version, bmc_update_date, bmc_engineer |
| • Региональные параметры: region, macro, power_type, timezone |
| |
| [ 2. Справочник регионов: network_region_profiles ] [ 3. Справочник пользователей: users ] |
| • Шаблоны BGP/ISIS/MTU/RR по регионам • id, username, password_hash, full_name, role, |
| allowed_macro (text[]), is_active, created_at |
| |
| [ 4. Таблица аудита: audit_logs ] |
| • id, node_id, field_name, old_val, new_val, author, created_at |
+----------------------------------------------------------------------------------------------------------------------+
Ключевые преимущества перед таблицей Excel
- Персональная ответственность и гибкий RBAC: Каждый инженер работает под собственной учётной записью с хешированием паролей через
bcrypt. Реализована гранулярная матрица прав (admin,engineer,viewer) с возможностью привязки пользователя сразу к нескольким макрорегионам (мультирегиональный доступ) для фильтрации зоны видимости узлов. - Исключение адресных коллизий: База данных на уровне ограничений целостности (
UNIQUE) блокирует дублированиеHostname environmentиLoopback IP. - Нестираемый аудит каждого действия (Audit Trail): Автоматическая фиксация каждого изменения поля в таблице
audit_logsс записью автора, даты, старого и нового значений. - Автоматизация бизнес-логики и автоподстановки:
- Автоматический расчёт жизненного цикла узла (
В плане→СМР→ПНР→МИГР) по цепочке заполнения дат. - Автоподстановка фамилии авторизованного инженера при установке дат СМР, ПНР, Миграции и BMC.
- Автоматическая привязка L1-портов на основе данных трансмиссии подключения.
- Автоматический расчёт жизненного цикла узла (
- Динамические региональные профили: Автоподстановка параметров маршрутизации (
BGP AS,ISIS Area,BGP RR1..RR4,Lo pairs,MTU,TimeZone) из справочников без необходимости ручного ввода. - Прямой мост к автоконфигурации (ZTP): Мгновенная генерация и скачивание готовых файлов конфигурации
.cfg(с разделением шаблонов под разные модели оборудования), а также предпросмотрCLI-команд прямо из интерфейса. - Интеграция с рабочими местами инженеров: Запуск
SSH-сессий в терминальном клиенте (SecureCRT / PuTTY) в один клик по Loopback IP через URI-схемуssh://. - Двусторонний обмен с Excel: Возможность гибкой пакетной загрузки оборудования через импорт и выгрузки актуальных отчётов в
.xlsxс фильтрацией по макрорегионам. - Защита периметра и изоляция клиентов: Защита API и веб-интерфейса сервисом Fail2ban (отслеживание автоматических сканеров и бан IP-адресов при повторных
401 Unauthorizedошибках подбора паролей) и выделенный порт57218для безопасного подключения десктопного тонкого клиента.
Архитектурный доклад: Принципы функционирования платформы
Уровень 1. Входные каналы и пользователи
Уровень обеспечивает взаимодействие различных типов клиентов с системой через независимые сценарии:
Инженеры (Web UI / SPA): Пользователи могут работать через современный веб-интерфейс в браузере. Интерфейс построен по принципуSingle Page Application (SPA), позволяя выполнять инлайн-редактирование ячеек таблицы на лету без перезагрузки всей страницы.Десктопный тонкий клиент (Windows GUI / pywebview): Автономное приложение в виде единого исполняемого файла exe, работающее через выделенный сетевой порт57218без необходимости открывать браузер общего назначения.Внешние интеграции и CLI (REST API): Сторонние Python-скрипты, модули автоматизации и сетевые утилиты обращаются напрямую к JSON API для пакетного импорта, экспорта данных и генерации конфигурационных файлов через вызовы cURL.Терминальные клиенты (SecureCRT / PuTTY): В ячейках с Loopback IP реализована интеграция с операционной системой клиента через URI-схемуssh://. Клик по IP-адресу инициирует открытие преднастроенного SSH-клиента на рабочей станции инженера без необходимости ручного копирования адреса.
Уровень 2. Веб-сервер, обратный прокси и безопасность (Nginx + Fail2ban + Iptables)
Выступает первой точкой входа сетевого трафика, обеспечивая производительность, проксирование и многоуровневую защиту периметра хоста:
Межсетевой экран ядра (Iptables): Базовый рубеж фильтрации. Отсекает паразитный трафик до уровня сокетов приложений, пропуская соединения строго на целевые порты (SSH, 443 для веб-интерфейса и 57218 для выделенного клиента), а также динамически применяет правила блокировки атакующих хостов от Fail2ban.SSL Termination & Маршрутизация: Nginx расшифровывает защищённые HTTPS-сессии (порт 443), снимая нагрузку с ядра приложения, и проксирует HTTP-запросы на внутренний ASGI-сервер Uvicorn через высокоскоростной сокет/var/www/html/app/environment_inventory.sock.Выделенный шлюз для десктопного клиента: Отдельныйserver-блок Nginx на порту57218осуществляет изолированное проксирование трафика от приложения с корректной передачей заголовков авторизации (Authorization,WWW-Authenticate).Двухуровневая активная защита (Fail2ban):nginx-auth-fail— непрерывно мониторитaccess.log, отслеживая повторные коды401 Unauthorizedи блокируя попытки подбора паролей к API и интерфейсу.nginx-custom-bad— выявляет автоматизированные сканеры, вредоносные ботнеты, попытки обращения к скрытым путям (.env,wp-login,phpmyadmin) и некорректные HTTP-запросы (коды 400, 403, 404, 444), отправляя нарушителей в бан еще до того, как они создадут паразитную нагрузку.
Статический контент: Отдача вспомогательных файлов (CSS-стили, JS-библиотеки, SVG-иконки) осуществляется напрямую через Nginx в обход Python, что гарантирует мгновенную загрузку UI-компонентов.
Уровень 3. Ядро приложения (FastAPI / Uvicorn / Python Core)
Центральный слой платформы, объединяющий пользовательский интерфейс, API-эндпоинты и строгую бизнес-логику.
1. Фронтенд & Табличный движок (Tabulator 6.2)
- Управляет отображением 47 параметров сетевого оборудования, сгруппированных по 10 тематическим блокам.
- Перехватывает события редактирования ячеек (
cellEdited), проверяет права доступа текущей роли инженера и инициирует асинхронную синхронизацию с бэкендом. - Предоставляет контекстное меню для просмотра CLI-команд, скачивания файлов
.cfgи очистки дат. - Адаптивная смена темы (☀️ / 🌙): Реализовано бесшовное переключение между светлой и тёмной темами оформления с динамической сменой CSS-переменных и стилей табличного ядра Tabulator (
tabulator_midnight.min.css/tabulator_simple.min.css), а также автоматическим сохранением выбранного режима вlocalStorageбраузера.
2. API & Backend Endpoints
/— Рендеринг основного SPA-шаблона./api/v1/me— Идентификация пользователя, передача профиля, ролевых ограничений и списка доступных макрорегионов./api/v1/nodes— Основной CRUD-маршрут для получения и сохранения параметров узлов с серверной фильтрацией по закрепленным за пользователем округам./api/v1/config/view/{id}и/download/{id}— Движок ZTP: рендерит шаблоны Jinja2 (start_config_model.j2иstart_config_environment.j2) в готовые конфигурационные файлы на основе параметров узла./api/v1/import/excelи/export/excel— Модули пакетной обработки данных с использованием библиотек pandas и openpyxl.
3. Модуль бизнес-логики и безопасности
- Ролевая модель (RBAC) и мультирегиональность: Авторизация через
HTTP Basic Authс валидацией паролей функциейget_password_hash(Bcrypt). Поддерживается закрепление инженера как за одним, так и за группой макрорегионов (например, одновременноЮгиПоволжье). Для ролиviewerдоступно редактирование только строго определённого набора полей (блоки СМР, ПНР, Миграция, BMC). - Авторасчёт жизненного цикла: Статус узла (
node_status) пересчитывается автоматически: при наличии даты СМР статус становитсяСМР, при наличии СМР + ПНР —ПНР, при наличии всех трёх дат (СМР + ПНР + Миграция) —МИГР. - Автоподстановка исполнителей: При внесении или изменении дат система извлекает фамилию авторизованного пользователя и автоматически заполняет поля
executor,migratorилиbmc_engineer. - Авто-связывание L1/L3: При указании узла или порта в блоках трансмиссии для различных вендоров, поля уровня
L1 Node nameиL1 Portзаполняются автоматически. - Региональные профили: При выборе региона система автоматически подставляет параметры
BGP AS,ISIS Area,MTU,TimeZone, а для специализированных регионов распределяет пары используемых адресовBGP RR1..RR4.
Уровень 4. База данных (PostgreSQL)
Слой хранения данных, обеспечивающий целостность, уникальность, аудит и разграничение прав доступа.
- Таблица
environment_nodes(47 полей): Хранит полную цифровую модель каждого узла. Декларативные ограничения целостности на уровне СУБД (UNIQUE) для полейhostname_environmentиloopback_ipисключают появление дубликатов и коллизий в сети. - Таблица
network_region_profiles: Служит нормализованным справочником параметров для всех регионов и макрорегионов (Юг, Поволжье, Центр, Северо-Запад, Москва). - Таблица
users(Справочник пользователей и мультирегиональный RBAC): Хранит данные инженеров (username,password_hash,full_name), их роли (admin,engineer,viewer) и перечень закрепленных макрорегионов (allowed_macroв виде массива или нормализованного списка), что позволяет гибко комбинировать зоны ответственности сотрудников. - Таблица
audit_logs(Audit Trail): Нестираемый журнал аудита. Любое изменение любого параметра через веб-интерфейс или API фиксируется отдельной записью с указаниемnode_id, имени поля, старого значения, нового значения, логина автора и точной метки времени.
Реализованный стек устраняет риски потери информации, блокирует коллизии IP-адресации на этапе ввода, гарантирует персональную ответственность сотрудников при мультирегиональной работе, надежно защищает сетевой периметр от атак перебора паролей и подозрительных бот-сканеров, сокращает рутинные операции благодаря сквозной автоматизации и автогенерации ZTP-конфигураций.
От концептуальной схемы к реализации
Красивая архитектура на диаграмме не имеет ценности без предсказуемой и легко масштабируемой реализации. Чтобы система выдерживала параллельную работу инженеров, мгновенно реагировала на инлайн-редактирование и не создавала накладных расходов на серверное железо, кодовая база была выстроена по модульному принципу.
Ниже представлена внутренняя механика ядра: файловая структура каталога приложения, специфика работы асинхронных сессий
SQLAlchemy поверх драйвера asyncpg и привязка сервиса к системному демону systemd.
Внутреннее устройство и кодовая база проекта
Окружение: Каталог /var/www/html/app, системный Python (без venv), кэш байткода вынесен в /home/user/.pycache, ASGI-сервер Uvicorn с сокетом /var/www/html/app/environment_inventory.sock (плюс проксирование через Nginx на порт 57218 для Windows тонкого клиента), защита периметра через Iptables и Fail2ban (nginx-auth-fail / nginx-custom-bad), СУБД net_inventory (PostgreSQL 17).
Инженерная ремарка: В целях информационной безопасности реальный боевой код модулей, токены, реквизиты авторизации и топологические структуры в статье опущены. Ключевые фрагменты логики приведены в виде абстрактных концептуальных сниппетов и базовых интерфейсов.
1. Дерево файлов и каталогов проекта
/var/www/html/app/
│
├── static/ # Статические ресурсы веб-интерфейса
│ ├── css/ # Таблицы стилей оформления
│ ├── js/ # JavaScript-модули и вендорные библиотеки
│ └── favicon.svg # Векторная иконка сайта (Favicon)
│
├── templates/ # HTML-страницы и шаблоны конфигураций Jinja2
│ ├── index.html # Главная страница SPA-интерфейса (47 полей + Tabulator 6.2 + мультирегиональный RBAC)
│ ├── start_config_environment.j2 # Эталонный Jinja2-шаблон генерации стартовых конфигураций environment
│ └── start_config_model.j2 # Jinja2-шаблон генерации конфигураций для линейки моделей
│
├── scripts/ # Вспомогательные консольные утилиты
│ └── import_excel.py # Асинхронная пакетная загрузка и валидация данных из Excel (.xlsx)
│
├── auth.py # Модуль аутентификации (HTTP Basic Auth, функция get_password_hash на bcrypt, RBAC)
├── database.py # Подключение asyncpg и пул асинхронных соединений PostgreSQL 17
├── models.py # Декларативные модели SQLAlchemy 2.0 (User, EnvironmentNode, NetworkRegionProfile, AuditLog)
├── rules.py # Движок авторасчёта бизнес-правил (BGP AS, /30 gateway, дефолты MTU/Speed)
├── main.py # Точка входа FastAPI (API-эндпоинты, мультирегиональная фильтрация, ZTP, экспорт XLSX)
└── environment_inventory.sock # Активный UNIX-сокет межпроцессного взаимодействия Nginx и Uvicorn
2. Назначение и состав ключевых файлов
1. auth.py — Аутентификация, хеширование паролей и гибкий RBAC
Обеспечивает безопасность приложения и разграничение зон ответственности:
- Хеширование и валидация паролей с использованием
bcryptчерез функциюget_password_hashи методverify_password. - Асинхронная зависимость
get_current_userдля валидации учетных данных HTTP Basic Auth, с обязательной проверкой флага активности учетной записи (is_active) без необходимости физического удаления пользователей из базы. - Поддержка ролей
admin,engineer(полный доступ к сетевым параметрам) иviewer: для наблюдателей действует белый списокVIEWER_ALLOWED_FIELDS, разрешающий редактировать только фактические даты и отметки этапов (СМР, ПНР, Миграция, BMC) при полном запрете на изменение сетевой топологии и добавление узлов. - Поддержка мультирегиональности: разбор и валидация массива разрешенных пользователю макрорегионов (
allowed_macro, типtext[]), позволяющая гибко закреплять инженера сразу за несколькими округами с разной ролью (например, одновременноengineer-Югиviewer-Поволжье).
Концепт реализации хеширования и валидации пользователя:
from passlib.context import CryptContext
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from database import get_db
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
security = HTTPBasic()
def verify_password(plain_password: str, hashed_password: str) -> bool:
return pwd_context.verify(plain_password, hashed_password)
async def get_current_user(credentials: HTTPBasicCredentials = Depends(security), db = Depends(get_db)):
user = await get_user_by_username(db, credentials.username)
if not user or not verify_password(credentials.password, user.password_hash):
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, headers={"WWW-Authenticate": "Basic"})
if not user.is_active:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Учетная запись отключена")
return user
2. database.py — Асинхронный пул соединений с БД
Инициализирует асинхронный движок SQLAlchemy 2.0 поверх драйвера asyncpg:
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
DATABASE_URL = "postgresql+asyncpg://netadmin:SECURE_PASS@127.0.0.1:5432/net_inventory"
engine = create_async_engine(DATABASE_URL, echo=False, pool_size=10, max_overflow=5)
AsyncSessionLocal = async_sessionmaker(bind=engine, expire_on_commit=False)
async def get_db():
async with AsyncSessionLocal() as session:
yield session
3. models.py — Модели данных SQLAlchemy 2.0
Содержит декларативные модели с методом to_dict(), безопасно сериализующим даты и IP-адреса в JSON-формат:
User: хранит системные идентификаторы (id), учетные записи (username, password_hash), ФИО инженера (full_name) для автоподстановки в этапы работ, системную роль (role: admin, engineer, viewer), массив разрешенных округов (allowed_macro: text[]), статус активности (is_active: bool) для мгновенного отзыва доступа без удаления аккаунта и таймстамп регистрации (created_at).EnvironmentNode: цифровая модель узла (47 атрибутов). Включает ограничения целостности (UNIQUE) на поляhostname_environmentиloopback_ipдля исключения адресных коллизий на уровне СУБД.NetworkRegionProfile: эталонные региональные параметры (BGP AS, ISIS Area, Route Reflectors RR1..RR4, пары Lo pairs, MTU, TimeZone).AuditLog: нестираемый журнал аудита изменений (node_id, field_name, old_val, new_val, author, created_at).
Концепт структуры модели узла:
from sqlalchemy import Column, Integer, String, Date, UniqueConstraint
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
pass
class EnvironmentNode(Base):
__tablename__ = "environment_nodes"
id = Column(Integer, primary_key=True)
hostname_environment = Column(String(64), unique=True, nullable=False, index=True)
loopback_ip = Column(String(45), unique=True, nullable=False, index=True)
node_status = Column(String(32), default="В плане")
macro_region = Column(String(64), nullable=False)
# Поля жизненного цикла, трансмиссии и BGP...
4. rules.py — Движок авторасчёта и бизнес-правил
Асинхронная функция apply_business_rules() пересчёта параметров перед сохранением и генерацией конфигураций:
- Автоопределение порта интеграции и скорости по модели оборудования.
- Динамический поиск и подстановка эталонного сетевого профиля региона из базы данных PostgreSQL 17 (BGP AS, ISIS Area, Route Reflectors RR1..RR4, Lo pairs, MTU).
- Автоматический расчет IP-шлюза соседа (
gateway_ip) в подсети /30 для командip routeиping. - Автоматический расчёт жизненного цикла узла (
node_status: «В плане», «СМР», «ПНР», «МИГР») по цепочке дат. - Автоподстановка фамилии авторизованного инженера в поля исполнителей (
executor,migrator,bmc_engineer) при фиксации дат. - Автоматическая трансляция параметров оптической трансмиссии (заполненная в соответствующей ячейке различных вендоров) на уровень L1 (L1 Node name, L1 Port).
- Валидация и нормализация IP-адресов через
ipaddress.
Концепт расчета жизненного цикла узла:
def resolve_lifecycle_status(cmr_date, pnr_date, migration_date) -> str:
if migration_date:
return "МИГР"
if pnr_date:
return "ПНР"
if cmr_date:
return "СМР"
return "В плане"
5. main.py — REST API, ZTP-генератор, Экспорт/Импорт и Контроль прав
- GET /: Отдаёт интерфейс операторской таблицы Tabulator.
- GET /api/v1/me: Получение данных текущего пользователя, его роли и списка всех разрешённых ему макрорегионов.
- GET /api/docs: Интерактивная Swagger-документация с тестированием всех методов.
- GET /api/v1/meta/regions: Выдача списка доступных регионов и сетевых эталонов.
- GET /api/v1/nodes: Быстрая асинхронная отдача записей таблицы в формате JSON с фильтрацией: пользователи видят только узлы, входящие в назначенные им макрорегионы (мультивыборка по
allowed_macro). - POST /api/v1/nodes: Сохранение inline-правок с валидацией региона, проверкой прав полей (RBAC), автоподстановкой ответственных инженеров и транзакционной записью каждого изменения в
audit_logs. При ошибке аутентификации отдает HTTP 401, попадающий под мониторинг Fail2ban. - GET /api/v1/config/view/{node_id}: Предпросмотр CLI-конфигурации узла на базе шаблонов Jinja2.
- GET /api/v1/config/download/{node_id}: Скачивание файла
.cfgс корректным именем хоста под целевую аппаратную платформу. - GET /api/v1/export/excel: Потоковая выгрузка актуальной базы в XLSX с помощью
pandasиopenpyxlс учетом региональных прав пользователя. - POST /api/v1/import/excel: Пакетный импорт данных из Excel с проверкой прав доступа, нормализацией полей и валидацией бизнес-правил.
Концепт фильтрации узлов по мультирегиональному профилю:
from fastapi import APIRouter, Depends
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
@router.get("/api/v1/nodes")
async def get_nodes(user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
stmt = select(EnvironmentNode)
if user.role != "admin":
stmt = stmt.where(EnvironmentNode.macro_region.in_(user.allowed_macro))
result = await db.execute(stmt)
return [node.to_dict() for node in result.scalars().all()]
6. templates/ — Шаблоны конфигураций (ZTP Jinja2)
index.html: дашборд оператора на Tabulator.js для просмотра, фильтрации и ручного управления сетевым оборудованием.start_config_environment.j2: эталонный шаблон для базовой линейки используемого оборудования.start_config_model.j2: специализированный шаблон начальной конфигурации для оборудования определенной линейки.
3. Шлюз Nginx, порт 57218 и активная эшелонированная защита (Fail2ban + Iptables)
Для подключения автономного десктопного клиента на Windows (сборка на базе pywebview в один .exe-файл) и защиты API от атак перебора паролей и сетевого сканирования развернута связка Nginx, Fail2ban и правил ядра Linux (Iptables):
- Выделенный порт для десктоп-клиента: В Nginx поднят отдельный блок
server { listen 57218; }, который проксирует вызовы напрямую в сокет/var/www/html/app/environment_inventory.sockс обязательным пробросом заголовковAuthorizationиWWW-Authenticate. - Джейл авторизации (
nginx-auth-fail): Непрерывно анализирует/var/log/nginx/access.log, отслеживая попытки несанкционированного доступа по коду ответа401 Unauthorized. При превышении порога неудачных попыток атакующий IP-адрес автоматически изолируется на транспортном уровне сетевым фильтром ядра (через динамические сеты nftables или цепочки iptables). - Джейл поведенческой фильтрации (
nginx-custom-bad): Анализирует лог обращений на предмет вредоносной активности (поиск скрытых файлов.env,.git, админок, зондирование уязвимостей, malformed-запросы с кодами 400, 403, 404, 444) и превентивно отправляет в бан сетевые сканеры и ботнеты.
Конфигурация блока Nginx для тонкого клиента:
server {
listen 57218;
server_name БЕЛЫЙ_IP_СЕРВЕРА;
location / {
proxy_pass http://unix:/var/www/html/app/environment_inventory.sock;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Authorization $http_authorization;
proxy_pass_header Authorization;
proxy_pass_header WWW-Authenticate;
}
}
Фильтры Fail2ban (/etc/fail2ban/filter.d/):
# 1. Отлов брутфорса и 401 Unauthorized (nginx-auth-fail.conf)
[Definition]
failregex = ^<HOST> - .* "(GET|POST).*" 401
ignoreregex =
# 2. Отлов паразитных сканеров, ботов и аномалий (nginx-custom-bad.conf)
[Definition]
failregex = ^<HOST> - .* "(GET|POST|HEAD) .*(/wp-.*|/admin.*|\.env|\.git|phpmyadmin).*" (400|403|404|444)
^<HOST> - .* "(GET|POST).*" 444
ignoreregex =
Блокировка нарушителей на уровне сетевого стека ядра (nftables / iptables):
При срабатывании любого из фильтров Fail2ban блокирует атакующий IP на уровне ядра Linux. В современных дистрибутивах (Debian 12/13) сервис по умолчанию взаимодействует с подсистемой nftables через быстродействующие хэш-множества (sets), отсекая паразитные пакеты до того, как они нагрузят веб-сервер:
# Проверка заблокированных IP в таблице ядра (nftables)
sudo nft list table inet f2b-table
# Мониторинг состояния "тюрем" через клиент Fail2ban
sudo fail2ban-client status nginx-custom-bad
sudo fail2ban-client status nginx-auth-fail
# Для систем со старым бэкендом iptables-multiport (если настроен явно)
sudo iptables -L -n -v | grep f2b-nginx
4. Запуск через Systemd (/etc/systemd/system/environment-inventory.service)
Конфигурация сервиса для работы с Unix-сокетом и изоляцией байткода в /home/user/.pycache:
[Unit]
Description=Environment Telecom Inventory (FastAPI Core)
After=network.target postgresql.service
[Service]
User=user
Group=www-data
WorkingDirectory=/var/www/html/app
Environment=PYTHONPYCACHEPREFIX=/home/user/.pycache
ExecStart=/usr/bin/uvicorn main:app --uds /var/www/html/app/environment_inventory.sock --workers 2 --umask 007
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
5. Сценарий масштабирования: вынос базы данных на удалённый сервер СУБД
Архитектура сервиса позволяет в любой момент вынести СУБД PostgreSQL 17 на выделенный хост (физический сервер или отдельную ВМ) для изоляции нагрузки, масштабирования и централизованного резервного копирования.
Шаг 1. Перенос существующей базы на новый сервер
- Создание дампа на текущем хосте:
pg_dump -U netadmin -h 127.0.0.1 -d net_inventory -F c -b -v -f /tmp/net_inventory_backup.dump - Передача файла дампа на сервер СУБД:
scp /tmp/net_inventory_backup.dump user@192.168.1.100:/tmp/ - Создание роли, пустой БД и восстановление данных на новом сервере:
# Создание пользователя и базы в PostgreSQL 17 sudo -u postgres psql -c "CREATE USER netadmin WITH PASSWORD 'SECURE_DB_PASSWORD';" sudo -u postgres psql -c "CREATE DATABASE net_inventory OWNER netadmin;" # Развертывание дампа pg_restore -U netadmin -d net_inventory -v /tmp/net_inventory_backup.dump
Шаг 2. Настройка сетевого доступа на удалённом сервере PostgreSQL 17
- Разрешить приём входящих сетевых соединений (
postgresql.conf):
В конфигурационном файле/etc/postgresql/17/main/postgresql.confзадаем директиву:listen_addresses = '*' - Разрешить авторизацию с IP веб-сервера FastAPI (
pg_hba.conf):
В конец файла/etc/postgresql/17/main/pg_hba.confдобавить правило доступа для пользователяnetadmin(например, с адреса192.168.1.50):# TYPE DATABASE USER ADDRESS METHOD host net_inventory netadmin 192.168.1.50/32 scram-sha-256 - Ограничение подключений через межсетевой экран (
iptables):sudo iptables -A INPUT -p tcp -s 192.168.1.50 --dport 5432 -j ACCEPT - Перезапуск службы СУБД:
sudo systemctl restart postgresql
Шаг 3. Переключение FastAPI-бэкенда на удалённую базу данных
- Обновление строки подключения в
database.py:
Изменить IP-адрес удаленного сервера PostgreSQL (например,192.168.1.100):DATABASE_URL = "postgresql+asyncpg://netadmin:SECURE_DB_PASSWORD@192.168.1.100:5432/net_inventory" - Корректировка Systemd-юнита (
environment-inventory.service):
Исключить локальную зависимостьpostgresql.serviceиз директивыAfter:[Unit] Description=Environment Telecom Inventory (FastAPI Core) After=network.target - Применение изменений и перезапуск сервиса:
sudo systemctl daemon-reload sudo systemctl restart environment-inventory.service
Шаг 4. Проверка статуса и журналов сервиса
Убедиться в успешной инициализации пула подключений к удалённой СУБД:
systemctl status environment-inventory.service
journalctl -u environment-inventory.service -n 30 --no-pager
Главный нюанс — Безопасность (Важно!)
При выносе базы данных за пределы локальной подсети трафик между серверами будет ходить через открытый интернет; передавать пароли и сетевые топологии в чистом виде небезопасно.
Для работы через интернет обязательно:
- Использовать SSL-шифрование в PostgreSQL: Настроить сертификаты (параметр
?ssl=requireв строкеDATABASE_URL), чтобы весь сетевой трафик между FastAPI и базой данных шифровался. - Использовать защищенный канал (VPN / Tailscale / WireGuard / IPsec): Самый надежный вариант для распределенной архитектуры — поднять между серверами частную виртуальную сеть (VPN). В таком случае серверы будут видеть друг друга по безопасным внутренним IP (например,
10.8.0.x), а порт СУБД5432будет полностью изолирован от публичного сканирования.
Итоги внедрения и эксплуатационные выводы
Отказ от ручного ведения учета кардинально изменил рабочий процесс учета, эксплуатации и ввода оборудования:
- Единый источник правды (Single Source of Truth): Полностью ушли от десятков разрозненных региональных Excel-файлов, пересылаемых в чатах и сетевых папках. База данных централизована на выделенном сервере, что гарантирует абсолютную консистентность данных и исключает работу с неактуальными версиями топологии.
- Ликвидация сетевых коллизий: Ограничения уникальности на уровне СУБД (
UNIQUE) полностью исключили дублирование Loopback IP и хостнеймов — человеческий фактор при заведении нового оборудования сведен к нулю. - Ускорение подготовки узлов (ZTP): Время генерации эталонной конфигурации узла сократилось с 15–20 минут ручной подстановки параметров по текстовым файлам до 2 секунд (один клик для экспорта выверенного
.cfg). - Прозрачность этапов строительства: Благодаря автоматическому расчёту статусов (
В плане → СМР → ПНР → МИГР) и сквозному журналуaudit_logsотпала необходимость в бесконечных статус-митингах и выяснениях, кто и когда изменил стыковочные порты. - Защищенный периметр: Комбинация изоляции прав по макрорегионам (
allowed_macro), выделенного порта для тонкого клиента и активной блокировки сканеров через Fail2ban обеспечила стабильную работу сервиса без риска компрометации критической инфраструктуры.
Вектор дальнейшего развития: Следующий логичный шаг архитектуры — трансформация платформы из учетной системы (Source of Truth) в активный оркестратор: добавление модуля пуша конфигураций прямо на узлы через Scrapli / Netmiko и интеграция со сквозным SNMP/Telemetry-мониторингом состояния портов в реальном времени. Ну а дальше... Реализация и интеграция будущих идей, которые пока еще не успели сформироваться в мысль.
Здесь я попытался показать техническую реализацию своей идеи — так, как вижу её сам. Статья не претендует на универсальное руководство к действию, поэтому здесь и отсутствуют длинные "портянки" рабочего кода: главное — передать архитектурную суть.