Skip to Content
🎉 gRPCity 3.0 is released. Read more →

Credentials

gRPC 跑在 HTTP/2 上,TLS 是天然适配的方案。默认情况下 gRPCity 不强制要求证书、流量以明文通信——内网可信链路下尚可,跨网络就有风险。需要保密性、完整性或对端鉴权时,请打开 TLS。

打开 TLS 会增加双端 CPU 开销。极高 QPS 的内部服务,要结合实际威胁模型权衡。

生成证书

用 OpenSSL 生成一个自签 CA,再用它签发服务端与客户端证书。下面的脚本把通用参数放进几个变量里,并把证书都生成在 certs/ 目录下。

# 创建 certs 保存目录 mkdir -p certs && cd certs # 设置密码变量 password="grpcity" # 证书有效期变量 days=365

生成 ca 证书

# 设置CA相关变量 ca_key="ca.key" ca_crt="ca.crt" ca_subject="/C=CN/ST=GD/L=Guangzhou/O=gRPCity/OU=gRPCity/CN=ca" # 生成CA密钥和证书 openssl genrsa -passout pass:$password -des3 -out $ca_key 4096 openssl req -passin pass:$password -new -x509 -days $days -key $ca_key -out $ca_crt -subj "$ca_subject"

生成 server 证书

# 设置服务器相关变量 server_key="server.key" server_csr="server.csr" server_crt="server.crt" server_subject="/C=CN/ST=GD/L=Guangzhou/O=gRPCity/OU=Server/CN=localhost" # 生成服务器密钥和证书 openssl genrsa -passout pass:$password -des3 -out $server_key 4096 openssl req -passin pass:$password -new -key $server_key -out $server_csr -subj "$server_subject" openssl x509 -req -passin pass:$password -days $days -in $server_csr -CA $ca_crt -CAkey $ca_key -set_serial 01 -out $server_crt openssl rsa -passin pass:$password -in $server_key -out $server_key

生成 client 证书

# 设置客户端相关变量 client_key="client.key" client_csr="client.csr" client_crt="client.crt" client_subject="/C=CN/ST=GD/L=Guangzhou/O=gRPCity/OU=Client/CN=localhost" # 生成客户端密钥和证书 openssl genrsa -passout pass:$password -des3 -out $client_key 4096 openssl req -passin pass:$password -new -key $client_key -out $client_csr -subj "$client_subject" openssl x509 -passin pass:$password -req -days $days -in $client_csr -CA $ca_crt -CAkey $ca_key -set_serial 01 -out $client_crt openssl rsa -passin pass:$password -in $client_key -out $client_key

最终的证书目录如下:

Terminal
. └── certs ├── ca.crt ├── ca.key ├── client.crt ├── client.csr ├── client.key ├── server.crt ├── server.csr └── server.key

手动构造 credentials

loader.makeServerCredentials()loader.makeClientCredentials() 覆盖了常用场景。当你需要更精细的控制——createFromSecureContext、Google ADC、组合 credentials——gRPCity 也把 credentials 命名空间和 ChannelCredentials / ServerCredentials 类型从主包重新导出,免去对 @grpc/grpc-js 的直接依赖:

import { credentials } from 'grpcity' const insecure = credentials.createInsecure()

服务端配置

loader.makeServerCredentials() 在服务端装配证书。

loader.makeServerCredentials(rootCerts, keyCertPairs, checkClientCertificate) 的参数说明如下:

  • rootCerts: 根证书,一般为 ca 证书;
  • keyCertPairs: 证书对,key和crt,必须数组;
  • checkClientCertificate: 是否检查客户端证书;

示例:

import fs from 'node:fs' import loader from './loader.js' const credentials = loader.makeServerCredentials( fs.readFileSync(path.resolve(__dirname, 'certs/ca.crt')), [{ private_key: fs.readFileSync(path.resolve(__dirname, 'certs/server.key')), cert_chain: fs.readFileSync(path.resolve(__dirname, 'certs/server.crt')) }], true)

两种方式把证书加载到服务端中:

1.在初始化的时候

const server = await loader.initServer({ credentials })

2.在监听启动的时候

await server.listen(addr, credentials)

优先级:listen() 优先于 initServer()

使用了证书后,不能使用 ip 来启动服务,可以使用localhost或域名。

客户端配置

loader.makeClientCredentials() 在客户端装配证书。

import fs from 'node:fs' import path from 'node:path' const credentials = loader.makeClientCredentials( fs.readFileSync(path.resolve(__dirname, 'certs/ca.crt')), fs.readFileSync(path.resolve(__dirname, 'certs/client.key')), fs.readFileSync(path.resolve(__dirname, 'certs/client.crt')) )

获得credentials后,有两种加载方式,如下所示:

  1. initClients() 时加载
const clients = await loader.initClients({ services: { 'test.helloworld.Greeter': addr, 'test.helloworld.Hellor': addr }, credentials })
  1. get()getReal() 时加载
const greeterClient = clients.get('test.helloworld.Greeter', { credentials }) const result = await greeterClient.sayHello({ name: 'greeter' })
  • initClients() 适合所有服务端都是使用同一个证书的场景
  • get() 适合不同服务端的不同证书的场景
Last updated on