本文是关于 gRPC 内置安全验证的概述。这里非常感谢 Thomas French ,在阅读完官方文档之后,感到了晦涩且非常 toy,而他写的博客则较为全面,降低了对于 gRPC 安全认证这个功能学习的门槛。
首先我们来讲下大致的一个流程:
1. 生成认证文件和一个私有密钥
2. 定义一个 RPC 服务
3. 书写服务端代码
4. 书写客户端代码
这里不知道为啥,通过命令行生成的 ssl 生成的证书有点问题。命令行如下:
openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 365 -out server.crt
此时确实生成了 ssl 相关的证书,但是并不能使用,抛出了如下的异常:
details = "failed to connect to all addresses"
debug_error_string =
"{"created":"@1619071291.415000000","description":"Failed to pick subchannel"
此时就直接使用了官网示例当中的密钥文件。
下面我们来看下 RPC 的服务定义,也就是说写一个 .proto
文件:
syntax = "proto3";
message Empty {
}
service Server {
rpc Foo (Empty) returns (Empty) {}
}
server:
from concurrent import futures
import grpc
import service_pb2
import service_pb2_grpc
# 这里需要对抽象方法进行实现
class ServerServicer(service_pb2_grpc.ServerServicer):
def Foo(self, request, context):
return service_pb2.Empty()
def main():
port = '50051'
with open('localhost.key', 'rb') as f:
private_key = f.read()
with open('localhost.crt', 'rb') as f:
certificate_chain = f.read()
server_credentials = grpc.ssl_server_credentials(
((private_key, certificate_chain,),))
server = grpc.server(futures.ThreadPoolExecutor(max_workers=1))
service_pb2_grpc.add_ServerServicer_to_server(ServerServicer(), server)
server.add_secure_port('[::]:'+port, server_credentials)
server.start()
print('server started')
server.wait_for_termination()
if __name__ == '__main__':
main()
这里对服务端的代码进行一个简单的说明:
首先我们需要把两个密钥文件的内容都都取出来
需要注意的是这里需要用元组把它给包裹起来:
((private_key, certificate_chain,),)
然后开启一个服务,并将对应的服务类添加到服务端当中。
再后面就是绑定安全接口。
client:
import grpc
import service_pb2
import service_pb2_grpc
def main():
host = 'localhost'
port = '50051'
with open('localhost.crt', 'rb') as f:
trusted_certs = f.read()
credentials = grpc.ssl_channel_credentials(root_certificates=trusted_certs)
channel = grpc.secure_channel('{}:{}'.format(host, port), credentials)
stub = service_pb2_grpc.ServerStub(channel)
print(f'connecting to {port}')
stub.Foo(service_pb2.Empty())
print('invoked ok')
channel.close()
if __name__ == '__main__':
main()
在客户端这里,我们首先也是读取了安全证书,然后建立连接的时候将证书传入。
然后通过stub 对服务端的方法进行调用。
下一章:gRPC 传输 metadata