过渡到不同的 PKI 模式

Google Distributed Cloud (GDC) air-gapped 提供了一个公钥基础结构 (PKI) API 来获取 Web 证书。本页面介绍了如何从一种 PKI 证书模式过渡到另一种模式。如需详细了解 PKI 模式配置类型,请参阅Web TLS 证书配置

准备工作

如需获得配置 PKI 默认证书签发者所需的权限,请让您的组织 IAM 管理员为您授予系统命名空间中的 Infra PKI Admin (infra-pki-admin) 角色。

改用自带子 CA 模式

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

创建自带子 CA

如需创建自带子 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 证书的请求生命周期。
    • RENEW_BEFORE:CA 证书过期前的轮替时间。
    • SECRET_NAME:将包含私钥和已签名的 CA 证书的 Kubernetes Secret 的名称。
  2. 将自定义资源应用到 Distributed Cloud 区域。

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

    MANAGEMENT_API_SERVER 替换为管理 API 服务器 kubeconfig 文件。

为子 CA 生成 CSR 并等待您对其进行签名。如需签署 CSR,请按照签署自带的子 CA 证书部分中的说明操作。

为自带子 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. 验证证书中的主题备用名称 (SAN) 扩展项:

      openssl x509 -text -noout -in sub_ca.crt | grep -A 1 "Subject Alternative Name"
      

      如果 CA 证书具有公用名 (CN) 而不是 SAN,请验证证书中的 CN

      openssl x509 -text -noout -in sub_ca.crt | grep -A 1 "Subject: CN"
      
  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. 验证自带子 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 替换为自带子 CA 签发者的名称。

  10. 使用 kubectl CLI 将自定义资源应用到管理 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))'
    

改用自带证书模式

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

创建自带证书的 CertificateIssuer

  1. 创建 CertificateIssuer 资源并将其保存为 YAML 文件,例如 byo-cert-issuer.yaml。此自带证书颁发者使用受管理的 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 替换为自带证书的签发者的名称。

  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"
    }
    

为自带证书签名

  1. 在等待外部签署 CSR 时,可由 BYO-cert 颁发者中指定的后备 CA 临时颁发 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 证书与来自同一证书签发机构的 default-wildcard-cert(具有 DNSName *.org-1.zone1.google.gdch.test)相匹配。在等待签署 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
    

过渡到采用 ACME 模式的自带证书

本部分提供了一系列步骤,用于过渡到采用 ACME 模式的自带证书。

创建具有 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:用于验证 ACME 服务器提供的证书链的 Base64 编码的 PEM CA 捆绑包。
    • 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 网络证书