В этой статье есть примеры для Node.JS, но они могут быть полезны и для других языков, так что давайте начнем. Все рабочие примеры вы можете найти здесь.

Как работает TLS?

Рекомендую прочитать лучшую юмористическую статью о том, как работает TLS.

Типы подключения gRPC

Вы можете использовать три типа подключений gRPC:

  1. Небезопасно — все данные передаются без шифрования.
  2. Server-Side TLS — браузерное шифрование, при котором только сервер предоставляет клиенту TLS-сертификат.
  3. Взаимный TLS — наиболее безопасный, и сервер, и клиент предоставляют друг другу свои сертификаты.

Создание самоподписанных сертификатов

Это необязательный шаг, если у вас нет сертификата от ЦС или вы хотите работать с TLS на локальном хосте.

Обратите внимание, что в производственной среде чаще всего рекомендуется выбирать сертификат ЦС для большей безопасности, например, вы можете получить бесплатный сертификат от Let’s Encrypt.

Подготовка

Начнем с реализации нашего сервиса gRPC.

Во-первых, мы определим наш сервисный файл Protocol Buffers.

Во-вторых, нам нужно сгенерировать определения типов, сервисов и клиентов.
Для TypeScript я предпочитаю использовать ts-proto, но вы можете выбрать любой инструмент, который вам нравится, в зависимости от вашего языка.

protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_opt=env=node,outputServices=grpc-js --ts_proto_out=./src/generated ./proto/tls_service.proto

Теперь мы можем реализовать наш сервер, работающий на Node.js.

gRPC

Здесь мы будем использовать официальный пакет @grpc/grpc-js как для сервера, так и для клиента.

Серверный TLS

Для серверного TLS требуется только сертификат сервера и его закрытый ключ.

Сервер

Клиент

Теперь мы можем реализовать клиентскую часть.

Обратите внимание, что если ваш сертификат TLS подписан центром сертификации (не самозаверяющим), вам не нужно предоставлять этот сертификат на клиенте; это должно работать автоматически.

Взаимный TLS

Для Mutual TLS требуется корневой сертификат, сертификат сервера и его закрытый ключ.
Корневой сертификат будет использоваться здесь для проверки того, что сертификат клиента подписан, и что сервер может доверять клиенту.

Сервер

Как и в разделе Server-Side, изменена только getServerCredentialsfunction.

Клиент

Как и в разделе Server-Side, изменено только getChannelCredentialsfunction.

Переопределить целевое имя SSL

Пакет @grpc/grpc-js дополнительно предоставляет некоторые полезные параметры канала, которые вы можете установить. О каждом из них вы можете прочитать здесь.

grpc.ssl_target_name_override — было бы полезно для нас, когда реальный сервер за прокси и CN не совпадают.

Чтобы настроить параметры канала, вам нужно передать их в третий аргумент конструктора клиента.

gRPC-Web

Прочтите сообщение в блоге grpc.io о состоянии gRPC-Web.

TL;DR
Что вам следует знать:

  1. Схема работы:
    Клиент ↔ Прокси [HTTP(S) gRPC-Web] ↔ Сервер (gRPC)
  2. Есть две реализации — официальный gRPC-Web и @improbable-eng/grpc-web.
  3. Сейчас gRPC-Web поддерживает только запросы Unary и Server-Streaming через HTTP(S).
    Кроме того, @improbable-eng/grpc-web поддерживает клиентскую и двунаправленную потоковую передачу с помощью экспериментального транспорта веб-сокетов. Это не входит в спецификацию gRPC-Web и не рекомендуется для использования в рабочей среде.
  4. Есть два прокси — Envoy с gRPC-Web filter от официального gRPC-Web и grpcwebproxy от @improbable-eng.
  5. Вы можете использовать любой клиент с любым прокси.
  6. У клиентов разные транспорты связи.
    Официальный gRPC-web поддерживает только XMLHttpRequest.
    @improbable-eng/grpc-web дополнительно поддерживает Fetch (используя его, если он доступен) и может быть расширен с помощью пользовательского транспорта, например Node.js .

Пакет @improbable-eng/grpc-web не имеет обновлений за последние 10 месяцев, поэтому, если вы не планируете использовать gRPC-Web с пользовательскими транспортами или в среде Node.js, то, по моему мнению, вам следует выбрать официальный gRPC. -Веб-клиент. Я создал запрос функции в официальном пакете для добавления поддержки Node.js https://github.com/grpc/grpc-web/issues/1277.

В этом примере мы будем использовать прокси-сервер Envoy, работающий в докере.

Серверный TLS

Сервер

Как вы уже заметили, нам нужно запустить нашу службу gRPC за прокси. Так что ничего менять не нужно, просто запустите сервис с помощью Server-Side TLS, о котором мы говорили ранее.

После этого нам нужно настроить envoy и запустить его.

docker-compose up envoy-server

Вот и все. Ваш прокси-сервер gRPC-Web с TLS на стороне сервера будет доступен по адресу https://0.0.0.0:8080 .

Взаимный TLS

Сервер

Хитрость заключается в том, чтобы запустить службу gRPC с помощью Server-Side TLS, но на стороне отправителя проверить сертификат клиента, подписанный доверенным центром сертификации.

docker-compose up envoy-mutual

Большой! Ваш прокси-сервер gRPC-Web с Mutual TLS будет доступен по адресу https://0.0.0.0:8080 .

Тестирование запросов gRPC и gRPC-Web

Недавно я выпустил многоплатформенный настольный клиент gRPC/gRPC-Web под названием ezy. Я работаю с gRPC каждый день, и нет полнофункциональных UI/UX-идеальных клиентов для тестирования gRPC, поэтому я попытался создать его.



Этот клиент имеет полнофункциональную поддержку gRPC/gRPC-Web. Буду признателен, если вы попробуете.

🙏 Если у вас есть отзывы или идеи, смело открывайте обсуждение.