您的位置:  首頁 > 技術 > go語言 > 正文

跟我一起學Go系列:Go gRPC 安全認證機制-SSL/TLS認證

2021-07-07 21:50 博客園 管理員 次閱讀 條評論

第一篇入門說過 gRPC 底層是基于 HTTP/2 協議的,HTTP 本身不帶任何加密傳輸功能,基于 SSL 的 HTTPS 協議才是加密傳輸。gRPC 使用了 HTTP/2 協議但是并未使用 HTTPS,即少了加密傳輸的部分。

對于加密傳輸的部分 gRPC 將它抽出來作為一個組件,可以由用戶自由選擇。gRPC 內默認提供了兩種 內置的認證方式:

  1. 基于 CA 證書的 SSL/TLS ?認證方式;
  2. 基于 Token 的認證方式。

同時也提供了可擴展的用戶自定義認證方式。

gRPC 中的連接類型一共有以下 3 種:

  1. insecure connection:不使用 TLS 加密;
  2. server-side TLS:僅服務端 TLS 加密;
  3. mutual TLS:客戶端、服務端都使用 TLS 加密。

我們之前的實例中都是使用 insecure connection:

Copyconn,?err?:=?grpc.Dial(":8972",?grpc.WithInsecure())

這種方式相當于裸奔的數據在網絡上行走,生產環境下這樣使用肯定是不行的。下面我們來說一下基于 TLS 認證方式加密操作。

server-side TLS

服務端 TLS 具體包含以下幾個步驟:

  1. 制作證書,包含服務端證書和 CA 證書;
  2. 服務端啟動時加載證書;
  3. 客戶端連接時使用CA 證書校驗服務端證書有效性。

CA 證書制作:

Copy#?生成.key??私鑰文件$?openssl?genrsa?-out?ca.key?2048#?生成.csr?證書簽名請求文件$?openssl?req?-new?-key?ca.key?-out?ca.csr??-subj?"/C=GB/L=China/O=rickiyang/CN=www.rickiyang.com"#?自簽名生成.crt?證書文件$?openssl?req?-new?-x509?-days?3650?-key?ca.key?-out?ca.crt??-subj?"/C=GB/L=China/O=rickiyang/CN=www.rickiyang.com"

服務端證書

和生成 CA證書類似,不過最后一步由 CA 證書進行簽名,而不是自簽名。

然后openssl 配置文件可能位置不同,需要自己修改一下。

首先找到你的 openssl 位置:

Copy$?find?/?-name?"openssl.cnf"

然后生成簽名證書:

Copy#?生成.key??私鑰文件$?openssl?genrsa?-out?server.key?2048#?生成.csr?證書簽名請求文件$?openssl?req?-new?-key?server.key?-out?server.csr?\

	-subj?"/C=GB/L=China/O=rickiyang/CN=www.rickiyang.com"?\

	-reqexts?SAN?\

	-config?<(cat?/usr/local/etc/openssl@1.1/openssl.cnf?<(printf?"\n[SAN]\nsubjectAltName=DNS:*.rickiyang.com"))#?簽名生成.crt?證書文件$?openssl?x509?-req?-days?3650?\

???-in?server.csr?-out?server.crt?\

???-CA?ca.crt?-CAkey?ca.key?-CAcreateserial?\

???-extensions?SAN?\

???-extfile?<(cat?/usr/local/etc/openssl@1.1/openssl.cnf?<(printf?"\n[SAN]\nsubjectAltName=DNS:*.rickiyang.com"))

至此會生成如下文件:

Copy-rw-r--r--???1?rickiyang??staff??1119??6?30?10:32?ca.crt

-rw-r--r--???1?rickiyang??staff???964??6?30?10:32?ca.csr

-rw-r--r--???1?rickiyang??staff??1679??6?30?10:31?ca.key

-rw-r--r--???1?rickiyang??staff????17??6?30?10:34?ca.srl

-rw-r--r--???1?rickiyang??staff??1164??6?30?10:34?server.crt

-rw-r--r--???1?rickiyang??staff??1017??6?30?10:33?server.csr

-rw-r--r--???1?rickiyang??staff??1679??6?30?10:32?server.key

下面我們用到的會有這三個:

Copyca.crt

server.key

server.crt

下面來看一下如何將加密校驗邏輯加入到代碼中。相關代碼在 ?Github 上,自行下載查看。

服務端的修改點如下:

  • NewServerTLSFromFile 加載證書
  • NewServer 時指定 Creds。
