grpc默认实现了基于证书的SSL加密通讯,使用中需要注意以下事项。
-
在Windows上开发,首先安装 OpenSSL,将OpenSSL.exe的路径添加到环境变量中。
-
通过以下样例脚本生成通讯中所需要的服务端和客户端证书,其中需要特别注意的是,Generate server signing reques中的CN=KEKYK字段,如果是本机测试,使用本机名称。如果是真实环境,使用域名。因为客户端必须通过机器名或域名访问该服务。
生成服务端和客户端证书
通过以下脚本生成服务端和客户端证书。脚本中命令的含义,详见博客中的另一篇文章《OpenSSL 生成服务器及客户端证书》。
@echo off
cd /d %~dp0
set OPENSSL_CONF=C:\Program Files\OpenSSL-Win64\bin\openssl.cfg
echo Generate CA key:
openssl genrsa -passout pass:1111 -des3 -out ca.key 4096
echo Generate CA certificate:
openssl req -passin pass:1111 -new -x509 -days 365 -key ca.key -out ca.crt -subj "/C=CN/ST=CA/L=Cupertino/O=YourCompany/OU=YourApp/CN=MyRootCA"
echo Generate server key:
openssl genrsa -passout pass:1111 -des3 -out server.key 4096
echo Generate server signing request:
openssl req -passin pass:1111 -new -key server.key -out server.csr -subj "/C=CN/ST=CA/L=Cupertino/O=YourCompany/OU=YourApp/CN=localhost"
echo Self-sign server certificate:
openssl x509 -req -passin pass:1111 -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:1111 -in server.key -out server.key
echo Generate client key
openssl genrsa -passout pass:1111 -des3 -out client.key 4096
echo Generate client signing request:
openssl req -passin pass:1111 -new -key client.key -out client.csr -subj "/C=CN/ST=CA/L=Cupertino/O=YourCompany/OU=YourApp/CN=FengJun"
echo Self-sign client certificate:
openssl x509 -passin pass:1111 -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:1111 -in client.key -out client.key
pause
脚本的执行结果:
使用SSL改进博客中《.NET使用gRPC入门教程》中的演示样例。
基于SSL的服务端
using Grpc.Core;
using GrpcLibrary;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace GrpcServer
{
class GrpcImpl : GrpcService.GrpcServiceBase
{
// 实现SayHello方法
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
}
}
class Program
{
const int Port = 9007;
public static void Main(string[] args)
{
var cacert = File.ReadAllText(path + "ca.crt");
var servercert = File.ReadAllText(path + "server.crt");
var serverkey = File.ReadAllText(path + "server.key");
var keypair = new KeyCertificatePair(servercert, serverkey);
var sslCredentials = new SslServerCredentials(new List<KeyCertificatePair>() { keypair }, cacert, false);
Server server = new Server
{
Services = { GrpcService.BindService(new GrpcImpl()) },
Ports = { new ServerPort("localhost", Port, sslCredentials) }
};
server.Start();
Console.WriteLine("GrpcService server listening on port " + Port);
Console.WriteLine("任意键退出...");
Console.ReadKey();
server.ShutdownAsync().Wait();
}
}
}
基于SSL的客户端
using Grpc.Core;
using GrpcLibrary;
using System;
using System.IO;
namespace GrpcClient
{
class Program
{
static void Main(string[] args)
{
var cacert = File.ReadAllText(path + "ca.crt");
var clientcert = File.ReadAllText(path + "client.crt");
var clientkey = File.ReadAllText(path + "client.key");
var ssl = new SslCredentials(cacert, new KeyCertificatePair(clientcert, clientkey));
Channel channel = new Channel("localhost:9007", ssl);
var client = new GrpcService.GrpcServiceClient(channel);
var reply = client.SayHello(new HelloRequest { Name = "April" });
Console.WriteLine("来自" + reply.Message);
channel.ShutdownAsync().Wait();
Console.WriteLine("任意键退出...");
Console.ReadKey();
}
}
}
执行结果