Reputation: 2234
Recently, I was trying to use rubygem grpc version 1.3.2 as a clinet and connect to a grpc server which is built from golang. I went through the documentation at GRPC.IO and used it in my code as it.
irb(main):017:0> GRPC::Core::Credentials.new(File.read(CA_FILE_PATH))
NameError: uninitialized constant GRPC::Core::Credentials
from (irb):17
from /usr/local/share/gems/gems/railties-4.2.1/lib/rails/commands/console.rb:110:in `start'
from /usr/local/share/gems/gems/railties-4.2.1/lib/rails/commands/console.rb:9:in `start'
from /usr/local/share/gems/gems/railties-4.2.1/lib/rails/commands/commands_tasks.rb:68:in `console'
from /usr/local/share/gems/gems/railties-4.2.1/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from /usr/local/share/gems/gems/railties-4.2.1/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
However their documentation specifically says,
creds = GRPC::Core::Credentials.new(load_certs) # load_certs typically loads a CA roots file
stub = Helloworld::Greeter::Stub.new('myservice.example.com', creds)
Then I came across ChannelCredentials and the creds is supposed to be either ChannelCredentials object or a symbol(e.g. :this_channel_is_insecure). Hence, I gave it a try as well.
I've taken the following function from the grpc gem's source code itself. This function was called in rspec test cases for loading the certs:
def load_certs
data_dir = "#{Rails.root}/certs"
files = ['ca.pem', 'server.key', 'server.pem']
files.map { |f| File.open(File.join(data_dir, f)).read }
end
Then I gave it a try with,
channel_creds = GRPC::Core::ChannelCredentials.new(load_certs)
stub = Helloworld::Greeter::Stub.new('myservice.example.com', channel_creds)
But the above failed with
E0619 09:59:10.410575570 14208 ssl_transport_security.c:601] Could not load any root certificate.
E0619 09:59:10.410604954 14208 ssl_transport_security.c:1315] Cannot load server root certificates.
E0619 09:59:10.410622519 14208 security_connector.c:837] Handshaker factory creation failed with TSI_INVALID_ARGUMENT.
I also tried:
channel_creds = GRPC::Core::ChannelCredentials.new(File.read(CA_FILE_PATH))
stub = Helloworld::Greeter::Stub.new('myservice.example.com', creds)
But all I got was error from the logs or rpc server:
2017/06/16 10:52:34 transport: http2Server.HandleStreams failed to receive the preface from client: EOF
2017/06/16 10:53:35 transport: http2Server.HandleStreams failed to receive the preface from client: EOF
2017/06/16 10:53:59 transport: http2Server.HandleStreams failed to receive the preface from client: EOF
2017/06/16 10:55:06 transport: http2Server.HandleStreams failed to receive the preface from client: EOF
Has anyone successfully tried this Ruby client Golang server combination with SSL/TLS enabled?
Upvotes: 6
Views: 2468
Reputation: 183
I can confirm this works.
channel_creds = GRPC::Core::ChannelCredentials.new(File.read("/home/user/.lnd/tls.cert"))
stub = Lnrpc::Lightning::Stub.new("127.0.0.1:10009", channel_creds)
obj = Lnrpc::GetInfoRequest.new
pp stub.get_info(obj)
Upvotes: 0
Reputation: 124
creds is supposed to be either ChannelCredentials object or a symbol
Yes the second argument of a client stub constructor (the creds argument), should be either a GRPC::Core::ChannelCredentials
object or specifically the ::this_channel_is_insecure
symbol (if the latter is passed, an insecure connection will be used).
I'd note that the test that uses
def load_certs
data_dir = "#{Rails.root}/certs"
files = ['ca.pem', 'server.key', 'server.pem']
files.map { |f| File.open(File.join(data_dir, f)).read }
end
might actually be misleading, since it only makes sense to construct channel credentials with the client's private key and certificate chain (that specific test I believe doesn't use the key and cert chain).
On the GRPC::Core::ChannelCredentials
constructor:
There are three forms that can be used, (there's a comment above the constructor code in https://github.com/grpc/grpc/blob/master/src/ruby/ext/grpc/rb_channel_credentials.c#L128 that goes over them), but the options are:
Credentials.new()
Credentials.new(pem_root_certs)
Credentials.new(pem_root_certs, pem_private_key, pem_cert_chain)
In all cases, the roots file, private key, and cert chain parameters are pem encoded strings.
Note that if no arguments are passed (Credentials.new()
is used), then the server root certificates will be found as described in this header comment (see the description for the behavior when server root certs parameter is null). And the last constructor is only needed if you want the client to use a private key and cert chain.
Upvotes: 4