轉換至其他 PKI 模式

Google Distributed Cloud (GDC) 實體隔離方案提供公用金鑰基礎架構 (PKI) API,可取得網路憑證。本文說明如何從一種 PKI 憑證模式轉換至另一種。如要進一步瞭解 PKI 模式設定類型,請參閱「網頁 TLS 憑證設定」。

本文適用於平台管理員群組中,想要管理憑證授權單位和憑證核發者的對象。詳情請參閱「GDC 實體隔離方案說明文件的目標對象」。

事前準備

轉換 PKI 模式前,您必須具備必要權限並準備環境。

要求 IAM 角色

如要建立、更新及刪除憑證授權單位和憑證核發者,請與 IAM 機構組織管理員聯絡,要求系統命名空間中的 PKI Infra 管理員 (infra-pki-admin) 角色。

準備環境

轉換為 BYO subCA 模式

本節提供一系列步驟,說明如何轉換至自備 (BYO) subCA 憑證模式。

建立 BYO subCA

如要建立 BYO subCA,請將自訂資源套用至 Distributed Cloud 區域。

  1. 建立 CertificateAuthority 資源,並儲存為 YAML 檔案。在以下範例中,您會看到 CertificateAuthority 資源範例

    apiVersion: pki.security.gdc.goog/v1
    kind: CertificateAuthority
    metadata:
      name: CA_NAME
      namespace: pki-system
    spec:
      caProfile:
        commonName: COMMON_NAME
        duration: DURATION
        renewBefore: RENEW_BEFORE
      caCertificate:
        externalCA: {}
      certificateProfile:
        keyUsage:
        - digitalSignature
        - keyCertSign
        - crlSign
        extendedKeyUsage:
        - serverAuth
      secretConfig:
        secretName: SECRET_NAME
    

    請替換下列變數:

    • CA_NAME:subCA 的名稱。
    • COMMON_NAME:CA 憑證的一般名稱。
    • DURATION:要求的 CA 憑證生命週期。請以小時為單位指定時間長度 (例如 1000h)。不支援天 (d) 或年 (y) 等單位。
    • RENEW_BEFORE:CA 憑證到期前的輪替時間。
    • SECRET_NAME:Kubernetes Secret 的名稱,用於保存私密金鑰和已簽署的 CA 憑證。
  2. 將自訂資源套用至 Distributed Cloud 可用區。

    kubectl apply -f byo-subca.yaml --kubeconfig MANAGEMENT_API_SERVER
    

    將 MANAGEMENT_API_SERVER 替換為 Management API 伺服器 kubeconfig 檔案。

系統會產生下層 CA 的 CSR,並等待您簽署。如要簽署 CSR,請按照「簽署 BYO subCA 憑證」一節的指示操作。