Copyfunc?TestGrpcServer(t?*testing.T)?{	//?監聽本地的8972端口

	lis,?err?:=?net.Listen("tcp",?":8972")	if?err?!=?nil?{

		fmt.Printf("failed?to?listen:?%v",?err)		return

	}	//?TLS認證

	creds,?err?:=?credentials.NewServerTLSFromFile("/Users/rickiyang/server.crt",?"/Users/rickiyang/server.key")	if?err?!=?nil?{

		grpclog.Fatalf("Failed?to?generate?credentials?%v",?err)

	}	//開啟TLS認證,?注冊攔截器

	s?:=?grpc.NewServer(grpc.Creds(creds),?grpc.UnaryInterceptor(LoggingInterceptor))?//?創建gRPC服務器

	pb.RegisterGreeterServer(s,?&server{})?????????????????????????//?在gRPC服務端注冊服務



	reflection.Register(s)?//在給定的gRPC服務器上注冊服務器反射服務

	//?Serve方法在lis上接受傳入連接,為每個連接創建一個ServerTransport和server的goroutine。

	//?該goroutine讀取gRPC請求,然后調用已注冊的處理程序來響應它們。

	err?=?s.Serve(lis)	if?err?!=?nil?{

		fmt.Printf("failed?to?serve:?%v",?err)		return

	}



}

同樣服務端使用 TLS 連接,客戶端也需要使用對應的連接方式才能進行傳輸??蛻舳舜a主要修改點:

  • NewClientTLSFromFile 指定使用 CA 證書來校驗服務端的證書有效性。注意:第二個參數域名就是前面生成服務端證書時指定的CN參數。
  • 建立連接時 指定建立安全連接 WithTransportCredentials。

對應代碼邏輯如下:

Copyfunc?TestGrpcClient(t?*testing.T)?{	//?TLS連接

	creds,?err?:=?credentials.NewClientTLSFromFile("/Users/rickiyang2/ca.crt",?"www.rickiyang.com")	if?err?!=?nil?{

		grpclog.Fatalf("Failed?to?create?TLS?credentials?%v",?err)

	}	//?連接服務器

	conn,?err?:=?grpc.Dial(":8972",?grpc.WithTransportCredentials(creds))	if?err?!=?nil?{

		fmt.Printf("faild?to?connect:?%v",?err)

	}	defer?conn.Close()



	c?:=?pb.NewGreeterClient(conn)	//?調用服務端的SayHello

	r,?err?:=?c.SayHello(context.Background(),?&pb.HelloRequest{Name:?"CN"})	if?err?!=?nil?{

		fmt.Printf("could?not?greet:?%v",?err)

	}



	fmt.Printf("Greeting:?%s?!\n",?r.Message)

}
mutual TLS

server-side TLS 中雖然服務端使用了證書,但是客戶端卻沒有使用證書,本章節會給客戶端也生成一個證書,并完成 mutual TLS。

生成客戶端證書和生成服務端證書沒有什么不同:

Copy#?生成.key??私鑰文件openssl?genrsa?-out?client.key?2048#?生成.csr?證書簽名請求文件openssl?req?-new?-key?client.key?-out?client.csr?\

	-subj?"/C=GB/L=China/O=lixd/CN=www.rickiyang.com"?\

	-reqexts?SAN?\

	-config?<(cat?/usr/local/etc/openssl@1.1/openssl.cnf?<(printf?"\n[SAN]\nsubjectAltName=DNS:*.rickiyang.com"))#?簽名生成.crt?證書文件openssl?x509?-req?-days?3650?\

-in?client.csr?-out?client.crt?\

-CA?ca.crt?-CAkey?ca.key?-CAcreateserial?\

-extensions?SAN?\

-extfile?<(cat?/usr/local/etc/openssl@1.1/openssl.cnf?<(printf?"\n[SAN]\nsubjectAltName=DNS:*.rickiyang.com"))

執行上面的命令之后我們會得到這兩個重要的文件:

Copyclient.crt

client.key

下面就是在代碼中去引用這些文件,mutual TLS 配置客戶端和服務端都需要修改,相關代碼點擊查看。

具體改動如下:

服務端:

