用CloudFlare的PKI工具CFSSL生成Certificate Bundle
說明
在閱讀ofollow,noindex" target="_blank">Kubernetes文件
的時候知道了CFSSL
,在CFFL的Github Readme
中看到它有一個bundle
命令,不知道用來做什麼的。
直到閱讀了Flare/">CloudFlare 技術部落格上的文章《Introducing CFSSL - CloudFlare’s PKI toolkit 》, 才知道了Certificate Bundle的意思,以及bundle命令的用途。
非對稱加密與PKI(Public key infrastructure)
要想知道cfssl專案的用途和bundle命令的目的,必須要知道非對稱加密和PKI是怎麼回事。
加密演算法可以粗略非為對稱加密
與非對稱加密
兩種型別。對稱加密演算法中加密和解密時使用相同的密碼,非對稱加密演算法中密碼是一對,加密和解密時使用不同的密碼。
使用非對稱加密演算法,用來加密的密碼可以完全只由加密人自己持有,其它人只需要持有解密用的密碼。因為加密密碼只有加密人自己知道,所以沒有人能夠偽造出可以被正確解密的密文。
非對稱加密演算法的這種特性,使它非常適合用來做電子簽名:只要能夠用解密密碼解開,就能確定這是加密人傳送的密文。
最經典最常用的非對稱加密演算法是RSA
演算法,可以參考《RSA的私鑰和公鑰,以及用openssl製作的方法
》。
怎樣驗證網站的真實性?
現在大部分主要網站都使用https加密,當我們在瀏覽器的位址列中看到綠色的證書狀態時,可以認定這是一個真實的網站(其實還有“同形”域名的矇蔽方法)。
瀏覽器為什麼認為這個網站是真實的?背後的機制是怎樣的?這個需要知曉。
使用https加密的網站,首先要生成一堆非對稱加密演算法用到的金鑰,這對金鑰非為私鑰和公鑰。 網站的Web伺服器用私鑰對傳送給瀏覽器的網頁加密,瀏覽器用公鑰解密收到的內容(實際中要比這負責,注意後文的解釋)。 這樣子實現了對傳輸內容的加密。
但是瀏覽器是怎樣得到公鑰的呢?是在瀏覽器向網站發起請求的時候,網站迴應給瀏覽器的。也就是說,瀏覽器器發起請求的時候,網站首先把公鑰傳給瀏覽器,然後瀏覽器用這個公鑰解密後續的內容。
看到這,你或許有疑問了:這不是把鎖連同鑰匙一起傳送了嗎?如果別人偽造一個公鑰給瀏覽器咋辦?
你的質疑是正確的。事實上網站返回給瀏覽器的不是一個純粹的公鑰,而是用另外一個私鑰簽署的公鑰
,這個被簽署的公鑰,通常被稱為Https證書
。
瀏覽器收到這個被另一個私鑰簽署過的
證書後,先用另一個私鑰對應的公鑰
檢查這個證書是否正確,如果正確就在位址列中顯示綠色的圖示,並繼續後續請求。
如果不正確,就提示證書不可信。
那麼,這另一個公鑰是怎麼來的?瀏覽器怎樣知道的?它是內建在瀏覽器中的,直接包含在瀏覽器的安裝檔案中。
實際的情況還要再複雜一點,這個用來驗證證書的公鑰,通常也需要被另一個公鑰驗證,以此類推,直到被瀏覽器中內建的證書驗證。 這樣一個鏈條,稱為“信任鏈”,如下圖所示:
一個證書和驗證它所需要的一系列證書,被稱為Certificate Bundle
。這套機制被稱為:Public key infrastructure
。
專門負責簽署證書的機構被稱為CA,它們依靠自己的公信力,得到瀏覽器廠商的支援後,將自己的公鑰內建在瀏覽器中,成為瀏覽器驗證其它證書是否真實的最後一個證書。
注意:https協議比上面說的過程要複雜。因為非對稱加密演算法的開銷很高,https協議中首先用非對稱加密選擇出對稱加密演算法,然後用對稱加密的方式加密資料,並且會定時更換對稱加密演算法或者金鑰。
現實中存在的問題
現實中,瀏覽器廠商有很多家,簽署證書的CA也有很多家。一些早期的瀏覽器中只包含了那時候已知的CA廠商的公鑰。 即使同一時期的瀏覽器,內建的CA廠商的公鑰也可能不同,CA廠商的公鑰也會隨著技術發展而更新,支援新的安全特性。
這樣一來,一個網站要想被所有的瀏覽器信任,就變成了一件困難的事情:它的公鑰需要得到多個CA多個時期的公鑰的簽署。 直接導致管理起來也比較繁瑣,容易出錯。
可能導致需要被網站伺服器傳送的證書數量增加,繼而瀏覽器端的驗證工作也增加,從而使使用者等待網頁內容的時間增加。 還可能導致明明應當使用更新更安全的方法,結果用了早期的不安全的方法。
CFSSL就是用來解決這些問題的,通過用它可以方便地生成Certificate Bundle。由CFSSL統一負責Certificate Bundle的生成,能夠覆蓋更多的瀏覽器,並且可以統一優化,管理也極為方便。
只需要把CA廠商簽署的證書,直接提交到CFSSL中,CFSSL自動將這個證書依賴的其它證書打包。就是下面這個命令:
cfssl bundle -cert mycert.crt
CFSSL的CA功能
CFSSL同時具有CA功能,它除了可以生成Ceritificate Bundle,還可以生成CA證書、公鑰、私鑰,以及簽署公鑰。
可以說,只要部署一套CFSSL,就可以成為一個CA機構了(要發揮作用,還需要得到瀏覽器廠商的認可和支援,將公鑰內建到瀏覽器中)。
生成CA證書
命令如下:
./cfssl gencert -initca ca_csr.json
ca_csr.json是一個CA證書的資訊,格式如下:
{ "CN": "CN", "key": { "algo": "rsa", "size": 2048 }, "names":[{ "C": "CN", "ST": "BeiJing", "L": "BeiJing", "O": "lijiaocn.com", "OU": "class" }] }
上面命令執行結果是一堆字串,可以用cfssljson
把它們匯入檔案中:
./cfssl gencert -initca cert/ca-csr.json | ./cfssljson -bare ca
執行結束後得到三個檔案:ca-key.pem、ca.csr、ca.pem。
生成公鑰和私鑰
命令如下:
cfssl genkey csr.json
csr.json包含的是要生成的公鑰和私鑰的資訊,格式如下:
{ "hosts": [ "example.com", "www.example.com" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C":"US", "L":"San Francisco", "O":"Internet Widgets, Inc.", "OU": "WWW", "ST": "California" } ] }
依然用cfssljson將其匯入到檔案中:
./cfssl genkey csr.json|./cfssljson -bare server
會得到下面兩個檔案:
server-key.pemserver.csr
server-key.pem
是私鑰,server.csr
是包含公鑰的簽署請求,可以理解為等待被簽署的公鑰。
簽署公鑰
命令如下:
./cfssl sign -ca=ca.pem -ca-key=ca-key.pem -csr=./server.csr|./cfssljson -bare server
執行之後得到可以直接使用的證書server.pem
。
也可以將生成和簽署的過程一起執行:
./cfssl gencert -ca=ca.pem -ca-key=ca-key.pem --config=ca-config.json -profile=kubernetes server1-csr.json | ../cfssljson -bare server1
ca-config.json
是簽署相關的配置:
{ "signing": { "default": { "expiry": "8760h" }, "profiles": { "kubernetes": { "usages": [ "signing", "key encipherment", "server auth", "client auth" ], "expiry": "8760h" } } } }
server1-csr.json
是要生成的證書資訊:
{ "CN": "kubernetes", "hosts": [ "127.0.0.1", "192.0.0.1", "10.0.0.1", "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster", "kubernetes.default.svc.cluster.local" ], "key": { "algo": "rsa", "size": 2048 }, "names": [{ "C": "CN", "ST": "BeiJing", "L": "BeiJing", "O": "lijiaocn.com", "OU": "class" }] }
CFSSL以服務的方式執行
上面都是用cfssl的命令完成證書製作的,cfssl還可以以服務的方式執行:
cfssl serve -address=localhost -port=8888 -ca-key=test-key.pem -ca=test-cert.pem
之後可以用cfssl的API提交操作,或者直接用cfssl命令連線cfssl服務,例如:
cfssl gencert -remote="localhost:8888" www.example.com csr.json