TLS完全指南(二):OpenSSL操作指南
生成RSA秘鑰對
以下OpenSSL的genrsagenrsa命令生成一個2048 bit的公鑰私 鑰對,輸出到文件server.key里gist:
openssl genrsa -out server.key 2048n
server.key是PEM格式pem的:
-----BEGIN RSA PRIVATE KEY-----nProc-Type: 4,ENCRYPTEDnDEK-Info: DES-EDE3-CBC,DB98A9512DD7CBCFnnyKTM+eoxBvptGrkEixhljqHSuE+ucTh3VqYQsgO6+8Wbh1docbFUKzLKHrferJBHn...n-----END RSA PRIVATE KEY-----n
雖說文件頭尾都標註著RSA PRIVATE KEY,但實際上這個文件里既包括公鑰也 包括私鑰genrsa。
生成身份證申請
以下OpenSSL的req命令req以上文中的 server.key 為輸 入,生成一個身份證申請(CSR)文件 server.csr。
openssl req -nodes -new -key server.key -subj "/CN=localhost" -out server.csrn
這個 CSR 里的公鑰是從 server.key 里提取出來的,域名是 localhost。 需要注意的是,如果將來我們啟動一個 HTTPS 服務,使用這個 CSR 簽署的身份 證,那麼客戶端必須可以通過域名 locahost 訪問到這個 HTTPS 服務。
server.csr文件也是PEM格式的,文件頭尾標註為 CERTIFICATE REQUEST:
-----BEGIN CERTIFICATE REQUEST-----nMIIC0TCCAbkCAQAwgYsxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTERMA8GA1UEn...n-----END CERTIFICATE REQUEST-----n
簽署身份證
以下OpenSSL的x509命令x509用指定的私鑰 server.key 簽署 server.csr,輸出身份證 server.crt:
openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crtn
server.crt也是PEM格式的。文件頭尾的標記為CERTIFICATE:
-----BEGIN CERTIFICATE-----nMIIDlDCCAnwCCQDQ1UvQyFD7jDANBgkqhkiG9w0BAQsFADCBizELMAkGA1UEBhMCn...n-----END CERTIFICATE-----n
在這個例子里,用來簽署CSR的私鑰和 CSR 里的公鑰是一對兒。也就是說這是一 個自簽名(self-sign)的例子。
通常情況下,我們會用一個CA的私鑰來簽署一個CSR。在這個為 Kubernetes apiserver 簽署身份證的例子sign里,apiserver 的身份 證是用一個自簽署的CA的私鑰來簽署的:
$ openssl genrsa -out ca-key.pem 2048n$ openssl req -x509 -new -nodes -key ca-key.pem -days 10000 -out ca.pem -subj "/CN=kube-ca"nn$ openssl genrsa -out apiserver-key.pem 2048n$ openssl req -new -key apiserver-key.pem -out apiserver.csr -subj "/CN=kube-apiserver" -config openssl.cnfn$ openssl x509 -req -in apiserver.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out apiserver.pem -days 365 -extensions v3_req -extfile openssl.cnfn
這個例子里,ca-key.pem是Kubernetes管理員自己創建的CA的私鑰(其實是密 鑰對)。第二個命令(openssl req -x509 ...)不經過生成CSR的過程,直接 輸出CA的身份證。注意CA的域名是 kube-ca。
接下來三個命令分別創建 apiserver 的私鑰,生成 apiserver 的CSR,以及用 CA 的private key(ca-key.pem)來簽署 apiserver 的身份證。
注意,簽署 apiserver.csr 得到 apiserver 的身份證(apiserver.pem) 的過程中,不僅需要 ca-key.pem,還需要CA的身份證 ca.pem,因為 apiserver.pem 里附上了 CA 的身份證。從而構成一個[信任鏈](./tls.md#信 任鏈)。
HTTPS Server
現在我們有了 server.key 和 server.crt。我們可以寫一個HTTPS服務程序, 它私藏 server.key,同時在與任何客戶端程序首輪通信的時候通告自己的身 份證 server.crt。這裡有幾點需要注意:
為了確保「私藏」一個文件,我們需要設置其文件系統訪問許可權為只有owner可 讀sign:
chmod 400 server.keyn
如果我們用Go語言來寫這個 HTTPS server,只需要在調用 http.ListenAndServeTLS() 函數的時候,把server.key和server.crt的文件路徑傳遞給它即可。整個程序源碼如下:
package mainnn import (n t"io"n t"log"n t"net/http"n )nn func main() {n thttp.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {n ttio.WriteString(w, "hello, world!n")n t})n tif e := http.ListenAndServeTLS(":443", "server.crt", "server.key", nil); e != nil {n ttlog.Fatal("ListenAndServe: ", e)n t}n }n
因為我們在前面這一步生成 server.csr 的時 候,指定的域名是 localhost,所以必須確保 HTTPS 程序監聽 localhost虛擬網卡上的埠 443。上面程序里指定的監聽地址是"443",只有埠沒 有標識網卡的IP地址或者域名,那麼 ListenAndServerTLS 會讓程序監聽 本機所有網卡上的 443 埠。
sudo go run server.go &n
同樣的原因,客戶端必須通過 localhost 訪問我們的 HTTPS 服務。在這 個例子里,localhost 域名意味著只有本機上執行的客戶端才能訪問。
訪問TLS服務
用瀏覽器
我們可以通過瀏覽器訪問我們的 HTTPS server。但是因為server的身份證是我 們自簽署的,瀏覽器里沒有CA的身份證其中的公鑰 可以驗證 server.crt,所以瀏覽器會提示說它不信任我們的HTTPS服務。但是 如果用戶表示信任,還是可以訪問的。
要想消除瀏覽器的提示,最簡單的辦法就是把我們為HTTPS服務自簽署的身份證 加入到瀏覽器里chrome。
實際上,很多公司的運維團隊都會生自命為本公司內部的CA,成一個自簽署的身 份證,加入到公司配發的電腦的操作系統或者瀏覽器里。而本公司內部的很多網 路服務(報銷系統、人事管理系統、考評系統、各種計算資源上的SSH服務)都 用這個內部CA來簽署。這樣用公司的電腦,即可訪問這些服務。
用curl
類似的,我們可以通過加 -k 參數讓 curl 信任我們的HTTPS 伺服器:
$ /usr/local/Cellar/curl/7.49.1/bin/curl -k https://localhostnhello, world!n
或者我們可以把我們自簽署的身份證告訴 curl,讓它用這個身份證驗證我們的 HTTPS 服務:
$ curl --cacert server.crt https://localhostnhello, world!n
如果手邊沒有 server.crt,我們甚至可以用 openssl 工具找我們的 HTTPS server 要一份:
$ /usr/local/Cellar/openssl/1.0.2h/bin/openssl s_client -showcerts -connect localhost:443 > cacert.pemn$ curl --cacert cacert.pem https://localhostnhello, world!n
請注意,Mac OS X 自帶的 openssl 版本太低,不支持 Go 語言 http package 里實現的高級加密演算法,所以我們得用 Homebrew 安裝新版本:
brew update && brew install openssln
下一步
從上面操作可以看出來,TLS的具體操作和 OpenSSL 息息相關。關於OpenSSL的 更多用法,可以參見esse。
當我們用 OpenSSL 創建了CA身份證並且用CA身份證給相關程序簽署了各自的身 份證之後,我們就可以開工寫作和調試這些程序了。在下一篇 里,我們介紹如何用Go語言寫HTTPS的server和client。
參考文獻
genrsa https://www.openssl.org/docs/manmaster/apps/genrsa.html
gist https://gist.github.com/denji/12b3a568f092ab951456
pem How do I create a PEM file from the certificates I received from you?
req https://www.openssl.org/docs/manmaster/apps/req.html
sign CoreOS
x509 https://www.openssl.org/docs/manmaster/apps/x509.html
perm ssh "permissions are too open" error
chrome Google Chrome, Mac OS X and Self-Signed SSL Certificates
esse OpenSSL Essentials: Working with SSL Certificates, Private Keys and CSRs
推薦閱讀:
※酷站推薦 - ssllabs.com/ssl-pulse - SSL/TLS Security Scan Summary
※TLS完全指南(零)
※為什麼SSL證書那麼貴?
※使用了不受支持的SSL協議是怎麼回事?
※如何看待 CNNIC 官方網站的證書改換成了 DigiCert 簽發的證書?