簽署 BYO subCA 憑證

  1. 從 GDC 環境取得憑證簽署要求 (CSR):

    kubectl get certificateauthorities CA_NAME -n pki-system -ojson | jq -j '"echo ",
    .status.externalCA.csr, " | base64 -d > ","sub_ca.csr\n"' | bash
    

    這個指令會在目前目錄中產生 sub_ca.csr 檔案。這個檔案包含 X.509 CA 憑證的 CSR。

  2. 使用客戶根 CA 的通訊協定,要求 sub_ca.csr 檔案的已簽署 CA 憑證。

  3. 如果憑證簽署要求獲得核准,您會取得由客戶根 CA 簽署的 CA 憑證。將憑證儲存至目前目錄中的 sub_ca.crt 檔案。此外,請取得客戶的根 CA 憑證,並將其儲存至目前目錄中的 ca.crt 檔案。如需確切操作說明,請洽詢 PMO。

  4. 請確認下列事項,確保憑證完整正確:

    1. 確認 sub_ca.crt 符合標準 PEM 編碼憑證格式:

      -----BEGIN CERTIFICATE-----
            <Certificate>
      -----END CERTIFICATE-----
      
    2. 確認 sub_ca.crt 是「基本限制」擴充功能中的有效憑證授權單位 (CA):

      openssl x509 -text -noout -in sub_ca.crt | grep -A 1 "Basic Constraints"
      

      輸出內容必須包含 CA:TRUE,否則需要進一步調查:

      X509v3 Basic Constraints: critical
          CA:TRUE
      
    3. 驗證 CA 憑證的一般名稱 (CN):

      openssl x509 -noout -subject -in sub_ca.crt
      

      如果您的設定需要主體別名 (SAN) 擴充功能,請驗證憑證中的 SAN 擴充功能:

      openssl x509 -text -noout -in sub_ca.crt | grep -A 1 "Subject Alternative Name"
      
  5. 產生規格來修補 CertificateAuthority 資源:

     echo "spec:
    caCertificate:
      externalCA:
        signedCertificate:
          certificate: $(base64 -w0 sub_ca.crt)
          ca: $(base64 -w0 ca.crt)" > patch.txt
    

    patch.txt 檔案中的內容類似下列程式碼片段:

     spec:
      caCertificate:
       externalCA:
        signedCertificate:
         certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURSekNDQ…
         ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURRVENDQ…
    
  6. 編輯 CertificateAuthority 資源的規格:

    kubectl patch certificateauthority CA_NAME -n pki-system --patch-file patch.txt --type='merge'
    
  7. 確認自備 subCA 是否就緒:

    kubectl get certificateauthority CA_NAME -n pki-system -ojson | jq -r ' .status.conditions[] | select( .type as $id | "Ready" | index($id))'
    

    畫面會顯示類似以下內容的輸出:

    {
      "lastTransitionTime": "2024-04-30T22:10:50Z",
      "message": "Certificate authority is ready for use",
      "observedGeneration": 3,
      "reason": "Ready",
      "status": "True",
      "type": "Ready"
    }
    
  8. 確認已簽署 CA 憑證的到期日:

    kubectl -n pki-system get secret SECRET_NAME -ojson | jq -j '"echo ",
    .metadata.name, " $(echo ", .data["tls.crt"], "| base64 -d | openssl x509 -enddate -noout)\n"' | bash
    
  9. 建立 CertificateIssuer 資源 YAML 檔案並儲存。例如:byo-subca-issuer.yaml:

    apiVersion: pki.security.gdc.goog/v1
    kind: CertificateIssuer
    metadata:
      name: BYO_SUBCA_ISSUER
      namespace: pki-system
    spec:
      caaasConfig:
        certificateAuthorityRef:
          namespace: pki-system
          name: CA_NAME
    

    將 BYO_SUBCA_ISSUER 替換為 BYO subCA 核發者的名稱。

  10. 使用 kubectl CLI,將自訂資源套用至 Management API 伺服器中的 Distributed Cloud 區域:

    kubectl apply -f byo-subca-issuer.yaml --kubeconfig MANAGEMENT_API_SERVER
    
  11. 確認新核發機構是否準備就緒:

    kubectl -n pki-system get certificateissuer.pki.security.gdc.goog/BYO_SUBCA_ISSUER -ojson | jq -r ' .status.conditions[] | select( .type as $id | "Ready" | index($id))'
    

轉換至 BYO 憑證模式

本節提供一系列步驟,協助您轉換至 BYO-cert 模式。

建立 BYO CertificateIssuer

  1. 建立 CertificateIssuer 資源,並儲存為 YAML 檔案,例如 byo-cert-issuer.yaml。這個 BYO 憑證核發者使用代管的 default-tls-ca 做為備用 CA:

    apiVersion: pki.security.gdc.goog/v1
    kind: CertificateIssuer
    metadata:
      name: BYO_CERT_ISSUER_NAME
      namespace: pki-system
    spec:
      byoCertConfig:
        fallbackCertificateAuthority:
          name: default-tls-ca
          namespace: pki-system
    

    將 BYO_CERT_ISSUER_NAME 替換為 BYO 憑證核發者的名稱。

  2. 在 Management API 伺服器中,將自訂資源套用至 Distributed Cloud 區域:

    kubectl apply -f byo-cert-issuer.yaml --kubeconfig MANAGEMENT_API_SERVER
    
  3. 確認新發卡機構是否已準備就緒。

    kubectl -n pki-system get certificateissuer.pki.security.gdc.goog/BYO_CERT_ISSUER_NAME -ojson | jq -r ' .status.conditions[] | select( .type as $id | "Ready" | index($id))'
    

    輸出看起來類似以下內容:

    {
      "lastTransitionTime": "2024-05-01T22:25:20Z",
      "message": "",
      "observedGeneration": 1,
      "reason": "FallbackCAReady",
      "status": "True",
      "type": "Ready"
    }
    

簽署 BYO 憑證

  1. 等待 CSR 取得外部簽署時,BYO 憑證核發者指定的備用 CA 可暫時核發 BYO 憑證。取得目前的 BYO-cert default-wildcard-cert 狀態:

    kubectl get certificate.pki.security.gdc.goog/default-wildcard-cert -n istio-system -o json | jq -r ' .status.conditions[] | select( .type as $id | "Ready" | index($id))'
    

    輸出看起來類似以下內容:

    {
      "lastTransitionTime": "2024-05-03T08:42:10Z",
      "message": "Certificate is issued by a fallback CA",
      "observedGeneration": 1,
      "reason": "UsingFallbackCA",
      "status": "True",
      "type": "Ready"
    }
    

    就緒原因會顯示 UsingFallbackCA,表示備用 CA 核發了憑證。接著,系統會將密鑰儲存在 Secret 中,供您使用。

  2. 取得憑證 Secret 名稱:

    kubectl -n istio-system get certificate.pki.security.gdc.goog/default-wildcard-cert -ojson | jq -r '.spec.secretConfig.secretName'
    

    輸出看起來類似以下內容:

    web-tls
    
  3. 檢查 Secret 的核發者:

    kubectl get secret web-tls -n istio-system -o jsonpath='{.data.tls\.crt}' |
    base64 -d | openssl x509 -text -noout | grep Issuer
    

    輸出看起來類似以下內容:

    Issuer: CN = GDC Managed ORG TLS CA
    

    自備憑證 (BYO-cert) 在等待自己的 CSR 簽章時,可以暫時使用相符的憑證。default-wildcard-cert 的 DNSName 為 *.org-1.zone1.google.gdch.test,與 dnsName 為 example-service.org-1.zone1.google.gdch.test 的 example-service 憑證相符,且兩者來自相同的憑證核發者。在等待 CSR 簽署期間,example-service 憑證可能會有下列狀態:

    {
      "lastTransitionTime": "2024-05-03T22:30:51Z",
      "message": "Using a matched issued Certificate: default-wildcard-cert/istio-system",
      "observedGeneration": 1,
      "reason": "UsingMatchedCert",
      "status": "True",
      "type": "Ready"
    }
    
  4. 從憑證狀態取得 CSR:

    kubectl -n istio-system get certificate.pki.security.gdc.goog/default-wildcard-cert -ojson | jq -r ' .status.byoCertStatus.csrStatus'
    

    輸出看起來類似以下內容:

    {
      "conditions": [
        {
          "lastTransitionTime": "2024-05-03T18:14:19Z",
          "message": "",
          "observedGeneration": 1,
          "reason": "WaitingForSigning",
          "status": "False",
          "type": "Ready"
        }
      ],
      "csr": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSB..."
    }
    
  5. 根據外部 CA 設定,簽署 CSR 的方法不盡相同。簽署時,請使用 CSR 的 SAN。例如:

    function signCert() {
       certName=$1
       ns=$2
    
       # Download the CSR from the certificate
       kubectl get certificate.pki.security.gdc.goog $certName -n $ns -o jsonpath='{.status.byoCertStatus.csrStatus.csr}' | base64 -d > $certName.csr
    
       # Get SAN from the csr
       san=$(openssl req -in $certName.csr -noout -text | grep 'DNS:' | sed -s 's/^[ ]*//')
    
       # Save SAN to extension config
       cat <<EOF >$certName-csr.ext
     keyUsage=digitalSignature,keyEncipherment
     extendedKeyUsage=serverAuth,clientAuth
     subjectAltName=${san}
     EOF
    
       # Sign the CSR with an external CA. You need to prepare the external CA cert and key
       openssl x509 -req -in $certName.csr -days 365 -CA ext-ca.crt -CAkey ext-ca.key -CAcreateserial -extfile $certName-csr.ext -out $certName-signed.crt
       openssl x509 -in $certName-signed.crt -text -noout
    
       # Upload the externally signed certificate by patching.
       echo "spec:
         byoCertificate:
            certificate: $(base64 -w0 $certName-signed.crt)
            ca: $(base64 -w0 ext-ca.crt)" > patch.txt
    
       kubectl patch certificate.pki.security.gdc.goog $certName -n $ns --patch-file patch.txt --type='merge'
     }
    
     # Use the function to sign the default-wildcard-cert in the istio-system namespace
     signCert default-wildcard-cert istio-system
    
  6. 確認下列詳細資料:

    • 憑證的 CSR 狀態為「Ready」
    kubectl -n istio-system get certificate.pki.security.gdc.goog/default-wildcard-cert -ojson | jq -r ' .status.byoCertStatus.csrStatus.conditions'
    
    [
       {
          "lastTransitionTime": "2024-05-03T21:56:25Z",
          "message": "",
          "observedGeneration": 2,
          "reason": "Signed",
          "status": "True",
          "type": "Ready"
       }
    ]
    
    • 憑證為Ready,原因為Issued
    kubectl get certificate.pki.security.gdc.goog/default-wildcard-cert -n istio-system -o json | jq -r ' .status.conditions[] | select( .type as $id | "Ready" | index($id))'
    

    輸出看起來類似以下內容:

    {
      "lastTransitionTime": "2024-05-03T08:42:10Z",
      "message": "Certificate is issued",
      "observedGeneration": 2,
      "reason": "Issued",
      "status": "True",
      "type": "Ready"
    }
    
    • 密鑰已更新:
    kubectl get secret web-tls -n istio-system -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -noout | grep Issuer
    

    輸出看起來類似以下內容:

            Issuer: CN = external-ca
    

