Как связаться с сервером gRP C, размещенным на Google Compute Engine, через SSL / TSL? - PullRequest
0 голосов
/ 01 апреля 2020

Контекст

Я разработал сервер gRP C в Java и соответствующий клиент gRP C в C#. Цель состоит в том, чтобы вызвать сервер gRP C с нескольких клиентов gRP C, развернутых на Windows машинах.

Посмотрев, как поддерживается gRP C в Azure, AWS, и Google Cloud Platform (GCP), я, скорее всего, буду размещать сервер gRP C в GCP. Поэтому в настоящее время я тестирую сценарий развертывания для сервера gRP C, как описано Google в руководстве по gRP C на Compute Engine . Короче говоря, это означает, что сервер gRP C работает в специально сконструированном контейнере Docker на виртуальной машине (ВМ) Google Compute Engine (GCE), рядом с прокси расширяемого сервиса (ESP), который работает в собственный предварительно сконфигурированный контейнер Docker на той же виртуальной машине.

Важным аспектом для использования в работе является возможность установить sh безопасный канал связи между клиентами gRP C и gRP * 1086. * сервер, использующий SSL / TSL. Вот где у меня возникают проблемы в сценарии облачного хостинга (но не в сценарии с автономным хостингом, где это прекрасно работает).

Что работает на данный момент? * Клиент gRP C, работающий на моем локальном компьютере Windows 10, успешно обменивается данными с сервером gRP C: через безопасный SSL / TLS канал , если я самостоятельно размещаю сервер на моей локальной Windows 10 машине; и через небезопасный канал в случае, если я размещаю сервер на GCE , как описано выше. Я выполнил следующие команды на виртуальной машине GCE для создания контейнеров docker для успешного взаимодействия клиент-сервер по небезопасному каналу . # Create the container network. sudo docker network create --driver bridge esp_net # Create dss-signer container from docker image. # The Java gRPC service listens on port 50051 (see esp container below). sudo docker run \ --detach \ --name=dss-signer \ --net=esp_net \ gcr.io/[my-project-name]/dss-signer:1.1 # Create Extensible Service Proxy (ESP) container from predefined docker image. # The ESP container's port 9000 is published as port 80 on the host machine, # meaning a client will have to connect to port 80 on the host machine. sudo docker run \ --detach \ --name=esp \ --publish 80:9000 \ --net esp_net \ gcr.io/endpoints-release/endpoints-runtime:1 \ --service=signer.endpoints.[my-project-name].cloud.goog \ --rollout_strategy=managed \ --http2_port=9000 \ --backend=grpc://dss-signer:50051 Таким образом Я бы сказал, что это работает в целом, и нет никаких проблем в коде Java или C# как таковых (за исключением вопросов, связанных с настройкой, связанных с его работой через SSL / TLS). Что не работает?

Мне не удалось установить безопасный канал между клиентом и сервером gRP C, следуя описанию в Включение SSL . Мой C# клиент всегда выдает следующее исключение:

Grpc.Core.RpcException
  HResult=0x80131500
  Message=Status(StatusCode=Unavailable, Detail="failed to connect to all addresses")
  Source=mscorlib
  StackTrace:
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at SignerClient.AbstractSignatureHandler.<InitiateCall>d__4.MoveNext()

[Rest of stack trace removed as it did not contain any helpful hints.]

Что я пробовал?

Вот команда openssl, используемая для создания ключа и сертификата сервера. В качестве общего имени я использую IP-адрес виртуальной машины GCE, отображаемый в облачной консоли Google. Я скопировал ключ и сертификат в каталог /etc/nginx/ssl.

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./nginx.key -out ./nginx.crt -subj "/O=[My Org]/OU=Servers/CN=[GCE VM IP Address]"

Вот команда docker для создания и запуска контейнера ESP docker, которая, насколько я понимаю, нужна изменить для включения SSL / TLS. Это также означает, что я не изменил «бэкэнд» сервер gRP C по сравнению с тем, что я описал выше. Не уверен, что это правильно.

sudo docker run \
--detach \
--name=esp \
--publish 443:443 \
--net esp_net \
--volume=/etc/nginx/ssl:/etc/nginx/ssl \
gcr.io/endpoints-release/endpoints-runtime:1 \
--service=signer.endpoints.[my-project-name].cloud.goog \
--rollout_strategy=managed \
--ssl_port=443 \
--backend=grpc://dss-signer:50051

