Поднимаем TLS для gRPC в Go
В этой статье мы рассмотрим, как поднять gRPC сервер и клиент для него на Go, если у вас валидный сертификат или самоподписанный сертификат.
8К открытий42К показов
В этой статье мы рассмотрим, как поднять gRPC сервер и клиент для него на Go, если у вас самоподписанный сертификат. Кстати, если вы опытный тестировщик и хотите присоединиться к команде, не пропустите вакансию Fullstack QA в Сбер.
Для начала мы обсудим, как поднять gRPC сервер и клиент без шифрования. Затем посмотрим, как мог бы выглядеть код клиента, если сервер использует сертификат, подписанный доверенным CA.
В конце я расскажу, что можно сделать, если вы хотите поднять server и client с TLS, если у вас самоподписанный сертификат.
Insecure connection
Давайте начнём с опции, когда вам не нужно шифрование. Допустим, server и client находятся в одном закрытом кластере и кроме них там никого нет. На самом деле, даже в этом случае я рекомендую поднять TLS, но давайте рассмотрим такую опцию.
Начнём с сервера, и тут всё просто: если нам не нужен TLS, то мы просто нигде не должны его настраивать.
С клиентом всё немного сложнее: если мы не хотим использовать TLS, то при создании gRPC соединения нам это явно нужно указать опцией grpc.WithTransportCredentials(insecure.NewCredentials()).
Secure connection
Что, если опция незащищённого соединения нам не подходит?
Давайте для начала вспомним, как работает TLS. Одним из шагов TLS рукопожатия является отправка от сервера его сертификата. Получив сертификат, клиент должен проверить его подпись. То есть получив сертификат клиент смотрит на подпись сертификата и проверяет, что эта подпись создана одним из доверенных CA. Список доверенных CA есть в системе.
Так происходит например при открытии любой https страницы в браузере.
Давайте теперь вернёмся к нашим gRPC серверу и клиенту. Представим, что наш сервер использует сертификат, подписанный доверенным CA, как научить нашего клиента распознавать это?
На первом шаге, когда мы создавали незащищённое соединение, мы указали опцию insecure для transport credentials. Без этой опции клиент не поднялся бы. Для защищённого соединения нам тоже нужно будет указать опцию transport credentials, но передать в неё системные CA. В Go это можно сделать следующим образом:
Теперь вместо grpc.WithTransportCredentials(insecure.NewCredentials()) нам нужно указать grpc.WithTransportCredentials(tlsCreds)
Так клиент научится верифицировать подпись серверного сертификата системными CA.
Secure connection + self-signed certificate
Давайте теперь подумаем, что нам делать, если мы хотим использовать самоподписанный сертификат на сервере. Если мы поднимем сервер с самоподписанным сертификатом и оставим код клиента, как мы сделали на предыдущем шаге, то ничего работать не будет, так как на этапе проверки подписи серверного сертификата на стороне клиента клиент посчитает сертификат невалидным, так как он подписанным неизвестным ему CA. В итоге TLS рукопожатие не пройдёт и соединение установлено не будет.
Давайте попробуем это исправить, но для начала научимся генерировать самоподписанные сертификаты.
Воспользуемся openssl, чтобы сгенерировать CA сертификат и серверный сертификат.
На выходе у нас должно получиться 6 файлов:
ca.crt, ca.key, ca.srl, server.crt, server.csr, server.key
Хорошо, теперь давайте поднимем сервер с этим сертификатом.
Следующим шагом нам нужно научить клиента верифицировать подпись самоподписанного сертификата, то есть добавить наш CA в список его доверенных CA. На стороне клиента нужно сделать следующее:
Теперь клиент и сервер могут общаться по TLS соединению с самоподписанным сертификатом.
Заключение
В этой статье мы рассмотрели три опции настройки TLS между сервером и клиентом в Go: незащищённое соединение, соединение с сертификатом, подписанным доверенным CA и соединение с самоподписанным сертификатом.
8К открытий42К показов