Перейти к содержанию

eID — консоль администратора (панель оператора)

Руководство для операторов и разработчиков: консоль администратора платформы eID — это связка операторской панели на Next.js (admin/, порт 3001) и Go-адмиn API (/v3/admin/*). Через неё оператор управляет гражданами, устройствами, сертификатами, сессиями, KYC/DAN, организациями (Legal Person), доверяющими сторонами (RP), журналами аудита и статусом системы.

Отдельное приложение. Консоль администратора — полностью отдельное приложение Next.js относительно web/ (демо RP для граждан, порт 3000). Дерево кода: admin/src/.

1. Чем управляет

Раздел Возможности
Граждане (/users) Поиск (etsi / РД / имя / documentNumber), детали + устройства + сертификаты + аудит
Устройства (/devices) Список/поиск, детали, деактивация утерянных устройств
Сертификаты (/certificates) Список/поиск, статус, отзыв
PKI (/pki, /org-ca) Состояние CA, пути OCSP/CRL, статус QSCD для e-Seal
Организации (/organizations) Регистрация Legal Person, представители, выпуск сертификата e-Seal
RP (/rps) Регистрация/редактирование/деактивация/реактивация RP, ротация секрета, управление подсистемами
Согласования (/approvals) Правило четырёх глаз: чувствительные операции подтверждает второй администратор
Аудит (/audit) Журнал всех операций + экспорт в CSV (eIDAS/ISO 27001)
Администраторы (/admins) Создание/смена роли/деактивация администраторов (только SUPER_ADMIN)
Система (/system) Версия, uptime, НЕсекретный статус конфигурации/HSM/KYC/PKI

2. Архитектура — BFF (браузер никогда не видит секрет)

Консоль администратора построена по паттерну Backend-for-Frontend (BFF). Браузер НИКОГДА не видит токен админской сессии — токен хранится только в httpOnly-cookie Next-сервера.

Браузер ──fetch──▶ Next BFF (порт 3001) ──Bearer──▶ Go admin API (/v3/admin/*)
  (cookie:             /api/login, /api/mfa,             middleware adminAuth
   admin_session,      /api/proxy/[...path]              + requireCap (RBAC)
   httpOnly)
  • Клиент → BFF. Когда страницы вызывают api("users?q=…"), запрос идёт на маршрут /api/proxy/* (admin/src/lib/client.ts).
  • BFF → Go. Прокси-маршрут читает токен сессии из cookie и передаёт его как Authorization: Bearer <token> на ${ADMIN_BACKEND_URL}/v3/admin/<path> (admin/src/app/api/proxy/[...path]/route.ts). Токен никогда не попадает в браузер, поэтому его нельзя похитить через XSS.
  • Защита. Белый список против path-traversal ([A-Za-z0-9._-], запрещает ./..), сверка хоста Origin/Referer с host на изменяющих запросах (эшелонированная защита от CSRF в дополнение к sameSite=strict) и маскирование upstream-ошибок 5xx общим сообщением.
  • Guard аутентификации. Layout (app) вызывает getMe() на сервере и перенаправляет на /login, если валидной сессии нет (admin/src/app/(app)/layout.tsx).
  • CSP/заголовки безопасности. admin/src/middleware.ts — nonce + strict-dynamic, connect-src 'self', frame-ancestors 'none', HSTS и другие.

Граница доверия. На стороне Go маршруты /v3/admin/* защищены middleware adminAuth (server/internal/httpapi/server.go). Порядок: (1) Authorization: Bearer <токен сессии> → полноценный RBAC; (2) X-Admin-Key → аварийный (break-glass) SUPER_ADMIN (сравнение за константное время); (3) только в профиле dev, если SMARTID_ADMIN_API_KEY пуст — открытый SUPER_ADMIN. На staging/prod fail-open недопустим НИКОГДА: обязателен Bearer либо break-glass-ключ.

3. Вход + MFA

Сценарий: email/пароль → TOTP (MFA) → токен сессии. При первом входе пользователь регистрирует аутентификатор по QR-коду.

Шаг Маршрут BFF Эндпойнт Go Описание
1. Вход POST /api/login POST /v3/admin/auth/login Проверка email/пароля; при успехе — токен со scope mfa
2. MFA POST /api/mfa POST /v3/admin/auth/mfa Код TOTP → токен со scope session
3. Выход POST /api/logout POST /v3/admin/auth/logout Удаление cookie (токен stateless)
  • Пароль. Хешируется и хранится через internal/admin/password.go; сообщения об ошибках обобщены («неверный email или пароль») для защиты от timing-атак и перебора.
  • TOTP (MFA). RFC 6238, HMAC-SHA1, шаг 30 секунд, 6 цифр — реализовано своими силами без внешней библиотеки (server/internal/admin/totp.go). При первом входе сервер возвращает URI otpauth:// и секрет; страница логина превращает его в QR-код для добавления в Google/Microsoft Authenticator. У кода есть окно ±1 шаг (расхождение часов), а использованный счётчик сохраняется, чтобы блокировать replay (RFC 6238 §5.2).
  • Токен. Stateless-токен, подписанный HMAC-SHA256 (без JWT-библиотеки), <b64url(payload)>.<b64url(HMAC)> (server/internal/admin/token.go). Scope mfa — ~5 минут, scope session — ~1 час.
  • Cookie. admin_mfa (5 минут, ожидание MFA) и admin_session (1 час) — обе httpOnly, sameSite=strict, в продакшене также secure.
  • Rate limit. Вход (по IP+email) и MFA (по IP) ограничиваются; при превышении — 429 + Retry-After.
  • Смена пароля. POST /v3/admin/auth/password — вошедший администратор меняет собственный пароль (с подтверждением текущего). Отдельная capability не требуется.

4. RBAC — роль и capability

Каждый маршрут объявляет требуемую capability; middleware requireCap проверяет, есть ли эта capability у роли вошедшего администратора (принцип наименьших привилегий). Матрица: server/internal/admin/roles.go.

Capabilities: rp:read, rp:write, org:read, org:write, user:read, device:read, device:revoke, cert:read, cert:revoke, session:read, audit:read, admin:manage, config:read, config:write.

Роль → capability:

Роль Предоставленные capabilities
SUPER_ADMIN все capabilities (включая управление администраторами)
RP_OPERATOR rp:read rp:write org:read org:write user:read session:read audit:read
SUPPORT rp:read org:read user:read device:read device:revoke cert:read session:read audit:read
AUDITOR rp:read org:read user:read device:read cert:read session:read audit:read config:read
SECURITY_OFFICER org:read user:read device:read device:revoke cert:read cert:revoke session:read audit:read config:read

Если capability недостаточно, Go-сторона возвращает 403 («недостаточно прав для этой операции»). Навигация во фронтенде показывает все страницы, но неавторизованная операция блокируется ответом 403 на бэкенде.

5. Основные возможности и эндпойнты /v3/admin/*

Все находятся за adminAuth. Требуемая capability указана рядом.

Гражданин / устройство / сертификат / сессия (чтение)

Метод + путь Cap Описание
GET /users?q=&limit=&offset= user:read Поиск граждан (etsi/РД/имя); если ничего не найдено — поиск владельца по documentNumber
GET /users/{etsi} user:read Гражданин + устройства + сертификаты + аудит
GET /devices?q=&active= device:read Поиск устройств
GET /devices/{documentNumber} device:read Детали устройства
GET /certificates?q=&status= cert:read Поиск сертификатов
GET /users/{etsi}/certificates cert:read История сертификатов гражданина
GET /sessions/{sessionId} session:read Безопасный просмотр сессии

Секретный материал НИКОГДА не возвращается. Функции представления (userView/deviceView/certView/sessionView, handlers_admin_read.go) вырезают handle HSM, Enc(x_client), модуль Пайе, секрет/токен сессии и объёмный base64 сертификата, показывая только безопасные поля.

RP (доверяющая сторона)

Метод + путь Cap Описание
POST /relying-parties rp:write Регистрация RP — API-секрет возвращается ТОЛЬКО здесь и ОДИН раз
GET /relying-parties, GET /relying-parties/{id} rp:read Список / детали
PATCH /relying-parties/{id} rp:write Редактирование
POST /relying-parties/{id}/deactivate | /reactivate rp:write Деактивация / реактивация
POST /relying-parties/{id}/rotate-secret rp:write Новый секрет (ТОЛЬКО здесь, ОДИН раз)

Подсистема RP. Подсистема автоматически регистрируется самим RP (find-or-create); администратор может только просматривать / переименовывать / деактивировать / объединять:

Метод + путь Cap Описание
GET /relying-parties/{id}/subsystems rp:read Список подсистем внутри RP
PATCH /relying-parties/{id}/subsystems/{sid} rp:write Изменение отображаемого имени подсистемы
POST /relying-parties/{id}/subsystems/{sid}/deactivate | /activate rp:write Деактивация / активация
POST /relying-parties/{id}/subsystems/{sid}/merge rp:write Объединение с другой подсистемой

Полное руководство по интеграции RP: RP_INTEGRATION.md. Модель и протокол подсистем: RP_SUBSYSTEMS.md.

Отзыв сертификатов + PKI

Метод + путь Cap Описание
POST /certificates/{serial}/revoke cert:revoke Отзыв по серийному номеру (OCSP/CRL + статус + деактивация устройства); {reason} 0–10
POST /devices/{documentNumber}/deactivate device:revoke Деактивация утерянного устройства (по умолчанию reason=1 keyCompromise)
GET /pki/status config:read Subject/серийный номер/срок действия CA, число отзывов, URL OCSP/CRL, Org CA, QSCD для e-Seal

KYC / DAN

Сценарий KYC в основном проходит через мобильное приложение и callback DAN (/v3/kyc/*, вне консоли администратора — server.go mountKyc). GET /v3/kyc/methods показывает активные методы KYC (dan / gsign / passport / citizenCard). Блок kyc в системном GET /v3/admin/system отражает НЕсекретный статус провайдера KYC.

Метод + путь Cap Описание
GET /organizations?q= org:read Список/поиск
GET /organizations/{etsi} org:read Детали + представители
POST /organizations org:write Регистрация (PENDING либо сразу ACTIVE)
PATCH /organizations/{etsi} org:write Название / статус (FSM)
POST /organizations/{etsi}/representatives org:write Добавить представителя
DELETE /organizations/{etsi}/representatives/{id} org:write Деактивировать представительство
POST /organizations/{etsi}/seal-certificate org:write Выпустить сертификат e-Seal (NTRMN)

Подключение организации: ORG_ONBOARDING.md.

Аудит + статистика

Метод + путь Cap Описание
GET /audit?type=&subject=&limit=&offset= audit:read Журнал аудита (с пагинацией)
GET /audit/export?type=&subject= audit:read Экспорт в CSV (отчёт eIDAS/ISO 27001)
GET /stats audit:read Метрики панели + тренды

Система / статус HSM (только чтение)

Метод + путь Cap Описание
GET /system config:read Версия, uptime, НЕсекретный статус конфигурации security/kyc/pki/hsm/push

Секреты не раскрываются. adminSystemInfo (handlers_admin_system.go) НИКОГДА не раскрывает ключи, пароли и API-ключи — он лишь указывает, «настроено ли» (например, swMasterKeyConfigured: true).

Управление администраторами (только SUPER_ADMIN)

Метод + путь Cap Описание
GET /admins admin:manage Список администраторов (представление без секретов)
POST /admins admin:manage Новый администратор (email + пароль от 8 символов + роль)
PATCH /admins/{id} admin:manage Смена роли
POST /admins/{id}/deactivate admin:manage Деактивация (вместо удаления — сохраняет аудит)

Процесс согласования по правилу четырёх глаз

При SMARTID_ADMIN_REQUIRE_4EYES=true чувствительная операция (отзыв сертификата, деактивация устройства, деактивация RP) не выполняется сразу — она становится запросом в статусе PENDING (202), который подтверждает другой администратор.

Метод + путь Cap Описание
GET /approvals?status= audit:read Ожидающие запросы
POST /approvals/{id}/approve (capability самой операции, динамически) Подтвердить
POST /approvals/{id}/reject (capability самой операции, динамически) Отклонить

Подтверждающий обязан (а) обладать capability операции (например, отзыв сертификата → cert:revoke) И (б) отличаться от инициатора — попытка подтвердить собственный запрос блокируется ошибкой ErrSelfApproval (403) (handlers_admin_approval.go).

6. Запуск

Фронтенд (консоль администратора):

cd admin
npm run dev     # порт 3001 (next dev -p 3001)
npm run build
npm run lint
npm run test    # vitest

Одна ключевая переменная окружения: ADMIN_BACKEND_URL (адрес Go-бэкенда, по умолчанию http://localhost:8080).

Бэкенд (Go admin API) — запускается из server/ (go run ./cmd/smartid). Переменные окружения для админки/RBAC (server/internal/config/config.go, все с префиксом SMARTID_*):

Env Описание
SMARTID_ADMIN_TOKEN_SECRET HMAC-секрет токена сессии (≥16 символов). Если пуст, админская аутентификация отключена
SMARTID_ADMIN_SEED_EMAIL Email первого SUPER_ADMIN (seed при старте, идемпотентный)
SMARTID_ADMIN_SEED_PASSWORD Пароль первого администратора (только для seed — затем обязательно сменить)
SMARTID_ADMIN_SEED_ROLE Роль для seed (по умолчанию SUPER_ADMIN)
SMARTID_ADMIN_API_KEY Аварийный X-Admin-Key (SUPER_ADMIN вне RBAC; в проде опционально)
SMARTID_ADMIN_REQUIRE_4EYES Требовать подтверждение вторым администратором для чувствительных операций (по умолчанию false)

Конфигурация для dev. В профиле dev, если SMARTID_ADMIN_API_KEY пуст, /v3/admin/* становится открытым SUPER_ADMIN (Bearer не требуется) — только для локальной разработки. На staging/prod такого НЕ происходит никогда; необходимо настроить SMARTID_ADMIN_TOKEN_SECRET + seed либо break-glass-ключ.

7. Ссылки

Исходный код: