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 区域。
创建
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 的名称。
将自定义资源应用到 Distributed Cloud 区域。
kubectl apply -f byo-subca.yaml --kubeconfig MANAGEMENT_API_SERVER
将 MANAGEMENT_API_SERVER 替换为管理 API 服务器 kubeconfig 文件。
为子 CA 生成 CSR 并等待您对其进行签名。如需签署 CSR,请按照签署自带的子 CA 证书部分中的说明操作。
为自带子 CA 证书签名
从 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。使用客户的根 CA 协议为
sub_ca.csr
文件请求已签名的 CA 证书。对于已获批准的证书签名请求,您将获得由客户的根 CA 签名的 CA 证书。将证书存储到当前目录中的
sub_ca.crt
文件。此外,获取客户的根 CA 证书,并将其存储到当前目录中的ca.crt
文件中。如需确切的说明,请与 PMO 联系。请验证以下各项,以确保证书的完整性和准确性:
确保
sub_ca.crt
符合标准的 PEM 编码证书格式:-----BEGIN CERTIFICATE----- <Certificate> -----END CERTIFICATE-----
验证
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
验证证书中的主题备用名称 (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"
生成用于修补
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…
修改
CertificateAuthority
资源的规范:kubectl patch certificateauthority CA_NAME -n pki-system --patch-file patch.txt --type='merge'
验证自带子 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" }
验证已签名的 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
创建
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 签发者的名称。
使用
kubectl
CLI 将自定义资源应用到管理 API 服务器中的 Distributed Cloud 区域:kubectl apply -f byo-subca-issuer.yaml --kubeconfig MANAGEMENT_API_SERVER
验证新签发机构的就绪情况:
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
创建
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 替换为自带证书的签发者的名称。
在 Management API 服务器中将自定义资源应用到 Distributed Cloud 区域:
kubectl apply -f byo-cert-issuer.yaml --kubeconfig MANAGEMENT_API_SERVER
验证新签发机构是否已准备就绪。
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" }
为自带证书签名
在等待外部签署 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 中,可供随时使用。获取证书 Secret 名称:
kubectl -n istio-system get certificate.pki.security.gdc.goog/default-wildcard-cert -ojson | jq -r '.spec.secretConfig.secretName'
输出类似于以下内容:
web-tls
检查 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" }
从证书状态中获取 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..." }
根据外部 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
验证以下详细信息:
- 证书的 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
- 证书的 CSR 状态为
过渡到采用 ACME 模式的自带证书
本部分提供了一系列步骤,用于过渡到采用 ACME 模式的自带证书。
创建具有 ACME 配置的 CertificateIssuer
创建包含 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 账号私钥。
将自定义资源应用到 Distributed Cloud 可用区:
kubectl apply -f acme-issuer.yaml --kubeconfig MANAGEMENT_API_SERVER
验证新签发机构的就绪情况:
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 网络证书。