改用 BYO 憑證 (ACME 模式)

本節提供一系列步驟,說明如何轉換至採用 ACME 模式的 BYO 憑證。

建立具有 ACME 設定的 CertificateIssuer

  1. 建立具有 ACME 設定的 CertificateIssuer 資源,並儲存為 YAML 檔案,例如 acme-issuer.yaml。

    apiVersion: pki.security.gdc.goog/v1
    kind: CertificateIssuer
    metadata:
      name: ACME_ISSUER_NAME
      namespace: pki-system
    spec:
         acmeConfig:
           rootCACertificate: ROOT_CA_CERTIFICATE
           acme:
             server: ACME_SERVER_URL
             caBundle: CA_BUNDLE
             privateKeySecretRef:
               name: PRIVATE_KEY_SECRET_NAME
    

    請替換下列變數:

    • ACME_ISSUER_NAME:ACME 核發者的名稱。
    • ROOT_CA_CERTIFICATE:ACME 伺服器核發的憑證根 CA 資料。
    • ACME_SERVER_URL:用於存取 ACME 伺服器目錄端點的網址。
    • CA_BUNDLE:Base64 編碼的 PEM CA 套裝組合,用於驗證 ACME 伺服器提供的憑證鏈結。
    • PRIVATE_KEY_SECRET_NAME:包含 ACME 帳戶私密金鑰的 Secret 名稱。

    如要使用現有的 ACME 帳戶私密金鑰,請確保保存該金鑰的 Secret 在與 ACME 核發者相同的命名空間中,使用 PRIVATE_KEY_SECRET_NAME 名稱。如未提供,系統會自動產生同名的密鑰,用於儲存 ACME 帳戶私密金鑰。

  2. 將自訂資源套用至 Distributed Cloud 區域:

    kubectl apply -f acme-issuer.yaml --kubeconfig MANAGEMENT_API_SERVER
    
  3. 確認新核發機構是否準備就緒:

    kubectl --kubeconfig MANAGEMENT_API_SERVER -n pki-system get certificateissuer.pki.security.gdc.goog/ACME_ISSUER_NAME -ojson | jq -r ' .status.conditions[] | select( .type as $id | "Ready" | index($id))'
    

    畫面會顯示類似以下內容的輸出:

    {
      "lastTransitionTime": "2024-05-01T18:32:17Z",
      "message": "",
      "observedGeneration": 1,
      "reason": "ACMEClientReady",
      "status": "True",
      "type": "Ready"
    }
    

重新核發憑證

如要將預設核發者切換為新的 ACME 核發者,請參閱「變更預設憑證核發者」一節。

如要立即使用新的預設核發者重新核發憑證,請參閱「手動重新核發 PKI 網路憑證」。