巧用 CFSSL 管理 Kubernetes 集群證書
熟悉HTTP、HTTPS、SSL、TLS
HTTP 是一個(gè)網(wǎng)絡(luò)協(xié)議,是專門用來傳輸 Web 內(nèi)容,大部分網(wǎng)站都是通過 HTTP 協(xié)議來傳輸 Web 頁面、以及 Web 頁面上包含的各種東東(圖片、CSS 樣式、JS 腳本)。
SSL 是Secure Sockets Layer的縮寫,中文叫做“安全套接層”。它是在上世紀(jì)90年代中期,由網(wǎng)景公司設(shè)計(jì)的。(順便插一句,網(wǎng)景公司不光發(fā)明了 SSL,還發(fā)明了很多 Web 的基礎(chǔ)設(shè)施——比如CSS 樣式表和JS 腳本),為啥要發(fā)明 SSL 這個(gè)協(xié)議捏?因?yàn)樵然ヂ?lián)網(wǎng)上使用的 HTTP 協(xié)議是明文的,存在很多缺點(diǎn)——比如傳輸內(nèi)容會被偷窺(嗅探)和篡改。發(fā)明 SSL 協(xié)議,就是為了解決這些問題。
TLS是 SSL的 標(biāo)準(zhǔn)化,SSL標(biāo)準(zhǔn)化之后的名稱改為 TLS(是Transport Layer Security的縮寫),中文叫做傳輸層安全協(xié)議。很多相關(guān)的文章都把這兩者并列稱呼(SSL/TLS),因?yàn)檫@兩者可以視作同一個(gè)東西的不同階段。
HTTPS 協(xié)議,說白了就是“HTTP 協(xié)議”和“SSL/TLS 協(xié)議”的組合。你可以把 HTTPS 大致理解為——HTTP over SSL或HTTP over TLS。
CA認(rèn)證的原理
通過下面介紹信的描述介紹CA的原理
◇ 普通的介紹信
想必大伙兒都聽說過介紹信的例子吧?假設(shè) A 公司的張三先生要到 B 公司去拜訪,但是 B 公司的所有人都不認(rèn)識他,他咋辦捏?常用的辦法是帶公司開的一張介紹信,在信中說:茲有張三先生前往貴公司辦理業(yè)務(wù),請給予接洽......云云。然后在信上敲上A公司的公章。
張三先生到了 B 公司后,把介紹信遞給 B 公司的前臺李四小姐。李小姐一看介紹信上有 A 公司的公章,而且 A 公司是經(jīng)常和 B 公司有業(yè)務(wù)往來的,這位李小姐就相信張先生不是歹人了。
這里,A公司就是CA證書
◇ 引入中介機(jī)構(gòu)的介紹信
好,回到剛才的話題。如果和 B 公司有業(yè)務(wù)往來的公司很多,每個(gè)公司的公章都不同,那前臺就要懂得分辨各種公章,非常滴麻煩。所以,有某個(gè)中介公司 C,發(fā)現(xiàn)了這個(gè)商機(jī)。C公司專門開設(shè)了一項(xiàng)“代理公章”的業(yè)務(wù)。
今后,A 公司的業(yè)務(wù)員去 B 公司,需要帶2個(gè)介紹信:
介紹信1:含有 C 公司的公章及 A 公司的公章。并且特地注明:C 公司信任 A 公司。
介紹信2:僅含有 A 公司的公章,然后寫上:茲有張三先生前往貴公司辦理業(yè)務(wù),請給予接洽......云云。
某些不開竅的同學(xué)會問了,這樣不是增加麻煩了嗎?有啥好處捏?
主要的好處在于,對于接待公司的前臺,就不需要記住各個(gè)公司的公章分別是啥樣子的;他/她只要記住中介公司 C 的公章即可。當(dāng)他/她拿到兩份介紹信之后,先對介紹信1的 C 公章,驗(yàn)明正身;確認(rèn)無誤之后,再比對介紹信1和介紹信2的兩個(gè) A 公章是否一致。如果是一樣的,那就可以證明介紹信2是可以信任的了。
公鑰基礎(chǔ)設(shè)施PKI
CA(Certification Authority)證書,指的是權(quán)威機(jī)構(gòu)給我們頒發(fā)的證書。
密鑰就是用來加解密用的文件或者字符串。密鑰在非對稱加密的領(lǐng)域里,指的是私鑰和公鑰,他們總是成對出現(xiàn),其主要作用是加密和解密。常用的加密強(qiáng)度是2048bit。
RSA即非對稱加密算法。非對稱加密有兩個(gè)不一樣的密碼,一個(gè)叫私鑰,另一個(gè)叫公鑰,用其中一個(gè)加密的數(shù)據(jù)只能用另一個(gè)密碼解開,用自己的都解不了,也就是說用公鑰加密的數(shù)據(jù)只能由私鑰解開。
證書的編碼格式
PEM(Privacy Enhanced Mail),通常用于數(shù)字證書認(rèn)證機(jī)構(gòu)(Certificate Authorities,CA),擴(kuò)展名為.pem, .crt, .cer, 和 .key。內(nèi)容為Base64編碼的ASCII碼文件,有類似的頭尾標(biāo)記服務(wù)器認(rèn)證證書。
- "-----BEGIN CERTIFICATE-----"
- "-----END CERTIFICATE-----"
中級認(rèn)證證書和私鑰都可以儲存為PEM格式(認(rèn)證證書其實(shí)就是公鑰)。Apache 和 Nginx 等類似的服務(wù)器使用PEM格式證書。
DER(Distinguished Encoding Rules),與 PEM 不同之處在于其使用二進(jìn)制而不是 Base64 編碼的 ASCII。擴(kuò)展名為.der,但也經(jīng)常使用.cer用作擴(kuò)展名,所有類型的認(rèn)證證書和私鑰都可以存儲為 DER 格式。Java 使其典型使用平臺。
證書簽名請求 CSR
CSR(Certificate Signing Request),它是向 CA 機(jī)構(gòu)申請數(shù)字 ××× 書時(shí)使用的請求文件。在生成請求文件前,我們需要準(zhǔn)備一對對稱密鑰。私鑰信息自己保存,請求中會附上公鑰信息以及國家,城市,域名,Email 等信息,CSR 中還會附上簽名信息。當(dāng)我們準(zhǔn)備好 CSR 文件后就可以提交給CA機(jī)構(gòu),等待他們給我們簽名,簽好名后我們會收到 crt 文件,即證書。
注意:CSR 并不是證書。而是向權(quán)威證書頒發(fā)機(jī)構(gòu)獲得簽名證書的申請。
把 CSR 交給權(quán)威證書頒發(fā)機(jī)構(gòu),權(quán)威證書頒發(fā)機(jī)構(gòu)對此進(jìn)行簽名,完成。保留好CSR,當(dāng)權(quán)威證書頒發(fā)機(jī)構(gòu)頒發(fā)的證書過期的時(shí)候,你還可以用同樣的CSR來申請新的證書, Key 保持不變.
數(shù)字簽名
數(shù)字簽名就是"非對稱加密+摘要算法",其目的不是為了加密,而是用來防止他人篡改數(shù)據(jù)。
其核心思想是:比如A要給B發(fā)送數(shù)據(jù),A先用摘要算法得到數(shù)據(jù)的指紋,然后用A的私鑰加密指紋,加密后的指紋就是A的簽名,B收到數(shù)據(jù)和A的簽名后,也用同樣的摘要算法計(jì)算指紋,然后用A公開的公鑰解密簽名,比較兩個(gè)指紋,如果相同,說明數(shù)據(jù)沒有被篡改,確實(shí)是A發(fā)過來的數(shù)據(jù)。假設(shè)C想改A發(fā)給B的數(shù)據(jù)來欺騙B,因?yàn)榇鄹臄?shù)據(jù)后指紋會變,要想跟A的簽名里面的指紋一致,就得改簽名,但由于沒有A的私鑰,所以改不了,如果C用自己的私鑰生成一個(gè)新的簽名,B收到數(shù)據(jù)后用A的公鑰根本就解不開。
常用的摘要算法有MD5、SHA1、SHA256。
使用私鑰對需要傳輸?shù)奈谋镜恼M(jìn)行加密,得到的密文即被稱為該次傳輸過程的簽名。
數(shù)字證書和公鑰
數(shù)字證書則是由證書認(rèn)證機(jī)構(gòu)(CA)對證書申請者真實(shí)身份驗(yàn)證之后,用CA的根證書對申請人的一些基本信息以及申請人的公鑰進(jìn)行簽名(相當(dāng)于加蓋發(fā)證書機(jī) 構(gòu)的公章)后形成的一個(gè)數(shù)字文件。實(shí)際上,數(shù)字證書就是經(jīng)過CA認(rèn)證過的公鑰,除了公鑰,還有其他的信息,比如Email,國家,城市,域名等。
CFSSL安裝及基礎(chǔ)知識
cfssl是CloudFlare開源的一款PKI/TLS工具。CFSSL 包含一個(gè)命令行工具和一個(gè)用于簽名、驗(yàn)證并且捆綁TLS證書的HTTP API 服務(wù)。使用Go語言編寫。
CFSSL包括:
- 一組用于生成自定義 TLS PKI 的工具
- cfssl程序,是cfssl的命令行工具
- multirootca程序是可以使用多個(gè)簽名密鑰的證書頒發(fā)機(jī)構(gòu)服務(wù)器
- mkbundle程序用于構(gòu)建證書池
- cfssljson程序,從cfssl和multirootca程序獲取JSON輸出,并將證書,密鑰,CSR和bundle寫入磁盤
PKI借助數(shù)字證書和公鑰加密技術(shù)提供可信任的網(wǎng)絡(luò)身份。通常,證書就是一個(gè)包含如下身份信息的文件:
- 證書所有組織的信息
- 公鑰
- 證書頒發(fā)組織的信息
- 證書頒發(fā)組織授予的權(quán)限,如證書有效期、適用的主機(jī)名、用途等
- 使用證書頒發(fā)組織私鑰創(chuàng)建的數(shù)字簽名
安裝 cfssl
這里我們只用到cfssl工具和cfssljson工具
- # curl -L https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -o /usr/local/bin/cfssl
- # curl -L https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -o /usr/local/bin/cfssljson
- # curl -L https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -o /usr/local/bin/cfssl-certinfo
- # chmod +x /usr/local/bin/cfssl*
cfssl 常用子命令介紹
- bundle: 創(chuàng)建包含客戶端證書的證書包
- genkey: 生成一個(gè)key(私鑰)和CSR(證書簽名請求)
- scan: 掃描主機(jī)問題
- revoke: 吊銷證書
- certinfo: 輸出給定證書的證書信息, 跟cfssl-certinfo 工具作用一樣
- gencrl: 生成新的證書吊銷列表
- selfsign: 生成一個(gè)新的自簽名密鑰和 簽名證書
- print-defaults: 打印默認(rèn)配置,這個(gè)默認(rèn)配置可以用作模板
- serve: 啟動一個(gè)HTTP API服務(wù)
- gencert: 生成新的key(密鑰)和簽名證書
- -ca:指明ca的證書
- -ca-key:指明ca的私鑰文件
- -config:指明請求證書的json文件
- -profile:與-config中的profile對應(yīng),是指根據(jù)config中的profile段來生成證書的相關(guān)信息
- ocspdump: 從cert db 中的所有 OCSP 響應(yīng)中生成一系列連貫的 OCSP 響應(yīng),供 ocspserve 使用
- ocspsign: 為給定的CA、Cert和狀態(tài)簽署OCSP響應(yīng)。返回一個(gè)base64編碼的OCSP響應(yīng)
- info: 獲取有關(guān)遠(yuǎn)程簽名者的信息
- sign: 簽名一個(gè)客戶端證書,通過給定的CA和CA密鑰,和主機(jī)名
- ocsprefresh: 用所有已知未過期證書的新OCSP響應(yīng)刷新ocsp_responses表。
- ocspserve: 設(shè)置一個(gè)HTTP服務(wù)器,處理來自文件或直接來自數(shù)據(jù)庫的OCSP請求(見RFC 5019)。
常用命令
- $ cfssl gencert -initca ca-csr.json | cfssljson -bare ca ## 初始化ca
- $ cfssl gencert -initca -ca-key key.pem ca-csr.json | cfssljson -bare ca ## 使用現(xiàn)有私鑰, 重新生成
- $ cfssl certinfo -cert ca.pem
- $ cfssl certinfo -csr ca.csr
使用 CFSSL 創(chuàng)建 CA 認(rèn)證步驟
創(chuàng)建認(rèn)證中心(CA)
cfssl 可以創(chuàng)建一個(gè)獲取和操作證書的內(nèi)部認(rèn)證中心。運(yùn)行認(rèn)證中心需要一個(gè) CA 證書和相應(yīng)的 CA 私鑰。任何知道私鑰的人都可以充當(dāng)CA來頒發(fā)證書。因此,私鑰的保護(hù)至關(guān)重要,這里我們以 k8s 所需的證書來實(shí)踐一下:
- $ cfssl print-defaults config > config.json # 默認(rèn)證書策略配置模板
- $ cfssl print-defaults csr > csr.json #默認(rèn)csr請求模板
結(jié)合自身的要求,修改證書請求文件csr.json,證書10年
- {
- "CN": "kubernetes",
- "key": {
- "algo": "rsa",
- "size": 2048
- },
- "names": [
- {
- "C": "CN",
- "ST": "BeiJing",
- "L": "BeiJing",
- "O": "k8s",
- "OU": "System"
- }
- ],
- "ca": {
- "expiry": "87600h"
- }
- }
知識點(diǎn) :
- "CN":Common Name,kube-apiserver 從證書中提取該字段作為請求的用戶名 (User Name)
- "O":Organization,kube-apiserver從證書中提取該字段作為請求用戶所屬的組 (Group)
- C: Country, 國家
- L: Locality,地區(qū),城市
- O: Organization Name,組織名稱,公司名稱
- OU: Organization Unit Name,組織單位名稱,公司部門
- ST: State,州,省
證書配置模板文件ca-config.json
- {
- "signing": {
- "default": {
- "expiry": "87600h"
- },
- "profiles": {
- "kubernetes": {
- "usages": [
- "signing",
- "key encipherment",
- "server auth",
- "client auth"
- ],
- "expiry": "87600h"
- }
- }
- }
- }
知識點(diǎn):
- config.json:可以定義多個(gè) profiles,分別指定不同的過期時(shí)間、使用場景等參數(shù);后續(xù)在簽名證書時(shí)使用某個(gè) profile;此實(shí)例只有一個(gè)kubernetes模板。
- signing:表示該證書可用于簽名其它證書;生成的 ca.pem 證書中CA=TRUE
- server auth:表示client可以用該 CA 對server提供的證書進(jìn)行驗(yàn)證;
- client auth:表示server可以用該CA對client提供的證書進(jìn)行驗(yàn)證;
- 注意標(biāo)點(diǎn)符號,最后一個(gè)字段一般是沒有逗號的。
初始化創(chuàng)建CA認(rèn)證中心,將會生成ca-key.pem(私鑰)和ca.pem(公鑰)
- $ cfssl gencert -initca ca-csr.json | cfssljson -bare ca
創(chuàng)建 Kubernetes 證書
創(chuàng)建kubernetes-csr.json證書請求文件
- {
- "CN": "kubernetes",
- "hosts": [
- "127.0.0.1",
- "10.1.20.129",
- "10.1.20.128",
- "10.1.20.126",
- "10.1.20.127",
- "10.254.0.1",
- "*.kubernetes.master",
- "localhost",
- "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": "k8s",
- "OU": "System"
- }
- ]
- }
知識點(diǎn):
- 這個(gè)證書目前專屬于 apiserver,加了一個(gè) *.kubernetes.master域名以便內(nèi)部私有 DNS 解析使用(可刪除);至于很多人問過 kubernetes 這幾個(gè)能不能刪掉,答案是不可以的;因?yàn)楫?dāng)集群創(chuàng)建好后,default namespace 下會創(chuàng)建一個(gè)叫 kubenretes 的svc,有一些組件會直接連接這個(gè) svc 來跟 api 通信的,證書如果不包含可能會出現(xiàn)無法連接的情況;其他幾個(gè) kubernetes 開頭的域名作用相同
- hosts包含的是授權(quán)范圍,不在此范圍的的節(jié)點(diǎn)或者服務(wù)使用此證書就會報(bào)證書不匹配錯(cuò)誤。10.254.0.1是指kube-apiserver 指定的 service-cluster-ip-range 網(wǎng)段的第一個(gè)IP。
生成 Kubernetes 證書和私鑰
- $ cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kubernetes-csr.json | cfssljson -bare kubernetes
知識點(diǎn):
- -config 引用的是模板中的默認(rèn)配置文件,
- -profiles是指定特定的使用場景,比如config.json中的kubernetes區(qū)域
創(chuàng)建 admin 證書
創(chuàng)建 admin 證書請求文件admin-csr.json
- {
- "CN": "admin",
- "hosts": [],
- "key": {
- "algo": "rsa",
- "size": 2048
- },
- "names": [
- {
- "C": "CN",
- "ST": "BeiJing",
- "L": "BeiJing",
- "O": "system:masters",
- "OU": "System"
- }
- ]
- }
生成 admin 證書和私鑰
- $ cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin
知識點(diǎn): 這個(gè)admin 證書,是將來生成管理員用的kubeconfig 配置文件用的,現(xiàn)在我們一般建議使用RBAC 來對kubernetes 進(jìn)行角色權(quán)限控制, kubernetes 將證書中的CN字段作為User, O 字段作為 Group。
同樣,我們也可以按照同樣的方式來創(chuàng)建 Kubernetes 中 etcd 集群的證書
創(chuàng)建 etcd 集群證書
1. 證書簽署請求文件ca-csr.json
- {
- "CN": "etcd CA",
- "key": {
- "algo": "rsa",
- "size": 2048
- },
- "names": [
- {
- "C": "CN",
- "L": "Beijing",
- "ST": "Beijing"
- }
- ]
- }
2. 為節(jié)點(diǎn)創(chuàng)建服務(wù)證書請求文件,指定授權(quán)的主機(jī)節(jié)點(diǎn)etcd-server-csr.json
- {
- "CN": "etcd",
- "hosts": [
- "10.1.20.129",
- "10.1.20.126",
- "10.1.20.128"
- ],
- "key": {
- "algo": "rsa",
- "size": 2048
- },
- "names": [
- {
- "C": "CN",
- "L": "BeiJing",
- "ST": "BeiJing"
- }
- ]
- }
3. 證書配置模板文件ca-config.json
- {
- "signing": {
- "default": {
- "expiry": "87600h"
- },
- "profiles": {
- "etcd": {
- "expiry": "87600h",
- "usages": [
- "signing",
- "key encipherment",
- "server auth",
- "client auth"
- ]
- }
- }
- }
- }
4. 生成 etcd 集群所需的證書與私鑰
- $ cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
- $ cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=etcd etcd-server-csr.json | cfssljson -bare server
這樣就完成 etcd 所需證書的申請,同時(shí)了解了 cfssl 工具的強(qiáng)大,寫到這里,本次的實(shí)驗(yàn)就結(jié)束了。