过渡到不同的 PKI 模式

Google Distributed Cloud (GDC) 网闸隔离配置提供了一个公钥基础架构 (PKI) API 来获取 Web 证书。本文档介绍了如何从一种 PKI 证书模式过渡到另一种模式。如需详细了解 PKI 模式 配置类型,请参阅 Web TLS 证书配置

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

准备工作

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

请求 IAM 角色

如需创建、更新和删除证书授权机构和证书颁发者,请与组织 IAM 管理员联系,以请求系统命名空间中的 PKI 基础架构管理员 (infra-pki-admin) 角色。

准备环境

过渡到 BYO 子 CA 模式

本部分提供了一系列步骤,用于过渡到自带 (BYO) 子 CA 证书模式。

创建 BYO 子 CA

如需创建 BYO 子 CA,请将自定义资源应用于 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 子 CA 证书进行签名部分中的说明操作。

对 BYO 子 CA 证书进行签名

  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 子 CA 的就绪情况:

    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 子 CA 颁发者的名称。

  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 证书模式。

创建 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 证书可以由 BYO 证书颁发者中指定的后备 CA 临时颁发。获取当前 BYO 证书 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 证书) 在等待自己的 CSR 签名时,可以暂时使用匹配的证书。例如,dnsName 为 example-service.org-1.zone1.google.gdch.test 的 example-service 证书与来自同一证书颁发者的 DNSName 为 *.org-1.zone1.google.gdch.testdefault-wildcard-cert 匹配。example-service 证书在等待其 CSR 签名时可以保持以下状态:

    {
      "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"
    }
    
    • Secret 已更新:
    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
    

过渡到采用 ACME 模式的 BYO 证书

本部分提供了一系列步骤,用于过渡到采用 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:PEM CA 的 Base64 编码软件包,用于 验证 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 证书