GO 1.15 以上版本解決GRPC X509 Common Name field, use SANs or temporarily enable Common Name matching


第1步:生成 CA 根證書

👍 openssl genrsa -out ca.key 2048

Generating RSA private key, 2048 bit long modulus (2 primes)
.............+++++
..................................................................................................................+++++
e is 65537 (0x010001)

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

You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:cn
State or Province Name (full name) [Some-State]:shanghai
Locality Name (eg, city) []:shanghai
Organization Name (eg, company) [Internet Widgits Pty Ltd]:custer
Organizational Unit Name (eg, section) []:custer
Common Name (e.g. server FQDN or YOUR name) []:localhost
Email Address []:

第2步:用 openssl 生成 ca 和雙方 SAN 證書。

准備默認 OpenSSL 配置文件於當前目錄

linux系統在 : /etc/pki/tls/openssl.cnf

Mac系統在: /System/Library/OpenSSL/openssl.cnf

1:cp 目錄到項目目錄進行修改設置

cp /System/Library/OpenSSL/openssl.cnf /learn-gin/06.gin-grpc/keys

2:找到 [ CA_default ],打開 copy_extensions = copy

3:找到[ req ],打開 req_extensions = v3_req # The extensions to add to a certificate request

4:找到[ v3_req ],添加 subjectAltName = @alt_names

5:添加新的標簽 [ alt_names ] , 和標簽字段

[ alt_names ]
DNS.1 = localhost
DNS.2 = *.custer.fun

這里填入需要加入到 Subject Alternative Names 段落中的域名名稱,可以寫入多個。

第3步:生成服務端證書

👍 openssl genpkey -algorithm RSA -out server.key

........................................................................................+++++
.......................................+++++

👍 openssl req -new -nodes -key server.key -out server.csr -days 3650 -subj "/C=cn/OU=custer/O=custer/CN=localhost" -config ./openssl.cnf -extensions v3_req

Ignoring -days; not generating a certificate

👍 openssl x509 -req -days 3650 -in server.csr -out server.pem -CA ca.pem -CAkey ca.key -CAcreateserial -extfile ./openssl.cnf -extensions v3_req

Signature ok
subject=C = cn, OU = custer, O = custer, CN = localhost
Getting CA Private Key

server.csr是上面生成的證書請求文件。ca.pem/ca.key是CA證書文件和key,用來對server.csr進行簽名認證。這兩個文件在之前生成的。

第4步:生成客戶端證書

👍 openssl genpkey -algorithm RSA -out client.key

........+++++
...........+++++

👍 openssl req -new -nodes -key client.key -out client.csr -days 3650 -subj "/C=cn/OU=custer/O=custer/CN=localhost" -config ./openssl.cnf -extensions v3_req

Ignoring -days; not generating a certificate

👍 openssl x509 -req -days 3650 -in client.csr -out client.pem -CA ca.pem -CAkey ca.key -CAcreateserial -extfile ./openssl.cnf -extensions v3_req

Signature ok
subject=C = cn, OU = custer, O = custer, CN = localhost
Getting CA Private Key

現在 Go 1.15 以上版本的 GRPC 通信,這樣就完成了使用自簽CA、Server、Client證書和雙向認證

服務端代碼

func main() {
	cert, _ := tls.LoadX509KeyPair("cert/server.pem", "cert/server.key")
	certPool := x509.NewCertPool()
	ca, _ := ioutil.ReadFile("cert/ca.pem")
	certPool.AppendCertsFromPEM(ca)

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

	services.RegisterProdServiceServer(rpcServer, new(services.ProdService))

	listen, _ := net.Listen("tcp", ":8081")
	rpcServer.Serve(listen)
}

客戶端代碼

func main() {
	cert, _ := tls.LoadX509KeyPair("cert/client.pem", "cert/client.key")
	certPool := x509.NewCertPool()
	ca, _ := ioutil.ReadFile("cert/ca.pem")
	certPool.AppendCertsFromPEM(ca)

	creds := credentials.NewTLS(&tls.Config{
		Certificates: []tls.Certificate{cert},
		ServerName:   "localhost",
		RootCAs:      certPool,
	})

	conn, err := grpc.Dial(":8081", grpc.WithTransportCredentials(creds))

	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	prodClient := services.NewProdServiceClient(conn)
	prodRes, err := prodClient.GetProdStock(context.Background(), &services.ProdRequest{ProdId: 12})
	if err != nil {
		log.Fatal(err)
	}
	log.Info(prodRes.ProdStock)
}


免責聲明!

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



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