ADR: Доверенная среда передачи данных между компонентами Netgap
- Status: Accepted by Andrei Ganiushkin
andrey@ganyushkin.ru - Date: 2026-08-07
- Authors: Andrei Ganiushkin
andrey@ganyushkin.ru - Related issues: -
Context
Netgap реализует паттерн logical airgap и устанавливается на границе доверенного и недоверенного контуров (ADR 0008). Компоненты продукта (шлюзы и сервисы) взаимодействуют между собой по сети, в том числе через сегменты, которые по определению нельзя считать доверенными: трафик между сторонами логического разрыва проходит именно через ту границу, которую продукт призван защищать.
Требуется зафиксировать метод организации доверенной среды передачи данных внутри Netgap — между его собственными компонентами. Доверенная среда означает одновременное выполнение четырёх свойств для каждого внутреннего соединения:
- конфиденциальность — трафик недоступен для чтения третьей стороне;
- целостность — модификация трафика в канале обнаруживается и приводит к разрыву соединения;
- взаимная аутентификация — каждая сторона криптографически доказывает свою подлинность до передачи первого байта прикладных данных; недостаточно аутентифицировать только сервер;
- авторизация отправителя — принимающая сторона проверяет не только «сертификат подписан доверенным CA», но и «этот конкретный компонент имеет право обращаться к этому конкретному сервису».
Существенные ограничения:
- модель угроз включает активного атакующего в сети между компонентами (MITM, спуфинг, несанкционированное подключение постороннего клиента к внутреннему API);
- компоненты могут взаимодействовать по разным прикладным протоколам; свойства доверенной среды не должны зависеть от прикладного протокола;
- поставка — статические бинарные файлы с минимальными зависимостями в целевой среде (ADR 0008): решения, требующие внешнего runtime, sidecar-прокси или агентов в ОС, противоречат модели поставки;
- TLS-стек проекта —
rustls(следствие ADR 0000: чистый Rust, без OpenSSL в поставке (ADR 0008)); - источник сертификатов не ограничивается: заказчик вправе использовать публичный CA или собственный корпоративный УЦ; для разработки и тестовых стендов используется private PKI — см. методичку Работа с сертификатами.
Decision
Все коммуникации между компонентами Netgap выполняются исключительно по mTLS (TLS 1.3) независимо от прикладного протокола, со строгой проверкой идентичности отправителя по SPIFFE ID. Незащищённого внутреннего транспорта в продукте не существует — ни как режима по умолчанию, ни как опции конфигурации.
Правила, вытекающие из решения:
- mTLS обязателен и неотключаем. Каждое внутреннее соединение — TLS 1.3 с обязательным
клиентским сертификатом. В коде отсутствует plaintext-режим и отсутствует опция «отключить
проверку сертификата» (аналог
insecure-skip-verify). Отсутствие валидного клиентского сертификата — разрыв соединения на этапе рукопожатия, до передачи прикладных данных. - Версия протокола — только TLS 1.3. TLS 1.2 и ниже для внутренних соединений не
поддерживаются. Наборы шифров — AEAD из TLS 1.3:
TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_CHACHA20_POLY1305_SHA256. - Идентичность — SPIFFE ID. Каждый компонент получает сертификат, в SAN которого записан
URI вида
spiffe://<trust-domain>/<component>/<instance>. Принимающая сторона после успешной проверки цепочки извлекает SPIFFE ID из клиентского сертификата и сверяет его с явным списком разрешённых идентичностей для данного сервиса (deny by default). Проверка по CN и DNS-именам для авторизации не используется — см. Идентичность клиента. - Проверка симметрична. Не только сервер авторизует клиента: клиент проверяет SPIFFE ID сервера и отказывается работать с сервером, чья идентичность не соответствует ожидаемой. Это исключает перенаправление трафика на подставной узел с любым «валидным» сертификатом того же CA.
- Алгоритмы ключей. Leaf-сертификаты компонентов — ECDSA P-256 или Ed25519; CA (корневой и промежуточный) — ECDSA P-384 или RSA 4096. RSA для leaf-сертификатов допускается (минимум 3072 бита) для совместимости с УЦ заказчика, но не рекомендуется. Компоненты обязаны принимать все перечисленные алгоритмы — выбор конкретного остаётся за PKI заказчика. Обоснование — в Ключах и алгоритмах.
- Требования к сертификатам. Обязательные расширения: SAN c URI (SPIFFE ID), EKU
clientAuthи/илиserverAuthпо роли соединения,Basic Constraints: CA:FALSE.rustlsстрого проверяет EKU; сертификаты без нужного назначения отклоняются. - Доверие — только явный Truststore. Корни доверия задаются в конфигурации компонента (ADR 0002); системное хранилище ОС не используется. Trust-домены разных инсталляций изолированы: компонент доверяет только корню своей PKI.
- Автоматизация выдачи и ротация. Компоненты поддерживают автоматизированный жизненный цикл
сертификатов:
- выпуск через внешние механизмы автоматизации (HashiCorp Vault PKI, cert-manager, корпоративный УЦ заказчика) — см. Автоматизацию выпуска;
- горячую ротацию: компонент получает сигнал
перезагрузки сертификата и подменяет их в памяти
rustlsбез рестарта процесса и без разрыва уже установленных соединений — см. mTLS в Rust на rustls; - рекомендуемый срок жизни leaf-сертификатов — короткий (часы–дни), что делает ротацию штатной регулярной операцией, а не аварийной процедурой.
- Отзыв сертификатов. Компоненты поддерживают проверку отзыва по CRL: файл CRL задаётся в конфигурации, перечитывается при обновлении и применяется при проверке каждого рукопожатия. Основной эксплуатационной стратегией при автоматизированной выдаче являются короткоживущие сертификаты (компрометация истекает сама), CRL — обязательный механизм для немедленного отзыва и для инсталляций с длинными сроками жизни сертификатов. Классический OCSP-запрос «в момент рукопожатия» во внутренних контурах не применяется (требует доступности OCSP- респондера с узлов периметра) — см. Отзыв сертификатов.
- Единый транспортный слой. mTLS реализуется один раз, в общем транспортном слое, и используется всеми внутренними протоколами. Прикладной код получает от транспорта уже проверенную идентичность (SPIFFE ID) и не реализует собственных проверок TLS.
- События безопасности журналируются. Отклонённые рукопожатия (невалидная цепочка, отозванный сертификат, неразрешённый SPIFFE ID, истёкший срок) фиксируются в журнале с указанием причины и предъявленной идентичности — это события безопасности, а не отладочный шум.
Решение сознательно принимает рост сложности разработки и тестирования: любой стенд, включая локальный, требует развёрнутой PKI и выпущенных сертификатов; «быстро поднять два компонента без сертификатов» невозможно by design. Это цена бескомпромиссной защиты внутреннего трафика — подробно в разделе Consequences.
Considered Alternatives
Alternative 1: mTLS (TLS 1.3) со строгой проверкой SPIFFE ID для всех внутренних соединений
- Pros:
- Все четыре свойства доверенной среды обеспечиваются на транспортном уровне одним механизмом, одинаково для любого прикладного протокола.
- Аутентификация криптографическая и взаимная: предъявление чужого сертификата бесполезно без
приватного ключа (
CertificateVerifyв рукопожатии), подключение постороннего клиента отсекается до прикладного уровня. - SPIFFE ID даёт стандартизированную, независимую от сети идентичность: авторизация не привязана к IP-адресам и DNS-именам, переезд компонента не меняет политику доступа.
- Опирается на стандартную PKI: заказчик использует собственный УЦ, продукт не навязывает инфраструктуру.
- Реализуется средствами
rustlsбез внешних зависимостей — совместимо с моделью поставки (ADR 0008). - Неотключаемость исключает класс инцидентов «защиту забыли включить» и упрощает аудит: не существует конфигурации продукта с незащищённым внутренним трафиком.
- Cons:
- Усложнение разработки и тестирования: каждый стенд требует PKI, выпуска и обновления сертификатов; отладка трафика требует ключей сессии вместо простого перехвата.
- Эксплуатационная нагрузка: жизненный цикл сертификатов (выдача, ротация, отзыв) становится обязательной частью эксплуатации продукта.
- Накладные расходы рукопожатия и шифрования (для TLS 1.3 с AEAD на современном CPU — незначительные).
- Reason for selection: единственная альтернатива, обеспечивающая максимальный уровень защиты внутренних коммуникаций при активном атакующем в сети, без внешних зависимостей в целевой среде и без привязки доверия к топологии сети.
Alternative 2: TLS без клиентских сертификатов + аутентификация на прикладном уровне (токены, HMAC)
Сервер предъявляет сертификат, клиент аутентифицируется прикладным секретом (bearer-токен, подписанные запросы).
- Pros:
- Проще стенды разработки: клиентские сертификаты не нужны.
- Привычная модель для HTTP API; секреты просто выпускать и передавать.
- Cons:
- Аутентификация несимметрична и происходит после установления канала: посторонний клиент получает TLS-соединение и поверхность прикладного парсера до проверки прав.
- Bearer-токен передаётся в канале и воспроизводим при утечке; не привязан к соединению, в отличие от приватного ключа, который канал не покидает.
- Каждый прикладной протокол реализует аутентификацию заново — множественные реализации одной критичной функции вместо одной проверенной.
- Появляется отдельная система распространения и ротации секретов, эквивалентная по сложности PKI, но без её стандартизации.
- Reason for rejection: более слабая модель (односторонняя криптографическая аутентификация, воспроизводимые секреты, поздняя проверка) при сопоставимой эксплуатационной сложности.
Alternative 3: Защита периметром — plaintext или обычный TLS внутри «доверенной» сети
Внутренний трафик не аутентифицируется взаимно; безопасность обеспечивается сегментацией сети, межсетевыми экранами и физическим контролем.
- Pros:
- Минимальная сложность разработки, тестирования и эксплуатации.
- Нулевые накладные расходы на криптографию внутри контура.
- Cons:
- Прямо противоречит модели угроз: компоненты Netgap стоят на границе недоверенного контура, их взаимный трафик проходит через защищаемую границу — «доверенной сети» между ними не существует по определению.
- Один скомпрометированный узел сегмента получает неограниченный доступ ко всем внутренним API (lateral movement).
- Безопасность продукта становится зависимой от корректности чужой сетевой конфигурации, которую продукт не контролирует и не может проверить.
- Reason for rejection: несовместимо с назначением продукта; периметровая модель отвергнута в пользу zero-trust: каждое соединение аутентифицируется само, независимо от сети.
Alternative 4: Сетевой туннель уровня ОС (IPsec, WireGuard) между узлами
Шифрование и аутентификация выносятся на уровень ОС/сети; приложение работает поверх туннеля.
- Pros:
- Прозрачно для приложения: код компонентов не меняется.
- WireGuard даёт простую и быструю криптографию; IPsec — сертифицированные реализации.
- Cons:
- Аутентифицируется узел, а не компонент: любой процесс на узле, включая скомпрометированный, получает доступ в туннель; авторизация «какой компонент к какому сервису» невозможна.
- Требует настройки и сопровождения на уровне ОС вне продукта: права администратора, модули ядра/интерфейсы, разная конфигурация под Linux и Windows — ломается принцип самодостаточной поставки (ADR 0008).
- Продукт не может проверить наличие туннеля: незащищённая инсталляция неотличима от защищённой с точки зрения самих компонентов.
- Reason for rejection: идентичность на уровне узла вместо компонента и перенос гарантии безопасности из продукта во внешнюю инфраструктуру, которую продукт не контролирует.
Alternative 5: Service Mesh (Istio/Linkerd) — mTLS через sidecar-прокси
mTLS между компонентами терминируется sidecar-прокси, управление сертификатами — control plane меша.
- Pros:
- mTLS, SPIFFE-идентичности и ротация «из коробки», без кода в приложении.
- Зрелые реализации, готовые политики авторизации.
- Cons:
- Требует Kubernetes/container runtime в целевой среде — недопустимая зависимость для узлов периметра и аттестованных контуров (ADR 0008).
- Участок «приложение → локальный sidecar» остаётся незащищённым и не аутентифицированным.
- Control plane меша становится критическим компонентом чужой поставки внутри границы доверия продукта; расширяется поверхность атаки и область аудита.
- Reason for rejection: несовместимо с моделью поставки (статические бинарные файлы на «голой» машине); для продукта из фиксированного числа компонентов инфраструктура меша избыточна. Архитектурные идеи меша (SPIFFE ID, короткие TTL, горячая ротация) заимствованы в принятое решение без самого меша.
Alternative 6: mTLS как опция конфигурации (включаемый режим)
Тот же mTLS, но с возможностью отключения для разработки, отладки или «простых» инсталляций.
- Pros:
- Быстрые стенды разработки и демонстрации без PKI.
- Упрощается первичное развёртывание у заказчика.
- Cons:
- Появляется класс инцидентов «в продакшене забыли включить»: незащищённая конфигурация становится валидным состоянием продукта.
- Кодовая база и тесты обязаны поддерживать два транспортных режима; plaintext-ветка кода — постоянная цель для ошибок и даунгрейд-атак.
- Гарантия «внутренний трафик всегда защищён» превращается из свойства продукта в свойство конкретной инсталляции — её нельзя заявлять в документации и при аудите.
- Reason for rejection: безопасность по умолчанию с возможностью отключения на практике означает отсутствие гарантии. Стоимость PKI на стендах разработки принимается осознанно и компенсируется автоматизацией (скрипты private PKI из методички).
Consequences
Positive
- Внутренний трафик Netgap защищён всегда и везде: конфиденциальность, целостность и взаимная аутентификация гарантируются самим продуктом, а не конфигурацией сети заказчика.
- Посторонний процесс не может ни подключиться к внутреннему API, ни выдать себя за компонент: соединение отклоняется на рукопожатии, до прикладного парсера.
- Авторизация по SPIFFE ID не зависит от IP-адресов и DNS: политика доступа переживает переезды, NAT и смену адресации; идентичность компонента едина во всех журналах и политиках.
- Одна реализация транспортной безопасности на все прикладные протоколы: аудируется и тестируется один слой, а не каждый протокол отдельно.
- Заказчик сохраняет контроль над PKI: публичный CA, корпоративный УЦ или Vault — продукт лишь предъявляет требования к содержимому сертификата.
- Короткие TTL + горячая ротация делают компрометацию ключа ограниченной по времени, а замену сертификатов — фоновой операцией без остановки сервиса.
- Отсутствие plaintext-режима упрощает аудит и сертификацию: незащищённой конфигурации не существует, проверять «включён ли TLS» не нужно.
Negative
- Сложность разработки и тестирования — осознанная цена решения. Любой стенд, включая локальный запуск двух компонентов на машине разработчика, требует развёрнутой PKI и полного комплекта сертификатов с корректными SAN/EKU/SPIFFE ID. Интеграционные и e2e-тесты обязаны выпускать сертификаты в рамках подготовки окружения; появляется отдельный класс тестов на негативные сценарии PKI (истёкший, отозванный, чужой trust-домен, неверный EKU).
- Отладка сетевых взаимодействий усложняется: трафик не читается перехватом; для анализа нужны
ключи сессии (
SSLKEYLOGFILE) или журналирование на концах соединения. - Эксплуатация получает обязательный процесс: мониторинг сроков действия, автоматизация выдачи, доставка CRL. Ошибки процесса (просроченный сертификат) приводят к отказу связи между компонентами — отказ безопасный, но это отказ.
- Первичное развёртывание у заказчика дороже: до запуска нужно спланировать trust-домен, схему SPIFFE ID и источник сертификатов.
- Рукопожатие TLS добавляет задержку установления соединения; смягчается пулами долгоживущих соединений.
Risks and Mitigations
- Risk: просроченный сертификат останавливает связь между компонентами — эксплуатационный
инцидент из-за процесса, а не атаки.
- Mitigation: короткие TTL только вместе с автоматизированной выдачей; горячая ротация без рестарта; метрика/журналирование остатка срока действия и алёрт заведомо раньше истечения.
- Risk: компрометация корневого или промежуточного CA делает возможным выпуск сертификатов
для подставных компонентов.
- Mitigation: авторизация по точному SPIFFE ID (deny by default) ограничивает ценность произвольного сертификата; поддержка CRL для немедленного отзыва; рекомендация заказчику — офлайн-корень и выделенный промежуточный CA для trust-домена Netgap.
- Risk: кража приватного ключа компонента с узла.
- Mitigation: короткий TTL ограничивает окно использования; отзыв через CRL; права доступа к файлу ключа — только процесс компонента; журналирование аномалий (один SPIFFE ID с неожиданных адресов).
- Risk: разработчики обходят сложность стендов небезопасными самоделками (общий «вечный»
сертификат, скопированный по проектам).
- Mitigation: штатные скрипты развёртывания тестовой private PKI из методички (Собственная PKI) как путь наименьшего сопротивления; выпуск полного комплекта сертификатов — часть подготовки тестового окружения в CI.
- Risk: УЦ заказчика не может выпустить сертификат с URI SAN (SPIFFE ID).
- Mitigation: требования к сертификатам зафиксированы в документации поставки и проверяются компонентом при старте с внятной диагностикой; для таких случаев заказчику предлагается выделенный промежуточный CA под trust-домен Netgap.
- Risk: ошибка в единственной реализации транспортного слоя затрагивает все внутренние
коммуникации сразу.
- Mitigation: транспортный слой опирается на
rustls(без собственной криптографии); негативные mTLS-сценарии входят в обязательный набор тестов; обновленияrustlsотслеживаются черезcargo audit.
- Mitigation: транспортный слой опирается на
References
- ADR 0000: Выбор основного языка разработки.
- ADR 0002: Выбор способа конфигурации приложения.
- ADR 0008: Выбор целевых платформ сборки.
- Методичка Работа с сертификатами в проекте Netgap: Ключи и алгоритмы, Цепочка доверия, Собственная PKI, Отзыв сертификатов, mTLS в Rust на rustls, Идентичность клиента: CN и SPIFFE ID, Автоматизация выпуска и ротация.
- RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3.
- RFC 5280: Internet X.509 Public Key Infrastructure Certificate and CRL Profile.
- SPIFFE ID and Verifiable Identity Document.
- SPIFFE X509-SVID.
- rustls.