Jak poprawnie dodać SSL w komunikacji gRPC?

0

Chciałebym zasztfrowac komunikację gRPC

wygenerowałem klucze zgodnie ze skryptem https://stackoverflow.com/questions/37714558/how-to-enable-server-side-ssl-for-grpc#37739265
nazwa serwera PC-MB (poprawiłem w certyfikacie CN=PC-MB).

Po stronie serwera:

  bool use_tls{true};
  std::shared_ptr<grpc::ServerCredentials> credentials;
  if(use_tls)
  {
    grpc::SslServerCredentialsOptions ssl_opts;
    ssl_opts.pem_root_certs = "";
    std::string test_server1_key= R"(-----BEGIN PRIVATE KEY-----
TUTAJ zawartosc server.key
-----END PRIVATE KEY-----)";
    std::string test_server1_cert =  R"(-----BEGIN CERTIFICATE-----
TUTAJ zawartosc server.crt
-----END CERTIFICATE-----)";
    grpc::SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key,
                                                        test_server1_cert};
    ssl_opts.pem_key_cert_pairs.push_back(pkcp);
    credentials = grpc::SslServerCredentials(ssl_opts);
  }
  else
    credentials =  grpc::InsecureServerCredentials();

builder.AddListeningPort(server_address, credentials);

wydaje się że serwer działa poprawnie bo na konsoli już nie zgłasza błędów (jak nie było certyfikatu i klucza to wypisywał błędy)

test serwera za pomocą openssl

$ openssl s_client -connect PC-MB:50001 -brief
Can't use SSL_get_servername
depth=0 C = US, ST = CA, L = Cupertino, O = YourCompany, OU = YourApp, CN = PC-MB
verify error:num=20:unable to get local issuer certificate
depth=0 C = US, ST = CA, L = Cupertino, O = YourCompany, OU = YourApp, CN = PC-MB
verify error:num=21:unable to verify the first certificate
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Peer certificate: C = US, ST = CA, L = Cupertino, O = YourCompany, OU = YourApp, CN = PC-MB
Hash used: SHA256
Signature type: RSA-PSS
Verification error: unable to verify the first certificate
Server Temp Key: ECDH, prime256v1, 256 bits
100000000A000000:error:0A000126:SSL routines:ssl3_read_n:unexpected eof while reading:ssl/record/rec_layer_s3.c:303:

zakładam ze to jest ok bo sam wygenerowałem certyfikaty

po stronie klienta

bool use_tls{true};
std::shared_ptr<grpc::ChannelCredentials> credentials;
if (use_tls)
{
  grpc::SslCredentialsOptions ssl_opts;
  ssl_opts.pem_private_key = R"(-----BEGIN PRIVATE KEY-----
TUTAJ client.key
-----END PRIVATE KEY-----)";
  ssl_opts.pem_cert_chain=R"(-----BEGIN CERTIFICATE-----
TUTAJ client.crt
-----END CERTIFICATE-----)";
  credentials = grpc::SslCredentials(ssl_opts);
}
else
{
  credentials = grpc::InsecureChannelCredentials();
}

channel = grpc::CreateChannel(TARGET_STR, credentials);

jak TARGET_STR="localhost:50001"

E1121 12:56:49.954000000 22132 C:/M/B/src/grpc-1.59.0/src/core/tsi/ssl_transport_security.cc:1432] Handshake failed with fatal error SSL_ERROR_SSL: error:0A000086:SSL routines::certificate verify failed.

jak TARGET_STR="PC-MB:50001" to nie ma błędów na konsoli
ale ClientReader::read(...) zwraca zawsze false i nic nie mogę odczytać :(

0

Klient na pewno nie używa klucza prywatnego. Poczytaj jak działa szyfrowanie asymetryczne i tls

0

Chyba jest to problem bo sporo wątków z podobnym problemem dotykającym self sign
Brakuje mi globalnego przełącznika(np. zmienna środowiskowa) który powodował by ignorowanie wszystkich błędów związanych z połączeniem ssl

2

Skoro certyfikat serwera jest samo podpisany, tzn, że Issuer (ten kto podpisuje certyfikat, tj. jednostka CA) jest tożsama z Subject (ten na kogo certyfikat jest wystawiony).
Klient dostając certyfikat od serwera będzie próbował go zweryfikować w oparciu o listę zaufanych jednostek CA (lista przeważnie utrzymywana jest w jakimś trust store). No ale klient nie zna tego CA, więc trzeba mu jakoś powiedzieć.

  1. Wypruwasz publiczną część openssl x509 -in selfsigned.pem -pubkey -noout > server.crt
    (Z tego co rozumiem, to już to masz w postaci server.crt )

  2. Mówisz klientowi, gdzie ma znaleźć ten server.crt

a) Jeśli klientowi nie powiesz jakiego trust store'a ma używać, to będzie używał domyślnego w danym ekosystemie (czyli np. systemowego). Wystarczy, że publiczny cert serwera dodasz do systemowego trust store'a (no ale to zależy od systemu; pod linuksem można użyć np. strace'a by sprawdzić jakie pliki są otwierane przez klienta i jednym z takich plików będzie systemowy trust store; tam dorzucasz server.crt i powinno śmigać)

b) Możesz powiedzieć programowo ssl_opts.pem_root_certs = "zawartosc server.crt";
Zgodnie z https://grpc.github.io/grpc/cpp/structgrpc_1_1_ssl_credentials_options.html#a0ce1730020e18d04b6af48c88e069869 możesz użyć zmiennej środowiskowej by wskazać lokalizację pliku server.crt -> GRPC_DEFAULT_SSL_ROOTS_FILE_PATH

0

Znalazłem przykład https://github.com/yasushi-saito/grpc-ssl-example/tree/master
gdzie podobno to działa ale nie znam zupełnie go i nie che mi się uruchomić :(
Bo jak by zadziałało to mogłbym zweryfikowac czy to wina serwera czy klienta

Z dodatkowych elementów których jeszcze i u siebie nie miałem a jest w grpc-ssl-example uzycie SetSslTargetNameOverride

1 użytkowników online, w tym zalogowanych: 0, gości: 1