Send and receive protocol buffers securely with gRPC in NodeJs

Hyperledger Fabric makes use of protocol buffers and gRPC.

In certain interop messaging situations where performance is critical, XML in SOAP messages or the contract-less JSON used in conjunction with REST services are being replaced by the new Google protocol buffers format. The “.proto” files describing protocol buffer messages can be used directly in server-side JavaScript (i.e. NodeJs) or can be used to generate source code in Go, Java and other compiled languages.

gRPC or “Google Remote Procedure Calls” uses protocol buffers by adding additional syntax in the .proto file.

I was reviewing protocol buffers and gRPC on my Hyperledger Fabric virtual image and managed to convince a NodeJs client program to communicate with a NodeJs server program via gRPC on secure HTTP/2. By “secure”, I mean using the most recent version of SSL: TLS.

I will retrace my steps here. To keep things simple and avoid forgetting something, I will be starting from scratch in a new, headless Linux virtual machine. In my next post, I will be back in my Hyperledger Fabric virtual machine to code the equivalent gRPC server and gRPC client programs in Java which will be able to communicate with the NodeJs ones and vice versa.

For now, we will stick to server-side JavaScript and NodeJs, but when it comes time to generate SSL certificates, we will create an extra one to be used by the Java programs in my next post.

 

Assumptions

  • You have Vagrant and Cygwin installed. Please refer to my previous post if you do not;
  • You are familiar with Linux command lines;
  • You know a little bit of JavaScript.

As described in my previous posts, I will be working under my %GOPATH% folder on Windows, i.e. under C:\gocode (also referred to here as  /cygdrive/c/gocode/ when viewed in Cygwin), but for this particular post you do not need to have the Go programming language installed: you can simply create a “nodecode” folder under the same folder where your Vagrantfile will be.

Steps we will follow

  • Setting up the virtual image with Vagrant
  • Make sure the computer name of the virtual image used in the client program as well as the SSL certificate will be resolved on the network
  • Coding the protocol buffer message
  • Coding the gRPC Server in NodeJs JavaScript
  • Coding the gRPC Client in NodeJs JavaScript
  • Creating the SSL certificates
  • Running the gRPC server
  • Running the gRPC client
  • Making sure we are using SSL

Setting up the virtual image with Vagrant

On Windows, open a Cygwin prompt. Do commands:

cd /cygdrive/c/gocode/

mkdir node

cd node

vagrant init hashicorp/precise64

vagrant up

This will take a few minutes. Next, we dive into our new Linux virtual machine:

vagrant ssh

This will present a welcome screen:

100.png

Next, we will install a few tools:

sudo apt-get update

sudo apt-get install curl dos2unix openssl

Add the NodeSource APT repository to Ubuntu and the PGP key for verifying packages:
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash –

Install Node.js:
sudo apt-get install -y nodejs

You can see NodeJs and npm are installed:

1.png

Next we create a subfolder under the Linux folder synced with the Windows host:

cd /vagrant

mkdir nodecode

cd nodecode

Next we install some plugins to NodeJs:

sudo npm install -g node-pre-gyp

sudo npm install –no-bin-links google-protobuf grpc –save

npm install

Make sure the computer name of the virtual image used in the client program as well as the SSL certificate will be resolved on the network

First, we need to double-check exactly what our computer name is on the Linux virtual machine. So in Cygwin, do command:

hostname

This displays “precise64” on my VM:

2.png

Just to make sure the SSL exchange will be convinced this computer is indeed “precise64”, in Cygwin let’s make sure it’s in the Linux hosts file:

cat /etc/hosts

And indeed it is “precise64“:

3.png

This computer name precise64 will be used in the SSL certificate generation commands below as well as in the gRPC client program. Your computer name will probably be different so I will flag the instances where you will need to make the substitution in red.

Coding the protocol buffer message

If you are lazy like me, you will use Notepad++ on Windows instead of vi on Linux.

Create a new text file on Windows called C:\gocode\node\nodecode\message.proto

or, alternately, on Linux at /vagrant/nodecode/message.proto

The end result will be the same.

In message.proto, add the following:

syntax = "proto3";

message TstCoordinates {
required int32 id = 1;
required string firstname = 2;
required string lastname = 3;
required string email = 4;
required string areacode = 5;
required string phone = 6;
required string extension = 7;
}

message TstId {
required int32 id = 1;
}

message Empty {}

service TstService{
rpc SendCoordinates (TstId) returns (TstCoordinates);
rpc List (Empty) returns (TstCoordinates);
}

That’s it. No code generation is required for NodeJs. If you saved the above file in Windows, back in Cygwin you might want to fix the carriage returns with command

dos2unix message.proto

Coding the gRPC Server in NodeJs JavaScript

In the same folder as message.proto, create a new text file called grpcserver.js, which will contain the following:

‘use strict’;

const fs = require(‘fs’);
const grpc = require(‘grpc’);
const serviceDef = grpc.load(“message.proto”);
const PORT = 7777;

const cacert = fs.readFileSync(‘certs/ca.crt’),
cert = fs.readFileSync(‘certs/server.crt’),
key = fs.readFileSync(‘certs/server.key’),
kvpair = {
‘private_key’: key,
‘cert_chain’: cert
};
const creds = grpc.ServerCredentials.createSsl(cacert, [kvpair]);