Copyfunc?TestGrpcServer(t?*testing.T)?{	//?從證書相關文件中讀取和解析信息,得到證書公鑰、密鑰對

	certificate,?err?:=?tls.LoadX509KeyPair(data.Path("/Users/rickiyang2/server.crt"),?data.Path("/Users/rickiyang2/server.key"))	if?err?!=?nil?{

		fmt.Errorf("err,?%v",?err)

	}	//?創建CertPool,后續就用池里的證書來校驗客戶端證書有效性

	//?所以如果有多個客戶端?可以給每個客戶端使用不同的?CA?證書,來實現分別校驗的目的

	certPool?:=?x509.NewCertPool()

	ca,?err?:=?ioutil.ReadFile(data.Path("/Users/rickiyang2/ca.crt"))	if?err?!=?nil?{

		fmt.Errorf("err,?%v",?err)

	}	if?ok?:=?certPool.AppendCertsFromPEM(ca);?!ok?{

		fmt.Errorf("failed?to?append?certs")

	}	//?構建基于?TLS?的?TransportCredentials

	creds?:=?credentials.NewTLS(&tls.Config{		//?設置證書鏈,允許包含一個或多個

		Certificates:?[]tls.Certificate{certificate},		//?要求必須校驗客戶端的證書?可以根據實際情況選用其他參數

		ClientAuth:?tls.RequireAndVerifyClientCert,?//?NOTE:?this?is?optional!

		//?設置根證書的集合,校驗方式使用?ClientAuth?中設定的模式

		ClientCAs:?certPool,

	})	//開啟TLS認證,?注冊攔截器

	s?:=?grpc.NewServer(grpc.Creds(creds),?grpc.UnaryInterceptor(LoggingInterceptor))?//?創建gRPC服務器

	pb.RegisterGreeterServer(s,?&server{})?????????????????????????//?在gRPC服務端注冊服務





	//?監聽本地的8972端口

	lis,?err?:=?net.Listen("tcp",?":8972")	if?err?!=?nil?{

		fmt.Printf("failed?to?listen:?%v",?err)		return

	}



	reflection.Register(s)?//在給定的gRPC服務器上注冊服務器反射服務

	//?Serve方法在lis上接受傳入連接,為每個連接創建一個ServerTransport和server的goroutine。

	//?該goroutine讀取gRPC請求,然后調用已注冊的處理程序來響應它們。

	err?=?s.Serve(lis)	if?err?!=?nil?{

		fmt.Printf("failed?to?serve:?%v",?err)		return

	}



}

客戶端:

Copyfunc?TestGrpcClient(t?*testing.T)?{	//?加載客戶端證書

	certificate,?err?:=?tls.LoadX509KeyPair(data.Path("/Users/rickiyang2/client.crt"),?data.Path("/Users/rickiyang2/client.key"))	if?err?!=?nil?{

		fmt.Errorf("err,?%v",?err)

	}	//?構建CertPool以校驗服務端證書有效性

	certPool?:=?x509.NewCertPool()

	ca,?err?:=?ioutil.ReadFile(data.Path("/Users/rickiyang2/ca.crt"))	if?err?!=?nil?{

		fmt.Errorf("err,?%v",?err)

	}	if?ok?:=?certPool.AppendCertsFromPEM(ca);?!ok?{

		fmt.Errorf("failed?to?append?ca?certs")

	}



	creds?:=?credentials.NewTLS(&tls.Config{

		Certificates:?[]tls.Certificate{certificate},

		ServerName:???"www.rickiyang.com",?//?NOTE:?this?is?required!

		RootCAs:??????certPool,

	})	//?連接服務器

	conn,?err?:=?grpc.Dial(":8972",?grpc.WithTransportCredentials(creds))	if?err?!=?nil?{

		fmt.Printf("faild?to?connect:?%v",?err)

	}	defer?conn.Close()



	c?:=?pb.NewGreeterClient(conn)	//?調用服務端的SayHello

	r,?err?:=?c.SayHello(context.Background(),?&pb.HelloRequest{Name:?"CN"})	if?err?!=?nil?{

		fmt.Printf("could?not?greet:?%v",?err)

	}



	fmt.Printf("Greeting:?%s?!\n",?r.Message)

}

本篇只介紹 SSL/TLS 認證相關的方式,生成證書相關操作本文是在 Mac 上操作,不同系統可能會有不一樣的環境問題, 如果出現問題按照相關提示排除錯誤。下一篇我們繼續介紹 Token 認證和自定義認證方式。

  • 0
    感動
  • 0
    路過
  • 0
    高興
  • 0
    難過
  • 0
    搞笑
  • 0
    無聊
  • 0
    憤怒
  • 0
    同情
熱度排行
友情鏈接
18禁高潮出水呻吟娇喘mp3,日本熟妇乱人伦A片免费高清,成人午夜精品无码区,狠狠色噜噜色狠狠狠综合久久,麻豆一区二区99久久久久,年轻的妈妈4,少妇被又大又粗又爽毛片,护士张开腿让我爽了一夜,男男互攻互受h啪肉np文,你好神枪手电视剧免费观看啊,97人妻一区二区精品免费,久久久婷婷五月亚洲97号色,freegaysexvideos男男中国,国产精品国产三级国av麻豆,国产精品又黄又爽又色无遮挡网站,亚洲av无码一区二区三区网站,亚洲国产精品久久久久蜜桃,国产真人无码作爱视频免费,国产成人精品亚洲一区二区三区,亚洲欧洲日产最新,老司机带带我精彩免费,国产成人久久精品激情,日本最新av免费一区二区三区,边摸边吃奶又黄又激烈视频
<蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>