Вот код C#, используемый для настройки безопасного канала на стороне клиента:

const string host = "[GCE VM IP Address]";
const int port = 443;

// Create the SSL credentials.
string caCertPem = File.ReadAllText("Certs\\ca.cer");
string clientCertPem = File.ReadAllText("Certs\\client.cer");
string clientKeyPem = File.ReadAllText("Certs\\client.key");

var keyCertificatePair = new KeyCertificatePair(clientCertPem, clientKeyPem);
var sslCredentials = new SslCredentials(caCertPem, keyCertificatePair);

// Create a client that communicates over a secure channel.
var channel = new Channel(host, port, sslCredentials);

Я также пробовал варианты вышеуказанной команды docker, например, с использованием другого порта SSL (8080) или с сохранением настройки http2_port. К сожалению, ничего не помогло.

Таким образом, как мне настроить это так, чтобы клиент gRP C и сервер, размещенный на GCE, могли безопасно общаться по SSL / TSL? Нужно ли настраивать клиент C# и сервер Java по-разному? Как мне настроить контейнер ESP docker?

1 Ответ

2 голосов
/ 04 апреля 2020

Основано на полезном совете Уэйна Чжана из группы Google по Конечные точки Google Cloud о включении ведения журнала gRP C для клиента gRP C и других исследованиях, связанных с ошибкой, указанной в журнале. Я нашел ответ на свой собственный вопрос.

Как я включил журнал gRP C на клиенте?

Чтобы включить ведение журнала gRP C на клиенте, работающем на моем * Для машины 1035 * 10 я установил переменные окружения GRPC_TRACE и GRPC_VERBOSITY следующим образом:

set GRPC_TRACE=all
set GRPC_VERBOSITY=DEBUG

Запуск клиента gRP C в командной строке дал очень подробный вывод с достаточной информацией, чтобы определить проблема.

Что вызвало ошибку?

Я был удивлен, обнаружив в журнале ошибку рукопожатия SSL. Это было связано с тем, что сертификат сервера, созданный, как описано в руководстве Google, не содержал расширения subjectAltName X.509. Клиент. NET gRP C (написано в C#), по-видимому, ожидает, что, хотя это никогда не было проблемой в моем сценарии с самостоятельным размещением. по двум причинам. Во-первых, документация по Extensible Service Proxy (ESP) в основном ориентирована на OpenAPI, а не на gRP C. Во-вторых, это языковая независимость c, и она не затрагивает языковые проблемы c, подобные этой.

Как я решил проблему?

В первой попытке я создал самозаверяющий сертификат X.509 с общим именем (CN) и расширением subjectAltName, оба из которых были настроены на IP-адрес моей виртуальной машины GCE. Однако это все равно не сработало, потому что клиент. NET gRP C не принял самозаверяющий сертификат сервера (т. Е. Тот, где субъект и издатель идентичны). Поэтому мне пришлось создать запрос сертификата сервера, а затем создать сертификат сервера на втором этапе, используя мой самозаверяющий сертификат и ключ CA root.

Итак, вот как я создал gRP C сертификат сервера:

REM Create GCE server certificate in PEM encoding.
REM Set ipAddress to whatever IP address the GCE VM is using.

set ipAddress=[GCE VM IP address]
set subject=/O=[MyOrganization]/OU=[MyOrganizationalUnit]/CN=%ipAddress%
set subjectAltNameConfig=subjectAltName = IP:%ipAddress%
echo %subjectAltNameConfig% > extfile.cfg

openssl req -newkey rsa:2048 -keyout Certs\nginx.key -nodes -out Certs\Requests\nginx.csr -subj "%subject%" -addext "%subjectAltNameConfig%"

REM Sign GCE server certificate.

openssl x509 -req -extfile extfile.cfg -in Certs\Requests\nginx.csr -CA Certs\ca.cer -CAkey Certs\ca.key -passin pass:[password] -days 365 -set_serial 01 -out Certs\nginx.crt

Все остальное в моем коде (Java gRP C сервер, C# gRP C клиент) и конфигурация (Docker команды для gRP C сервер и ESP с включенным SSL) было правильно. Два файла nginx.crt и nginx.key должны быть переданы на виртуальную машину GCE и сохранены в папке /etc/nginx/ssl, которая смонтирована в команде Docker.

...