var tstcoordinates = [
{
id: 1,
firstname: “Bill”,
lastname: “Williams”,
email: “williams@example.com”,
areacode: “444”,
phone: “555-1212”,
extension: “378”
},
{
id: 2,
firstname: “Happy”,
lastname: “Golucky”,
email: “lucky@example.com”,
areacode: “444”,
phone: “555-1212”,
extension: “382”
}
];

var server = new grpc.Server();

server.addService(serviceDef.TstService.service, {
list: function(call, callback) {
console.log(“in list”);
callback(null, tstcoordinates[0]);
},
sendCoordinates: function(call, callback) {
console.log(“in sendCoordinates, id received was ” + call.request.id);   
callback(null, tstcoordinates[1] );
return;
}
});

// CAREFUL! Back ticks not quotes in next two lines.
server.bind(`0.0.0.0:${PORT}`, creds);
//server.bind(`0.0.0.0:${PORT}`, grpc.ServerCredentials.createInsecure());
console.log(`Starting gRPC server on port ${PORT}`);
server.start();

Coding the gRPC Client in NodeJs JavaScript

In the same folder as message.proto, create a new text file called grpcclient.js, which will contain the following:

‘use strict’;

const fs = require(‘fs’);
const process = require(‘process’);
const grpc = require(‘grpc’);
const serviceDef = grpc.load(“message.proto”);

const PORT = 7777;

const cacert = fs.readFileSync(‘certs/ca.crt’),
cert = fs.readFileSync(‘certs/client.crt’),
key = fs.readFileSync(‘certs/client.key’),
kvpair = {
‘private_key’: key,
‘cert_chain’: cert
};

const creds = grpc.credentials.createSsl(cacert, key, cert);

const client = new serviceDef.TstService(`precise64:${PORT}`,creds);
console.log(“secure connection established with gRPC server”);

lst();
snd();

function printResponse(error, response) {
console.log(“in printResponse”);
if (error)
console.log(‘Error: ‘, error);
else
console.log(response);
}

function lst() {
console.log(“in list”);
client.list({}, function(error, response) {
console.log(“in list call”);
printResponse(error, response);
});
}

function snd() {
console.log(“in snd”);
client.sendCoordinates({‘id’: 1}, function(error, response) {
console.log(“in snd call”);
printResponse(error, response);
});
}

Creating the SSL certificates

Next we create the certs folder. In Cygwin:

mkdir /vagrant/nodecode/certs

cd /vagrant/nodecode/certs

Next, we create the cetificates. We won’t use all of them right away.

In Cygwin, do the commands:

echo Generate CA key:
openssl genrsa -passout pass:pkipwd -des3 -out ca.key 4096

echo Generate CA certificate:
openssl req -passin pass:pkipwd -new -x509 -days 365 -key ca.key -out ca.crt -subj  “/C=US/ST=CA/L=Cupertino/O=YourCompany/OU=YourApp/CN=MyRootCA”

echo Generate server key:
openssl genrsa -passout pass:pkipwd -des3 -out server.key 4096

echo Generate server signing request with SERVER COMPUTER NAME:
openssl req -passin pass:pkipwd -new -key server.key -out server.csr -subj  “/C=US/ST=CA/L=Cupertino/O=YourCompany/OU=YourApp/CN=precise64”

echo Self-sign server certificate:
openssl x509 -req -passin pass:pkipwd -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

echo Remove passphrase from server key:
openssl rsa -passin pass:pkipwd -in server.key -out server.key

echo Generate client key
openssl genrsa -passout pass:pkipwd -des3 -out client.key 4096

echo Generate client signing request with CLIENT-COMPUTERNAME:
openssl req -passin pass:pkipwd -new -key client.key -out client.csr -subj  “/C=US/ST=CA/L=Cupertino/O=YourCompany/OU=YourApp/CN=precise64”

echo Self-sign client certificate:
openssl x509 -passin pass:pkipwd -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt

echo Remove passphrase from client key:
openssl rsa -passin pass:pkipwd -in client.key -out client.key

echo Convert the server private key to a format understood by Java
openssl pkcs8 -topk8 -inform PEM -outform PEM -in server.key -out key.pem -nocrypt

This will create nine new files under /vagrant/nodecode/certs :

  • ca.crt
  • ca.key
  • client.crt
  • client.csr
  • client.key
  • server.crt
  • server.csr
  • server.key
  • key.pem

Running the gRPC server

cd /vagrant/nodecode

node grpcserver

This will successfully start the gRPC server:

5.png

Running the gRPC client

Leave the server window waiting. Open a new Cygwin prompt. Do:

cd /cygdrive/c/gocode/node

vagrant ssh

In Linux do:

cd /vagrant/nodecode

node grpcclient

This will display in the client:

6.png

Success!

Making sure we are using SSL

Okay, the client got a message back from the server. But are we really running SSL?

One easy way is to send a client request to the server and see what kind of error we get. On the client, try the command:

curl localhost:7777

This displays:

7

And on our gRPC server we get an SSL handshake error displayed:

9.png

It should be noted however that the gRPC server is not down. If the gRPC client calls again, it receives the response as before:

10.png

(end of post)

Bertrand Szoghy, 2017-05, Quebec City.

Advertisements

One thought on “Send and receive protocol buffers securely with gRPC in NodeJs

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s