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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM