全部產品
Search
文件中心

Alibaba Cloud Service Mesh:使用ACME CA為ASM網關簽發認證

更新時間:Jun 30, 2024

ACME(Automatic Certificate Management Environment)是一種用於自動化處理X.509數位憑證簽發請求的協議。通過ACME協議,可以自動驗證認證申請者的網域名稱所有權,然後為其簽發認證。Let's Encrypt是一個非營利性的公用CA(憑證授權單位),支援ACME協議,它可以簽發一般瀏覽器信任的認證。本文介紹如何使用cert-manager對接Let's Encrypt,為ASM網關簽發瀏覽器信任的HTTPS認證。

前提條件

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資源

  1. 使用資料面叢集的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,ingressClassNameistio。以下步驟將解釋該Solver如何生效。

    說明

    cert-manager支援使用Ingress API和Gateway API兩種類型的Solver。ASM也支援這兩種API。本樣本使用Ingress API。

  2. 等待Issuer就緒,使用以下命令,查看Issuer狀態。

    kubectl -n istio-system get issuer letsencrypt-prod-issuer

    預期輸出:

    NAME                      READY   AGE
    letsencrypt-prod-issuer   True    8m3s

步驟三:為ASM網關簽發認證

  1. 使用資料面叢集的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
  2. 等待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

展開查看預期輸出

{

    "authority_for": "xxxxxxx",

    "bytes_received": "0",

    "bytes_sent": "87",

    "downstream_local_address": "xx.xx.xx.xx:80",

    "downstream_remote_address": "xx.xx.xx.xx:57101",

    "duration": "0",

    "istio_policy_status": "-",

    "method": "GET",

    "path": "/.well-known/acme-challenge/JfKvfdSNmkR7UqmCQU0OSkJC3EsnP4ZUiCc28OLLLxA",

    "protocol": "HTTP/1.1",

    "request_id": "e6806d08-0469-4383-be8e-4d7506b39ec5",

    "requested_server_name": "-",

    "response_code": "200",

    "response_flags": "-",

    "route_name": "-",

    "start_time": "2024-04-08T12:04:06.153Z",

    "trace_id": "-",

    "upstream_cluster": "outbound|8089||cm-acme-http-solver-c4ch9.istio-system.svc.cluster.local",

    "upstream_host": "xx.xx.xx.xx:8089",

    "upstream_local_address": "xx.xx.xx.xx:55886",

    "upstream_response_time": "0",

    "upstream_service_time": "0",

    "upstream_transport_failure_reason": "-",

    "user_agent": "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)",

    "x_forwarded_for": "xx.xx.xx.xx"

}

可以看到網關上確實存在Let's Encrypt發出的請求,並且該請求被正常返回。在Issuer中配置了ingressClassNameistio。cert-manager會自動建立一個ingressClassNameistio的Ingress資源,將Challenge請求轉寄給cert-manager對應的Solver來完成驗證。

在Certificate就緒之後,使用kubectl -n istio-system get ingress無法看到相關的Ingress資源,是因為cert-manager在完成認證簽發後,會自動刪除Solver相關的資源,包括Ingress、Service、Deployment等資源。

步驟四:驗證Let's Encrypt簽發的認證

  1. 建立如下網關規則,在網關的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
  2. 修改原有的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
  3. 在瀏覽器中訪問https://${測試網域名稱}

    可以看到如下形式的瀏覽器地址欄,單擊image表徵圖,顯示串連安全,表明瀏覽器已經信任您的認證。

    image