golang grpc 证书报错

GO GRPC 证书报错

报错

报错信息

transport: authentication handshake failed: x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0

原因

是因为 go 1.15 版本开始废弃 CommonName,因此推荐使用 SAN 证书。 如果想兼容之前的方式,需要设置环境变量 GODEBUG 为 x509ignoreCN=0。

什么是 SAN

SAN(Subject Alternative Name) 是 SSL 标准 x509 中定义的一个扩展。使用了 SAN 字段的 SSL 证书,可以扩展此证书支持的域名,使得一个证书可以支持多个不同域名的解析。

解决

1. 修改GODEBUG方式

GODEBUG="x509ignoreCN=0" go run main.go

2. 使用SAN证书

2.1 生成 CA 根证书

# Key considerations for algorithm "RSA" ≥ 2048-bit
$ openssl genrsa -out server.key 2048

# Key considerations for algorithm "ECDSA" ≥ secp384r1
# List ECDSA the supported curves (openssl ecparam -list_curves)
$ openssl ecparam -genkey -name secp384r1 -out server.key

openssl req -new -x509 -days 3650 -key ca.key -out ca.pem

2.2 修改配置

cp /etc/ssl/openssl.cnf ./keys/
vim ./keys/openssl.cnf  
……
[CA_default]
# 打开copy_extensions的注释
copy_extensions = copy
……
[ req ]
# 将req_extensions的注释打开
req_extensions = v3_req # The extensions to add to a certificate request
……
[ v3_req ]
# 添加subjectAltName 
subjectAltName = @alt_names
# 文件末尾添加. www.p-pp.cn 和 *.p-pp.cn 代表允许的ServerName
[alt_names]
DNS.1 = www.p-pp.cn
DNS.2 = *.p-pp.cn

2.3 生成服务端证书

openssl genpkey -algorithm RSA -out hello.key

openssl req -new -nodes -key hello.key -out hello.csr -days 3650 -subj "/C=cn/ST=SH/L=SH/OU=SRE/O=TEST/CN=www.p-pp.cn" -config ./openssl.cnf -extensions v3_req
Ignoring -days; not generating a certificate

openssl x509 -req -days 3650 -in hello.csr -out hello.pem -CA server.pem -CAkey server.key -CAcreateserial -extfile ./openssl.cnf -extensions v3_req
Signature ok
subject=C = cn, ST = SH, L = SH, OU = SRE, O = TEST, CN = www.p-pp.cn
Getting CA Private Key

2.4 修改代码

Server
package main

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"net"
	"os"

	pb "grpc-hello/proto/hello" // 引入编译生成的包

	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/grpclog"
)

const (
	// Address gRPC服务地址
	Address = "127.0.0.1:50052"
)

// 定义helloService并实现约定的接口
type helloService struct{}

// HelloService Hello服务
var HelloService = helloService{}

// SayHello 实现Hello服务接口
func (h helloService) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
	grpclog.Println("收到请求grpclog")
	resp := new(pb.HelloResponse)
	resp.Message = fmt.Sprintf("Hello %s.", in.Name)

	return resp, nil
}

func main() {
	grpclog.SetLoggerV2(grpclog.NewLoggerV2(os.Stdout, os.Stdout, os.Stdout))
	listen, err := net.Listen("tcp", Address)
	if err != nil {
		grpclog.Fatalf("Failed to listen: %v", err)
	}
	// TLS认证
	cert, _ := tls.LoadX509KeyPair("../keys/hello.pem", "../keys/hello.key")
	certPool := x509.NewCertPool()
	ca, _ := ioutil.ReadFile("../keys/server.pem")
	certPool.AppendCertsFromPEM(ca)

	creds := credentials.NewTLS(&tls.Config{
		Certificates: []tls.Certificate{cert},
		ClientAuth:   tls.RequireAndVerifyClientCert,
		ClientCAs:    certPool,
	})

	// 实例化grpc Server
	s := grpc.NewServer(grpc.Creds(creds))

	// 注册HelloService
	pb.RegisterHelloServer(s, HelloService)

	grpclog.Infoln("Listen on " + Address + " with TSL")
	s.Serve(listen)
}
Client
package main

import (
	"crypto/tls"
	"crypto/x509"
	pb "grpc-hello/proto/hello" // 引入proto包
	"io/ioutil"
	"os"

	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/grpclog"
)

const (
	// Address gRPC服务地址
	Address = "127.0.0.1:50052"
)

func main() {
	grpclog.SetLoggerV2(grpclog.NewLoggerV2(os.Stdout, os.Stdout, os.Stdout))
	// TLS连接  记得把server name改成你写的服务器地址
	cert, _ := tls.LoadX509KeyPair("../keys/hello.pem", "../keys/hello.key")
	certPool := x509.NewCertPool()
	ca, _ := ioutil.ReadFile("../keys/server.pem")
	certPool.AppendCertsFromPEM(ca)

	creds := credentials.NewTLS(&tls.Config{
		Certificates: []tls.Certificate{cert},
		ServerName:   "www.p-pp.cn",
		RootCAs:      certPool,
	})

	// 连接
	conn, err := grpc.Dial(Address, grpc.WithTransportCredentials(creds))
	if err != nil {
		grpclog.Fatalln(err)
	}
	defer conn.Close()

	// 初始化客户端
	c := pb.NewHelloClient(conn)

	// 调用方法
	req := &pb.HelloRequest{Name: "gRPC"}
	res, err := c.SayHello(context.Background(), req)

	if err != nil {
		grpclog.Fatalln(err)
	}

	grpclog.Println(res.Message)
}

参考链接

https://www.cnblogs.com/custer/p/13999946.html
https://www.cnblogs.com/jackluo/p/13841286.html

posted @ 2021-12-27 15:17  董大轩  阅读(1863)  评论(1编辑  收藏  举报