標籤:

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。這裡有幾點需要注意:

  1. 為了確保「私藏」一個文件,我們需要設置其文件系統訪問許可權為只有owner可 讀sign:

    chmod 400 server.keyn

  2. 如果我們用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

  3. 因為我們在前面這一步生成 server.csr 的時 候,指定的域名是 localhost,所以必須確保 HTTPS 程序監聽 localhost虛擬網卡上的埠 443。上面程序里指定的監聽地址是"443",只有埠沒 有標識網卡的IP地址或者域名,那麼 ListenAndServerTLS 會讓程序監聽 本機所有網卡上的 443 埠。

    sudo go run server.go &n

  4. 同樣的原因,客戶端必須通過 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 openssl.org/docs/manmas

  • gist gist.github.com/denji/1

  • pem How do I create a PEM file from the certificates I received from you?

  • req openssl.org/docs/manmas

  • sign CoreOS

  • x509 openssl.org/docs/manmas

  • 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 簽發的證書?

TAG:SSL | HTTPS |