过渡到不同的 PKI 模式

Google Distributed Cloud (GDC) 网闸隔离配置提供公钥基础架构 (PKI) API,用于获取 Web 证书。本文档提供了从一种 PKI 证书模式转换到另一种模式的说明。如需详细了解 PKI 模式配置类型,请参阅 Web TLS 证书配置。

本文档适用于希望管理证书授权机构和证书颁发者的平台管理员群组中的受众群体。如需了解详情,请参阅适用于 GDC 网闸隔离配置文档的受众群体。

准备工作

在转换 PKI 模式之前,您必须拥有必要的权限并准备好环境。

申请 IAM 角色

如需创建、更新和删除证书授权机构和证书颁发机构,请与您的 IAM 组织管理员联系,请求在系统命名空间中授予 PKI Infra Admin (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:从属 CA 的名称。
    • COMMON_NAME:CA 证书的通用名称。
    • DURATION:CA 证书的请求生命周期。以小时为单位指定时长(例如 1000h)。不支持天 (d) 或年 (y) 等单位。
    • RENEW_BEFORE:CA 证书到期前的轮替时间。
    • SECRET_NAME:将保存私钥和已签名 CA 证书的 Kubernetes Secret 的名称。
  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. 验证 BYO 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-cert 颁发者的名称。

  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-cert 颁发者中指定的后备 CA 可以临时颁发 BYO-cert。获取当前的 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 签名时,可以暂时使用匹配的证书。dnsName 为 example-service.org-1.zone1.google.gdch.test 的 example-service 证书与来自同一证书颁发机构、DNSName 为 *.org-1.zone1.google.gdch.test 的 default-wildcard-cert 匹配。在等待其 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-cert。

创建具有 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。如果您未提供此 Secret,系统会自动生成一个同名的新 Secret 来存储 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 Web 证书。