- 无CA场景
在不考虑CA的场景下呢,client有client.key和client.crt,server有server.key和server.crt,生成方式可以如下:
$ openssl genrsa -out server.key 2048
$ openssl req -new -x509 -days 3650 \
-subj "/C=GB/L=China/O=grpc-server/CN=server.grpc.io" \
-key server.key -out server.crt
$ openssl genrsa -out client.key 2048
$ openssl req -new -x509 -days 3650 \
-subj "/C=GB/L=China/O=grpc-client/CN=client.grpc.io" \
-key client.key -out client.crt
key对应的是私钥,crt对应的是公钥
如果需要认证呢,首先, 认证分为单向认证和双向认证。
单向认证,client对server的认证,
双向认证,顾名思义是client和server相互认证
那么,对于client认证server来说,需要把server的公钥server.crt传给client,代码如下:
client
func main() {
creds, err := credentials.NewClientTLSFromFile(
"server.crt", "server.grpc.io",
)
if err != nil {
log.Fatal(err)
}
conn, err := grpc.Dial("localhost:5000",
grpc.WithTransportCredentials(creds),
)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
...
}
server
func main() {
creds, err := credentials.NewServerTLSFromFile("server.crt", "server.key")
if err != nil {
log.Fatal(err)
}
server := grpc.NewServer(grpc.Creds(creds))
...
}
那么对于双向认证来说,不仅client需要校验server的公钥server.crt,server同样需要校验client的公钥client.crt
server
func main() {
creds, err := credentials.NewServerTLSFromFile("server.crt", "server.key")
if err != nil {
log.Fatal(err)
}
server := grpc.NewServer(grpc.Creds(creds))
...
}
client
func main() {
creds, err := credentials.NewClientTLSFromFile(
"server.crt", "server.grpc.io",
)
if err != nil {
log.Fatal(err)
}
conn, err := grpc.Dial("localhost:5000",
grpc.WithTransportCredentials(creds),
)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
...
}
- 对于有Ca的场景,ca就是一个第三方认证机构,来保证
一般来说,ca的证书生成如下
生成ca私钥
openssl genrsa -out ca.key 4096
生成CA证书
openssl req -new -x509 -days 365 -subj "/C=GB/L=Beijing/O=github/CN=liuqh.icu" \
-key ca.key -out ca.crt
这样我们就得到了一个ca.crt的ca证书
然后我们如何用ca证书对公钥进行签发呢?一般流程如下
以client端举例
生成私钥
openssl genrsa -out client.key
生成CSR
openssl req -new -subj "/C=GB/L=Beijing/O=github/CN=liuqh.icu" \
-key client.key -out client.csr
基于CA签发证书
openssl x509 -req -sha256 -CA ca.crt -CAkey ca.key -CAcreateserial -days 365 \
-in client.csr -out client.crt
其实这里感觉屏蔽了很多细节。首先我们要知道,基于ca签发证书,本质是通过ca的私钥加密生成了client公钥client.crt,如果server安装了ca.crt,则server就获得了ca的公钥,这样可以对ca签发的client.crt进行解密验证。反向是相同道理的。
那我们再分析几种场景的写法,首先单向认证,client验证server,那么client只需要ca.crt即可验证server了
client
func main() {
// Load the server's CA certificate
caCert, err := ioutil.ReadFile("ca.crt")
if err != nil {
log.Fatalf("failed to load CA certificate: %v", err)
}
caCertPool := x509.NewCertPool()
if ok := caCertPool.AppendCertsFromPEM(caCert); !ok {
log.Fatalf("failed to append CA certificate to the certificate pool")
}
// Create a new TLS configuration with the client's certificate and private key
tlsConfig := &tls.Config{
ServerName: nodeConfigSsl.ServerName,
RootCAs: caCertPool,
}
// Create a new gRPC connection with the TLS transport credential
clientCreds := credentials.NewTLS(tlsConfig)
conn, err := grpc.Dial("localhost:12345", grpc.WithTransportCredentials(clientCreds))
if err != nil {
}
// Create a new gRPC client with the connection
client := NewGreeterClient(conn)
// Send a gRPC request to the server
resp, err := client.SayHello(context.Background(), &HelloRequest{Name: "Alice"})
if err != nil {
log.Fatalf("failed to send request: %v", err)
}
// Print the server's response
fmt.Println(resp.Message)
}
server
func main() {
// Load the server's certificate, private key, and CA certificate
serverCert, err := tls.LoadX509KeyPair("server.crt", "server.key")
if err != nil {
log.Fatalf("failed to load server credentials: %v", err)
}
// Create a new TLS configuration with the server's certificate and private key
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{serverCert},
}
// Create a new gRPC server with the TLS transport credential
serverCreds := credentials.NewTLS(tlsConfig)
server := grpc.NewServer(grpc.Creds(serverCreds))
// Register the gRPC server
RegisterGreeterServer(server, &greeterServer{})
// Listen for incoming connections
lis, err := net.Listen("tcp", ":12345")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
// Start the gRPC server
if err := server.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
第二种双向验证,则需要client传送公钥,但是同时也server也需要传送公钥
server
func main() {
// Load the server's certificate, private key, and CA certificate
serverCert, err := tls.LoadX509KeyPair("server.crt", "server.key")
if err != nil {
log.Fatalf("failed to load server credentials: %v", err)
}
caCert, err := ioutil.ReadFile("ca.crt")
if err != nil {
log.Fatalf("failed to load CA certificate: %v", err)
}
caCertPool := x509.NewCertPool()
if ok := caCertPool.AppendCertsFromPEM(caCert); !ok {
log.Fatalf("failed to append CA certificate to the certificate pool")
}
// Create a new TLS configuration with the server's certificate and private key
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{serverCert},
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: caCertPool,
}
// Create a new gRPC server with the TLS transport credential
serverCreds := credentials.NewTLS(tlsConfig)
server := grpc.NewServer(grpc.Creds(serverCreds))
// Register the gRPC server
RegisterGreeterServer(server, &greeterServer{})
// Listen for incoming connections
lis, err := net.Listen("tcp", ":12345")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
// Start the gRPC server
if err := server.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
client
func main() {
// Load the client's certificate and private key
clientCert, err := tls.LoadX509KeyPair("client.crt", "client.key")
if err != nil {
log.Fatalf("failed to load client credentials: %v", err)
}
// Load the server's CA certificate
caCert, err := ioutil.ReadFile("ca.crt")
if err != nil {
log.Fatalf("failed to load CA certificate: %v", err)
}
caCertPool := x509.NewCertPool()
if ok := caCertPool.AppendCertsFromPEM(caCert); !ok {
log.Fatalf("failed to append CA certificate to the certificate pool")
}
// Create a new TLS configuration with the client's certificate and private key
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{clientCert},
ServerName: ServerName,
RootCAs: caCertPool,
}
// Create a new gRPC connection with the TLS transport credential
clientCreds := credentials.NewTLS(tlsConfig)
conn, err := grpc.Dial("localhost:12345", grpc.WithTransportCredentials(clientCreds))
if err != nil {
}
// Create a new gRPC client with the connection
client := NewGreeterClient(conn)
// Send a gRPC request to the server
resp, err := client.SayHello(context.Background(), &HelloRequest{Name: "Alice"})
if err != nil {
log.Fatalf("failed to send request: %v", err)
}
// Print the server's response
fmt.Println(resp.Message)
}
非常好的参考文章:
https://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.html