golang grpc ssl
- 无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 certificatecaCert, 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 keytlsConfig := &tls.Config{ServerName: nodeConfigSsl.ServerName,RootCAs: caCertPool,}// Create a new gRPC connection with the TLS transport credentialclientCreds := credentials.NewTLS(tlsConfig)conn, err := grpc.Dial("localhost:12345", grpc.WithTransportCredentials(clientCreds))if err != nil {}// Create a new gRPC client with the connectionclient := NewGreeterClient(conn)// Send a gRPC request to the serverresp, err := client.SayHello(context.Background(), &HelloRequest{Name: "Alice"})if err != nil {log.Fatalf("failed to send request: %v", err)}// Print the server's responsefmt.Println(resp.Message)
}
server
func main() {// Load the server's certificate, private key, and CA certificateserverCert, 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 keytlsConfig := &tls.Config{Certificates: []tls.Certificate{serverCert},}// Create a new gRPC server with the TLS transport credentialserverCreds := credentials.NewTLS(tlsConfig)server := grpc.NewServer(grpc.Creds(serverCreds))// Register the gRPC serverRegisterGreeterServer(server, &greeterServer{})// Listen for incoming connectionslis, err := net.Listen("tcp", ":12345")if err != nil {log.Fatalf("failed to listen: %v", err)}// Start the gRPC serverif 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 certificateserverCert, 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 keytlsConfig := &tls.Config{Certificates: []tls.Certificate{serverCert},ClientAuth: tls.RequireAndVerifyClientCert,ClientCAs: caCertPool,}// Create a new gRPC server with the TLS transport credentialserverCreds := credentials.NewTLS(tlsConfig)server := grpc.NewServer(grpc.Creds(serverCreds))// Register the gRPC serverRegisterGreeterServer(server, &greeterServer{})// Listen for incoming connectionslis, err := net.Listen("tcp", ":12345")if err != nil {log.Fatalf("failed to listen: %v", err)}// Start the gRPC serverif err := server.Serve(lis); err != nil {log.Fatalf("failed to serve: %v", err)}
}
client
func main() {// Load the client's certificate and private keyclientCert, err := tls.LoadX509KeyPair("client.crt", "client.key")if err != nil {log.Fatalf("failed to load client credentials: %v", err)}// Load the server's CA certificatecaCert, 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 keytlsConfig := &tls.Config{Certificates: []tls.Certificate{clientCert},ServerName: ServerName,RootCAs: caCertPool,}// Create a new gRPC connection with the TLS transport credentialclientCreds := credentials.NewTLS(tlsConfig)conn, err := grpc.Dial("localhost:12345", grpc.WithTransportCredentials(clientCreds))if err != nil {}// Create a new gRPC client with the connectionclient := NewGreeterClient(conn)// Send a gRPC request to the serverresp, err := client.SayHello(context.Background(), &HelloRequest{Name: "Alice"})if err != nil {log.Fatalf("failed to send request: %v", err)}// Print the server's responsefmt.Println(resp.Message)}
非常好的参考文章:
https://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.html