Аутентификация сервис-сервис

Урок о том, почему «мы же внутри одной сети» — опасное оправдание, и как сервисы должны доказывать друг другу, кто они.

Zero-trust — модель, в которой ни один запрос не считается доверенным по факту своего происхождения; доверие каждый раз заново подтверждается проверяемой личностью и правами, независимо от того, из какой сети пришёл вызов.

В монолите вызов одной функции другой бесплатен и доверен. В микросервисах тот же вызов превращается в сетевой запрос между процессами, который теоретически может сделать кто угодно, кто оказался в той же сети. Если сервис заказов слепо верит любому, кто постучался на его внутренний порт, то злоумышленник, пробравшийся в одну часть инфраструктуры, получает ключи от всего.

Зачем это знать защитнику

Старая модель «жёсткий периметр, мягкая середина» (защищаем границу, а внутри всё доверяем) раз за разом проваливается: достаточно одной уязвимости на периметре или одного скомпрометированного контейнера, чтобы атакующий начал свободно ходить между сервисами (lateral movement). Аутентификация сервис-сервис превращает мягкую середину в систему, где каждый шаг приходится подтверждать.

Почему внутренняя сеть — не доверие

«Внутренняя сеть» в облаке — понятие подвижное: контейнеры создаются и удаляются, IP переиспользуются, сервисы соседствуют с чужими нагрузками. IP-адрес или нахождение в одном VPC не доказывают личность — их можно подделать или унаследовать после компрометации соседа. Поэтому решение принимается не по адресу источника, а по криптографически проверяемому удостоверению самого сервиса.

Mutual TLS (mTLS)

Обычный TLS проверяет только сервер: клиент убеждается, что говорит с настоящим банком. В mTLS проверка взаимная — и клиент, и сервер предъявляют сертификаты, подписанные общим доверенным центром (внутренним CA). Так каждый сервис получает проверяемую личность на уровне транспорта:

Сервис A  --- предъявляет свой сертификат --->  Сервис B
Сервис A  <-- предъявляет свой сертификат ---  Сервис B
Оба проверяют: подпись сертификата сделана нашим внутренним CA,
сертификат не истёк и не отозван, имя (SPIFFE ID / SAN) ожидаемое.

Принцип конфигурации сервера — требовать клиентский сертификат и валидировать его против доверенного CA:

# Иллюстрация настройки (сервисная сетка / прокси), не для копипаста на бой
mtls:
  mode: STRICT              # plaintext-подключения запрещены
  client_cert: required     # клиент обязан предъявить сертификат
  ca_bundle: /etc/certs/internal-ca.pem
  verify: [signature, expiry, revocation]

В реальности mTLS обычно не пишут руками в каждом сервисе, а делегируют сервисной сетке (service mesh) — sidecar-прокси берёт на себя выдачу, проверку и ротацию сертификатов, прозрачно для кода. Стандарт SPIFFE/SPIRE задаёт, как именно сервису присваивается и подтверждается его идентичность.

Токены сервисов

mTLS отвечает на вопрос «кто звонит» на уровне соединения. Часто нужен ещё уровень приложения — что этому сервису разрешено. Здесь применяют сервисные токены: короткоживущие, подписанные удостоверения с ограниченным набором прав (scope). Сервис получает токен у доверенного эмитента и предъявляет его в запросе; получатель проверяет подпись и scope:

Authorization: Bearer <подписанный токен>
  payload (читаемый, не секретный):
    sub:    "service/billing"
    aud:    "service/orders"     # для кого выписан
    scope:  "orders:read"        # только чтение заказов
    exp:    "+5min"              # живёт минуты, не дни

Важно: токен ограничивает аудиторию (aud) — токен, выписанный для сервиса заказов, нельзя предъявить платёжному сервису. Это снижает урон при утечке.

Как это работает под капотом

В основе и mTLS, и токенов лежит асимметричная криптография: приватный ключ остаётся у владельца, публичная часть (сертификат/ключ проверки) распространяется. Получатель проверяет подпись, не зная секрета отправителя. Доверие иерархично: всё сводится к доверенному корню (внутренний CA или эмитент токенов), которому стороны договорились верить.

Отдельная важная деталь — ротация. Чем дольше живёт ключ или сертификат, тем дороже его утечка. Современный подход — делать удостоверения короткоживущими (часы для сертификатов, минуты для токенов) и автоматически их обновлять. Тогда даже украденный сертификат быстро становится бесполезным, а аварийный отзыв (revocation) и плановая смена компрометированного корня становятся рутинной операцией, а не катастрофой.

Как защититься

  • Исходите из zero-trust: каждый межсервисный вызов аутентифицирован и авторизован, независимо от сети.
  • Включайте mTLS в режиме STRICT — plaintext-подключения между сервисами запрещены.
  • Выдавайте сервисам проверяемую идентичность (SPIFFE/service mesh), а не доверяйте по IP или хедеру.
  • Используйте короткоживущие сертификаты и токены с узким scope и явной аудиторией (aud); настройте автоматическую ротацию и отзыв.
  • Применяйте наименьшие привилегии: сервису доступны только те эндпоинты соседей, которые ему реально нужны.
  • Логируйте, какой сервис к какому обращался — это даёт видимость и помогает заметить аномалии.

Экспериментируйте на своих кластерах и в учебных лабораториях; вмешательство в чужую инфраструктуру наказуемо (в РФ — ст. 272/274 УК РФ).

Итоги

  • Нахождение в одной сети не доказывает личность — доверие подтверждается криптографией каждый раз.
  • mTLS даёт взаимную проверку сервисов на транспорте; токены сервисов добавляют ограниченные права на уровне приложения.
  • Короткоживущие удостоверения и автоматическая ротация резко снижают цену утечки.
  • Zero-trust между сервисами останавливает свободное перемещение атакующего внутри инфраструктуры.
Проверьте себя
1. Чем mutual TLS (mTLS) отличается от обычного TLS в контексте связи сервис-сервис?
AmTLS быстрее, потому что не шифрует трафик
BВ mTLS и клиент, и сервер предъявляют сертификаты — личность подтверждают обе стороны
CmTLS работает только внутри одного процесса
DmTLS заменяет необходимость в авторизации полностью
2. Почему в модели zero-trust нельзя доверять запросу только потому, что он пришёл из внутренней сети?
AВнутренняя сеть всегда медленнее внешней
BIP-адрес и факт нахождения в сети не доказывают личность и могут принадлежать скомпрометированному соседу
CВнутри сети нет шифрования по определению
DЗапросы из внутренней сети не логируются