ACME(Automatic Certificate Management Environment)是一種用於自動化處理X.509數位憑證簽發請求的協議。通過ACME協議,可以自動驗證認證申請者的網域名稱所有權,然後為其簽發認證。Let's Encrypt是一個非營利性的公用CA(憑證授權單位),支援ACME協議,它可以簽發一般瀏覽器信任的認證。本文介紹如何使用cert-manager對接Let's Encrypt,為ASM網關簽發瀏覽器信任的HTTPS認證。
前提條件
已添加ACK叢集到ASM執行個體,且ASM執行個體版本為1.16及以上。具體操作,請參見添加叢集到ASM執行個體和升級ASM執行個體。
已部署入口網關,並暴露80和443連接埠。具體操作,請參見建立入口網關。
已在ASM執行個體關聯的叢集中部署httpbin應用。具體操作,請參見部署httpbin應用。
已安裝cert-manager。具體操作,請參見在叢集中安裝cert-manager。
已在ASM網關上啟用Ingress API支援,具體操作,請參見步驟一:在目標網關上啟用Ingress。
cert-manager中的ACME說明
在使用cert-manager時,ACME Issuer組件負責向支援ACME協議的CA Server註冊使用者賬戶。建立ACME Issuer的過程中,cert-manager將為您產生一個私密金鑰,這個私密金鑰專門用於與ACME CA Server進行安全通訊。公用CA(如Let's Encrypt)頒發的認證通常被用戶端(如Web瀏覽器)所信任。這意味著當使用者通過瀏覽器訪問您的網站時,他們會自動信任該網站的SSL/TLS認證。公用CA頒發認證的主要目的是為了向瀏覽器證明當前伺服器確實是該網域名稱的合法服務提供者。為此,公用CA在頒發認證前需要核實申請認證的伺服器實際上控制著該網域名稱。更多關於ACME協議的定義和細節,請參見Automatic Certificate Management Environment。
Solving Challenges
挑戰(Challenges)是ACME協議中用於驗證認證申請者對目標網域名稱所有權的關鍵機制。在申請認證的過程中,ACME CA Server會要求用戶端(認證申請者)完成特定的挑戰,以確保只有網域名稱的合法所有者能成功申請對應的認證,以此來提高網路安全性,避免網域名稱冒充的風險。cert-manager支援兩種主要的挑戰類型:HTTP-01 Challenge和DNS-01 Challenge。
HTTP-01 Challenge依賴於伺服器在特定HTTP URL上公開由ACME用戶端產生的驗證密鑰。該密鑰應位於一個可公網訪問的URL中,其路徑需包含待申請認證的網域名稱。當ACME CA Server能按約定路徑從互連網上成功檢索到該密鑰,即認為申請者對目標網域名稱具備有效控制權。為了簡化這一過程,當設定了HTTP-01Challenge,cert-manager會自動調整叢集的Ingress設定,將指向該驗證密鑰URL的請求導向一個專門設立的小型Web服務。該服務承載著所需的驗證密鑰,用於響應ACME伺服器發起的挑戰驗證。
DNS-01 Challenge是通過在DNS系統中發布一條包含特定計算得出密鑰的TXT記錄來完成驗證。當這條TXT記錄在全球DNS緩衝中傳播生效後,ACME CA Server可通過標準DNS查詢來檢索該密鑰,從而確認申請者對指定網域名稱的實際所有權。在此過程中,具備適當許可權的cert-manager會自動為所使用的DNS服務商產生並提交所需TXT記錄,以滿足DNS-01 Challenge的要求。
實際情境中,您需要確認您當前的憑證授權單位是否支援ACME協議。如果支援,則ASM網關可以通過cert-manager自動從CA處擷取認證。例如,Sectigo目前已經支援了ACME協議,其原理與本文所述類似,詳情請參見Overview。
步驟一:準備公網網域名稱
要使用Let's Encrypt為網域名稱簽發認證,首先需要有一個公網網域名稱,並且需要您將公網網域名稱指向要使用的ASM網關。具體流程,請參見您的DNS供應商的文檔。如果您使用的是阿里雲提供的DNS服務,請參見添加解析記錄。關於Let's Encrypt的說明,請參見Getting Started。
步驟二:建立對接Let's Encrypt的Issuer資源
使用資料面叢集的KubeConfig,建立如下資源。
apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: letsencrypt-prod-issuer namespace: istio-system spec: acme: email: 'te**@mail.com' # 這個不是必要欄位,但是建議填寫。ACME Server可能通過該郵箱向您發送與認證相關的重要通知。 privateKeySecretRef: name: letsencrypt-prod server: https://acme-v02.api.letsencrypt.org/directory solvers: - http01: ingress: ingressClassName: istio
上述Issuer資源指定了一個
http01
類型的Solver,使用Ingress API,ingressClassName
為istio
。以下步驟將解釋該Solver如何生效。說明cert-manager支援使用Ingress API和Gateway API兩種類型的Solver。ASM也支援這兩種API。本樣本使用Ingress API。
等待Issuer就緒,使用以下命令,查看Issuer狀態。
kubectl -n istio-system get issuer letsencrypt-prod-issuer
預期輸出:
NAME READY AGE letsencrypt-prod-issuer True 8m3s
步驟三:為ASM網關簽發認證
使用資料面叢集的KubeConfig,建立如下資源。
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: istio-ingressgateway-certs namespace: istio-system spec: dnsNames: - ${測試網域名稱} # test.com issuerRef: group: cert-manager.io kind: Issuer name: letsencrypt-prod-issuer secretName: istio-ingressgateway-certs
等待Certificate就緒,使用以下命令,查看Certificate狀態。
kubectl -n istio-system get certificate istio-ingressgateway-certs
預期輸出:
NAME READY SECRET AGE istio-ingressgateway-certs True istio-ingressgateway-certs 59m
認證簽發過程解析
建立Certificate資源之後,cert-manager會使用建立的Issuer為這個網域名稱簽發認證。這個過程中,配置的Solver就會生效。
Let's Encrypt將會使用HTTP-01 Challenge來確認:當前Server是這個網域名稱的所有者。為此,Let's Encrypt會發送一個HTTP請求到這個網域名稱,然後它需要擷取到一個合法的傳回值,才可以完成驗證。在本樣本中,網關上只有httpbin的路由規則,並沒有任何和Challenge有關的配置。Let's Encrypt是否真的發送了Challenge請求?請求如何被響應?
您可以執行以下命令,查看網關日誌,判斷Let's Encrypt是否真的發送了Challenge請求。
kubectl -n istio-system logs ${網關Pod名稱} | grep letsencrypt | tail -1
可以看到網關上確實存在Let's Encrypt發出的請求,並且該請求被正常返回。在Issuer中配置了ingressClassName
為istio
。cert-manager會自動建立一個ingressClassName
為istio
的Ingress資源,將Challenge請求轉寄給cert-manager對應的Solver來完成驗證。
在Certificate就緒之後,使用kubectl -n istio-system get ingress
無法看到相關的Ingress資源,是因為cert-manager在完成認證簽發後,會自動刪除Solver相關的資源,包括Ingress、Service、Deployment等資源。
步驟四:驗證Let's Encrypt簽發的認證
建立如下網關規則,在網關的443連接埠上配置步驟三產生的認證。具體操作,請參見管理網關規則。
apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: httpbin-https namespace: default spec: selector: istio: ingressgateway servers: - hosts: - ${測試網域名稱} port: name: https number: 443 protocol: HTTPS tls: credentialName: istio-ingressgateway-certs mode: SIMPLE
修改原有的httpbin-vs虛擬服務為以下內容。具體操作,請參見管理虛擬服務。
apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpbin-vs namespace: default spec: gateways: - httpbin - httpbin-https # 新增這一行。 hosts: - '*' http: - name: test route: - destination: host: httpbin.default.svc.cluster.local port: number: 8000
在瀏覽器中訪問
https://${測試網域名稱}
。可以看到如下形式的瀏覽器地址欄,單擊表徵圖,顯示串連安全,表明瀏覽器已經信任您的認證。