TLS+gRPC怎么玩?如何讓自己的RPC通信更加安全?
今天我們要在前文的基礎(chǔ)之上,來(lái)和小伙伴們聊一聊如何確保 gRPC 的通信安全。
確保 gRPC 的通信安全我們有很多種不同的方式,其中一種,就是對(duì)通信過(guò)程進(jìn)行加密,使用上 TLS。對(duì)于 TLS 如何加密,如何協(xié)商密鑰,這些我這里就不再啰嗦了,我在之前的文章中都已經(jīng)介紹過(guò)了。咱們就直接來(lái)看具體的玩法。
這塊整體上可以分為兩大類:
- 啟用單向安全連接
- 啟用 mTLS 安全連接
我們分別來(lái)看。
1. 啟用單向安全連接
單向安全連接其實(shí)就是說(shuō)只需要客戶端校驗(yàn)服務(wù)端,確??蛻舳耸盏降南?lái)自預(yù)期的服務(wù)端,整個(gè)的校驗(yàn)就涉及到我們前文所說(shuō)的 TLS、CA 等內(nèi)容了,具體流程是這樣:
- 首先我們先在自己電腦本地生成一個(gè)自簽名的 CA 證書(shū)。
- 利用這個(gè) CA 證書(shū),生成一個(gè)服務(wù)證書(shū)。
大致上就這兩個(gè)步驟就行了,然后在客戶端和服務(wù)端中分別加載相應(yīng)的證書(shū)即可。
上面我們提到了需要先有一個(gè)自簽名的 CA 證書(shū),這一步其實(shí)也可以省略,省略之后就直接生成一個(gè)自簽名的服務(wù)證書(shū)即可,然后在客戶端和服務(wù)端都使用這個(gè)服務(wù)證書(shū)。
來(lái)實(shí)際操作一下。
先自己安裝一下 openssl 工具,配置一下環(huán)境變量,軟件安裝比較簡(jiǎn)單,我這里就不啰嗦了。
1.1 生成 CA 證書(shū)
首先我們來(lái)看下如何生成 CA 證書(shū)。
一共是三個(gè)步驟:
- 生成 .key 私鑰文件:
- out 表示輸出的文件名。
- 2048 表示私鑰的位數(shù)。
- 生成 .csr 證書(shū)簽名請(qǐng)求文件:
CSR 即證書(shū)簽名申請(qǐng)(Certificate Signing Request),獲取 SSL 證書(shū),需要先生成 CSR 文件并提交給證書(shū)頒發(fā)機(jī)構(gòu)(CA)。CSR 包含了用于簽發(fā)證書(shū)的公鑰、用于辨識(shí)的名稱信息(Distinguished Name)(例如域名)、真實(shí)性和完整性保護(hù)(例如數(shù)字簽名),通常從 Web 服務(wù)器生成 CSR,同時(shí)創(chuàng)建加解密的公鑰私鑰對(duì)。
- subj 中描述的是一些國(guó)家、城市、組織以及通用名稱(域名)等信息。
- 自簽名生成 .crt 證書(shū)文件
- -x509 表示是要生成自簽名證書(shū)。
- -days 3650 表示證書(shū)有效期是 3650 天。
- -key 表示生成證書(shū)所需要的密鑰。
有人說(shuō)公鑰呢?公鑰其實(shí)就在 .crt 證書(shū)文件中。
1.2 生成服務(wù)證書(shū)
再來(lái)看生成服務(wù)證書(shū),生成服務(wù)證書(shū)和生成 CA 證書(shū)其實(shí)整個(gè)過(guò)程差不多,唯一的區(qū)別在于,CA 證書(shū)是自簽名的,而服務(wù)證書(shū)是 CA 的私鑰給簽名的,就這個(gè)差別。
- 生成 .key 私鑰文件:
- 生成 .csr 證書(shū)簽名請(qǐng)求文件:
- 簽名生成 .crt 證書(shū)文件
- -req 和 -in 指定了 server.csr,這個(gè)是證書(shū)請(qǐng)求文件,這里實(shí)際上是表示簽署證書(shū)請(qǐng)求文件。
證書(shū)現(xiàn)在就生成完畢。
這里我們生成的私鑰都是 .key? 文件,這個(gè)用我們 Java 代碼加載的時(shí)候會(huì)有問(wèn)題,我們要將之轉(zhuǎn)為 .pem 格式然后再用 Java 代碼進(jìn)行加載,轉(zhuǎn)換的命令如下:
1.3 單向加密
現(xiàn)在證書(shū)都有了,在當(dāng)前項(xiàng)目目錄下新建一個(gè)文件夾,專門(mén)用來(lái)放證書(shū),項(xiàng)目目錄結(jié)構(gòu)如下:
我們看下代碼該如何改造實(shí)現(xiàn)單向加密通信。
先來(lái)看服務(wù)端代碼:
大家注意,由于我生成簽名的時(shí)候,使用的域名是 local.javaboy.org? 這是我在本地 hosts 文件中配置的,指向本地地址,所以在后續(xù)的通信中,我使用的域名都將是 local.javaboy.org。
- Paths.get 方法表示從項(xiàng)目的根目錄下開(kāi)始查找文件,參數(shù)是可變長(zhǎng)度參數(shù),參數(shù)共同組成文件完整路徑。
- 服務(wù)端需要加載服務(wù)簽名和服務(wù)私鑰,簽名證書(shū)是客戶端驗(yàn)證服務(wù)端身份用的,私鑰則是服務(wù)端解密客戶端消息使用的。
服務(wù)端的改造就這些。
再來(lái)看客戶端的改造:
客戶端主要是加載 CA 證書(shū)文件,服務(wù)端的證書(shū)就是 CA 私鑰簽發(fā)的,但是需要 CA 公鑰也就是 ca.crt 進(jìn)行驗(yàn)簽,所以這里客戶端加載了 ca.crt 即可。
好啦,整體上的流程差不多就是這個(gè)樣子。
2. 啟用 mTLS 安全連接
上面的例子只是客戶端校驗(yàn)了服務(wù)端的身份,服務(wù)端并沒(méi)有校驗(yàn)客戶端的身份,如果想要雙向校驗(yàn),那么就把上面的流程對(duì)稱操作一遍就可以了。
首先我們需要為客戶端生成相應(yīng)的證書(shū),步驟跟前面也基本上一直,使用 CA 進(jìn)行簽名,如下:
- 生成 .key 私鑰文件:
- 生成 .csr 證書(shū)簽名請(qǐng)求文件:
- 簽名生成 .crt 證書(shū)文件
然后來(lái)看看代碼。
先來(lái)看服務(wù)端:
服務(wù)端要加載的文件多了 ca.crt,這是給客戶端驗(yàn)簽的時(shí)候需要用到。
再來(lái)看看客戶端代碼:
客戶端多了 client.crt? 和 client.pem,兩者的作用根服務(wù)端中這兩者的作用基本一致,前文已有說(shuō)明,這里就不再贅述了。
好啦,如此之后,我們的 gRPC 通信就加上了 TLS 的外殼,更加安全了。