概览
本指南介绍了如何将 Keyfactor EJBCA Enterprise(部署为外部设备)集成为 Google Distributed Cloud (GDC) 气隙环境的第三方证书颁发机构 (CA)。
Keyfactor EJBCA Enterprise 是一款高度可伸缩、稳健且符合 FIPS 标准的证书授权机构平台,可帮助组织在异构环境中管理公钥基础架构 (PKI)。
GDC 网闸隔离配置包含一个内置的证书授权机构服务,用于在托管云边界内自动管理密钥和证书。不过,如果组织已针对 GDC 以外的现有工作负载将 PKI 基础架构标准化为 Keyfactor EJBCA,则可能更倾向于针对在气隙 GDC 环境中运行的工作负载利用相同的一致 CA 架构和管理政策。
本指南演示了如何配置 GDC 网络、内部 DNS 和 Kubernetes cert-manager,以自动执行证书生命周期管理 (ACME),并使用注册机构 (RA) 模式支持大批量程序化签发。
前提
在继续阅读本指南之前,请确保满足以下假设条件:
- Keyfactor EJBCA 部署为软件设备或硬件设备,并为该服务配置了稳定的 IP 地址。
- 已在 EJBCA 实例中创建根证书授权机构 (CA)、从属证书授权机构和管理证书授权机构。
- 已配置实体 (EE) 配置文件(例如,用于 TLS 服务器证书)。
- 已下载管理 CA 用户的证书。
- EJBCA 实例上已启用必需的协议(例如 ACME)。
- 本指南中使用的是 RSA 签名算法。您可以根据具体要求或 EJBCA 实例中的配置更改签名算法。
架构
该架构遵循外部证书授权机构模型,其中 EJBCA 服务器及其后端的硬件安全模块 (HSM) 托管在物理 GDC 边界之外,但可通过网络访问。EJBCA 服务器可以部署在外部,可以是硬件设备,也可以是软件设备。本指南中介绍的核心集成仅要求外部 EJBCA 服务器可通过稳定的 IP 地址访问。

此架构的关键组件包括:
- EJBCA Enterprise Server:在外部部署为 Keyfactor 硬件设备或软件设备,其中包含 CA(根 CA 和从属 CA),并在经过 CC EAL4+ 认证的 HSM 中生成所有 CA 密钥材料。
- GDC Standard Kubernetes 集群:运行客户工作负载、cert-manager 和集成代理的计算环境。
- GDC 内部 DNS:管理用于解析 ACME DNS-01 质询的本地专用 DNS 区域(使用在环境变量中配置的专用域名)。
- GDC 出站网关:将集群 pod 的出站流量定向到外部 EJBCA 服务器 IP 地址。
- Harbor 私有注册表:托管镜像容器映像(例如 EJBCA cert-manager 签发者),用于气隙部署。
准备工作
在开始集成之前,请确保您的 GDC 环境满足以下要求:
- 首先,创建一个项目,用于存放本指南中生成的所有资源。
配置本指南中将引用的环境变量。根据需要修改这些值,以匹配您的特定环境:
# GDC Environment Configuration export GDC_ORG="your-org-name" export GDC_ZONE="your-zone-name" export GDC_PROJECT_ID="your-project-id" export GDC_USER_NAME="your-gdc-user-email" export GDC_CLUSTER_NAME="your-cluster-name" # EJBCA Server Configuration export EJBCA_DNS_ZONE="example.internal" export EJBCA_HOSTNAME="ejbca.${EJBCA_DNS_ZONE}" export EJBCA_LB_IP="XX.XX.XX.XX" # Stable IP of your EJBCA Server export EJBCA_CA_NAME="GDC Subordinate CA" export EJBCA_NAMESPACE="ejbca-ee" export CERTIFICATE_PROFILE_NAME="GDC TLS SERVER PROFILE" export END_ENTITY_PROFILE_NAME="GDC TLS SERVER EE PROFILE" # Harbor Private Registry Configuration export HARBOR_INSTANCE_URL="your-harbor-url.internal" export HARBOR_PROJECT="your-harbor-project" export HARBOR_ROBOT_ACCOUNT="robot$your-robot-name" export HARBOR_ROBOT_SECRET="your-robot-secret" export HARBOR_PULL_SECRET_NAME="harbor-secret"网络注意事项:本指南假设该脚本是从堡垒节点运行的,该节点可以访问 GDC 网闸隔离配置 API,还可以访问互联网来下载所需的清单和容器映像。如果您是从无法访问互联网的机器运行此命令,则必须单独获取这些资源(例如,使用
docker save从已联网的机器导出图片,并使用docker load导入这些图片),然后安全地将它们上传到您的环境中,才能继续操作。
配置 kubectl 别名
在本部分中,您将为 GDC 的区域管理和全局 API 创建便捷的命令行别名:
为区域管理 API 创建别名(将 MANAGEMENT_API_KUBECONFIG 替换为管理 API 的 kubeconfig 的路径):
alias km="kubectl --kubeconfig MANAGEMENT_API_KUBECONFIG"为全局 API 创建别名(将 GLOBAL_API_KUBECONFIG 替换为全局 API 的 kubeconfig 路径):
alias kg="kubectl --kubeconfig GLOBAL_API_KUBECONFIG"
创建 GDC 标准集群
在本部分中,您将在 GDC 中部署标准 Kubernetes 集群,并配置 GDC 标准集群管理员角色和本地 Harbor 容器注册表凭据:
1 运行以下命令,确定可用的虚拟机映像类型:
```shell
gdcloud compute machine-types list
```
2 为集群工作器节点选择合适的机器类型:
```shell
export MACHINE_TYPE="n3-standard-8-gdc"
```
3 使用可用区级管理 API 创建具有两个工作器节点的标准集群:
```shell
km create -f - <<EOF
apiVersion: cluster.gdc.goog/v1
kind: Cluster
metadata:
name: ${GDC_CLUSTER_NAME}
namespace: ${GDC_PROJECT_ID}
spec:
nodePools:
- machineTypeName: ${MACHINE_TYPE}
nodeCount: 2
name: ${GDC_CLUSTER_NAME}-node-pool
EOF
```
This creates a simple GDC cluster. Cluster creation
can take up to 60 minutes to complete. To check the status, use the
following command:
```shell
km get clusters/${GDC_CLUSTER_NAME} \
-n ${GDC_PROJECT_ID} \
--watch
```
After the cluster is ready, the output should show a STATE of `Running`.
4 集群准备就绪后,检索其凭据:
```shell
KUBECONFIG=kubeconfig-${GDC_CLUSTER_NAME}.yaml gdcloud clusters \
get-credentials ${GDC_CLUSTER_NAME} \
--standard \
--project ${GDC_PROJECT_ID} \
--zone ${GDC_ZONE}
```
5 为 GDC 用户分配 GDC 标准集群管理员角色:
```shell
gdcloud projects add-iam-policy-binding ${GDC_PROJECT_ID} \
--member="user:${GDC_USER_NAME}" \
--role=cluster-admin
gdcloud projects add-iam-policy-binding ${GDC_PROJECT_ID} \
--member="user:${GDC_USER_NAME}" \
--role=standard-cluster-admin
```
6 在 GDC 中创建 Harbor 实例和 Harbor 项目,以托管镜像容器映像:
```shell
gdcloud projects add-iam-policy-binding ${GDC_PROJECT_ID} \
--member="user:${GDC_USER_NAME}" \
--role=harbor-instance-admin
```
7 创建 Harbor Robot 账号并记录其用户名和密钥。
8 使用您的 Harbor 实例进行身份验证:
```shell
docker --config=./docker-harbor login ${HARBOR_INSTANCE_URL} \
-u ${HARBOR_ROBOT_ACCOUNT} \
-p ${HARBOR_ROBOT_SECRET}
```
This saves the robot account credentials to
`./docker-harbor/config.json` for subsequent Secret creation.
基础架构和网络配置
在本部分中,您将配置底层 GDC 基础架构和网络设置。这样可确保 Kubernetes 工作负载能够解析外部 EJBCA 主机域名,并成功将出站 API 调用路由到其 IP 地址。
GDC 网闸隔离配置中的专用 DNS 设置
为了建立网域解析,您需要部署专用 DNS 区域和记录集,以将外部 EJBCA 服务器映射到本地网域名称,从而允许 GDC 内的服务使用稳定的主机名(而不是原始 IP 地址)进行连接:
为用户分配“受管 DNS 项目管理员”角色:
gdcloud projects add-iam-policy-binding ${GDC_PROJECT_ID} \ --member=user:${GDC_USER_NAME} \ --role=managed-dns-project-admin部署全局
ManagedDNSZone资源:kubectl --kubeconfig GLOBAL_API_KUBECONFIG apply -f - <<EOF apiVersion: networking.global.gdc.goog/v1 kind: ManagedDNSZone metadata: name: private-example-internal namespace: ${GDC_PROJECT_ID} spec: dnsName: ${EJBCA_DNS_ZONE} visibility: PRIVATE EOF部署指向 EJBCA 设备 IP 地址的
ResourceRecordSet:kubectl --kubeconfig GLOBAL_API_KUBECONFIG apply -f - <<EOF apiVersion: networking.global.gdc.goog/v1 kind: ResourceRecordSet metadata: name: ${EJBCA_HOSTNAME} namespace: ${GDC_PROJECT_ID} spec: name: ${EJBCA_HOSTNAME} ttlSeconds: 600 type: A rrData: - ${EJBCA_LB_IP} dnsZone: private-example-internal EOF
出站 NAT 网关设置
接下来,您可以通过设置自定义子网和 NAT 网关来配置 GDC 出站流量网络,以允许 Kubernetes 工作负载(例如 cert-manager 和注册机构客户端)安全地将出站流量路由到 EJBCA 服务器:
分配项目级和组织级网络开发者角色:
gdcloud projects add-iam-policy-binding ${GDC_PROJECT_ID} \ --member=user:${GDC_USER_NAME} \ --role=cloud-nat-developer gdcloud projects add-iam-policy-binding ${GDC_PROJECT_ID} \ --member=user:${GDC_USER_NAME} \ --role=subnet-project-admin gdcloud organizations add-iam-policy-binding ${GDC_ORG} \ --member="user:${GDC_USER_NAME}" \ --role=subnet-org-admin创建出站子网:
kubectl --kubeconfig MANAGEMENT_API_KUBECONFIG apply -f - <<EOF apiVersion: ipam.gdc.goog/v1 kind: Subnet metadata: name: ejbca-cluster-egress namespace: ${GDC_PROJECT_ID} spec: ipv4Request: prefixLength: 32 parentReference: name: data-network-segment-${GDC_ZONE}-group namespace: platform type: SubnetGroup type: Leaf EOF创建与 cert-manager 颁发者选择器匹配的
CloudNATGateway:kubectl --kubeconfig MANAGEMENT_API_KUBECONFIG apply -f - <<EOF apiVersion: networking.gdc.goog/v1 kind: CloudNATGateway metadata: name: ejbca-egress-gateway namespace: ${GDC_PROJECT_ID} spec: subnetRefs: - ejbca-cluster-egress workloadSelector: labelSelector: clusters: matchLabels: kubernetes.io/metadata.name: ${GDC_CLUSTER_NAME} workloads: matchLabels: app.kubernetes.io/name: ejbca-cert-manager-issuer EOF
Kubernetes cert-manager 集成
在本部分中,您将自定义 EJBCA cert-manager 颁发者与 GDC 的 cert-manager 服务集成。这样一来,您就可以为容器化服务建立自动证书配置、续订和生命周期管理。

为签发者配置 EJBCA
如需集成签发者,您需要在 EJBCA 服务器内配置必要的配置文件、注册管理客户端凭据,并设置角色绑定。这样一来,便可建立一个安全的管理渠道,让 cert-manager 能够向 EJBCA 进行身份验证并从中请求证书。
创建管理员证书配置文件
首先,在 EJBCA 中建立证书配置文件,以定义管理证书的技术属性和加密限制(例如算法和有效期):
- 打开 EJBCA 管理界面,依次前往 CA Functions > Certificate Profiles。
- 克隆 ENDUSER 配置文件并将其命名为
GDC ADMIN PROFILE。 - 修改
GDC ADMIN PROFILE并配置以下设置:- 可用的密钥算法:RSA
- 可用的位长度:2048、3072、4096
- 签名算法:SHA512WithRSA
- 有效性:
200d - 发卡机构备用名称:清除 使用
- CRL 分发点:选中使用
- 使用 CA 定义的 CRL 分发点:选中使用
- 授权信息访问:检查使用情况
- 使用 CA 定义的 OCSP 定位器:选中使用
- 使用 CA 定义的 CA 颁发者:选中使用
- 可用的 CA:选择
GDC Subordinate CA
- 点击保存。
创建管理员最终实体个人资料
接下来,您需要在 EJBCA 中创建一个最终实体配置文件,以定义默认字段和 CA 分配,从而简化注册和颁发管理证书的过程:
- 依次前往 RA Functions > End Entity Profiles。
- 在添加最终实体配置文件下,输入
GDC ADMIN EE PROFILE,然后点击添加配置文件。 - 修改配置文件并配置以下设置:
- 默认证书配置文件:
GDC ADMIN PROFILE - 可用的证书配置文件:
GDC ADMIN PROFILE - 默认 CA:
GDC Subordinate CA - 可用的 CA:
GDC Subordinate CA
- 默认证书配置文件:
- 点击保存。
注册管理员证书
在建立配置文件后,您可以使用 EJBCA 注册机构 (RA) 接口注册管理身份,并提取私钥、公共证书和信任链,以生成对 cert-manager 进行身份验证所需的实体凭据文件:
- 前往 RA Web 标签页。
- 点击提交新请求,然后配置:
- 证书类型:
GDC ADMIN EE PROFILE - 密钥对生成:由 CA 完成
- 密钥算法:RSA 4096 位
- 通用名称 (CN):
cert-manager - 用户名:
cert-manager - 注册代码:
abcd
- 证书类型:
- 点击下载 PEM,然后将其另存为
cert-manager.pem。 将 PEM 文件拆分为三个文件:
client.key(密钥):openssl pkey -in cert-manager.pem -out client.keyclient.crt(公开证书):openssl x509 -in cert-manager.pem -out client.crtca.crt(包含从属 CA 证书和根 CA 证书的信任链):awk '/BEGIN CERTIFICATE/{i++} i>1' cert-manager.pem > ca.crt
配置角色和访问权限规则
最后,您在 EJBCA 中创建一个管理角色,并将其绑定到 cert-manager 证书序列号,以确保签发者仅拥有批准和请求证书所需的最低权限集:
- 在 EJBCA 管理界面中,依次前往 RA Functions > Search End Entities。
- 搜索
cert-manager最终实体,并记录其证书序列号。 - 依次前往系统功能 > 角色和访问权限规则,然后点击添加。
- 将该角色命名为
cert-manager,然后使用您记录的序列号添加新成员。 - 点击修改访问权限规则,然后配置以下权限:
- 角色模板:RA 管理员
- 已获授权的 CA:
GDC Subordinate CA - 最终实体规则:批准、创建和修改最终实体
- 最终实体配置文件:
GDC TLS SERVER EE PROFILE - 其他规则:清除查看审核日志
- 点击保存。
准备 GDC 集群
为了准备 GDC 环境,您需要使用标准 Kubernetes 集群进行身份验证,并将提取的 EJBCA 管理凭据存储在 Kubernetes Secret 中,以便 cert-manager 签发者 Pod 可以安全地访问这些凭据:
检索标准集群凭据:
gdcloud clusters get-credentials "${GDC_CLUSTER_NAME}" \ --standard \ --project "${GDC_PROJECT_ID}" \ --zone "${GDC_ZONE}"为自定义签发者创建目标命名空间:
kubectl create ns ejbca-issuer-system部署 TLS 身份验证 Secret:
kubectl create secret tls ejbca-secret \ -n ejbca-issuer-system \ --cert=client.crt \ --key=client.key部署 EJBCA 信任链 Secret:
kubectl create secret generic ejbca-ca-secret \ -n ejbca-issuer-system \ --from-file=ca.crt
安装 EJBCA 颁发者
如需配置部署,请将 EJBCA cert-manager 签发者容器映像镜像到您的私有 Harbor 注册表中,然后部署 Helm 图表。此命令会实例化将 Kubernetes 证书请求转换为 EJBCA API 调用所需的自定义控制器:
在签发者的命名空间中创建 Harbor 映像拉取 Secret:
# Authenticate with the private Harbor registry docker --config=./docker-harbor login ${HARBOR_INSTANCE_URL} \ -u ${HARBOR_ROBOT_ACCOUNT} \ -p ${HARBOR_ROBOT_SECRET} kubectl create secret docker-registry ${HARBOR_PULL_SECRET_NAME} \ --from-file=.dockerconfigjson=./docker-harbor/config.json \ -n ejbca-issuer-system将官方 EJBCA cert-manager 签发者映像镜像到 Harbor:
docker pull keyfactor/ejbca-cert-manager-issuer:latest --platform linux/amd64 docker tag keyfactor/ejbca-cert-manager-issuer:latest \ ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/ejbca-cert-manager-issuer:latest docker --config=./docker-harbor push \ ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/ejbca-cert-manager-issuer:latest添加 Helm 代码库并下载图表:
helm repo add ejbca-issuer https://keyfactor.github.io/ejbca-cert-manager-issuer helm repo update helm pull ejbca-issuer/ejbca-cert-manager-issuer --untar使用镜像映像代码库部署 Helm 图表:
helm install ejbca-cert-manager-issuer ./ejbca-cert-manager-issuer \ --namespace ejbca-issuer-system \ --set image.repository=${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/ejbca-cert-manager-issuer \ --set "imagePullSecrets[0].name=${HARBOR_PULL_SECRET_NAME}" \ --set image.tag=latest
创建提供方资源
接下来,您将建立 GDC RBAC 权限并部署全局 ClusterIssuer 资源,该资源会将 EJBCA 服务器注册为 Kubernetes cert-manager 框架内的可信签名源:
配置 RBAC 权限,以允许 GDC 的 cert-manager 控制器使用自定义 EJBCA 签发者:
kubectl apply -f - <<EOF apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: cert-manager-controller-approve:issuers-ejbca-issuer-keyfactor-com rules: - verbs: - approve apiGroups: - cert-manager.io resources: - signers resourceNames: - issuers.ejbca-issuer.keyfactor.com/* - clusterissuers.ejbca-issuer.keyfactor.com/* --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: cert-manager-controller-approve:issuers-ejbca-issuer-keyfactor-com subjects: - kind: ServiceAccount name: cert-manager namespace: cert-manager roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cert-manager-controller-approve:issuers-ejbca-issuer-keyfactor-com EOF部署全局
ClusterIssuer资源:kubectl apply -f - <<EOF apiVersion: ejbca-issuer.keyfactor.com/v1alpha1 kind: ClusterIssuer metadata: name: clusterissuer-ejbca spec: hostname: "${EJBCA_HOSTNAME}" ejbcaSecretName: "ejbca-secret" caBundleSecretName: "ejbca-ca-secret" certificateAuthorityName: "${EJBCA_CA_NAME}" certificateProfileName: "${CERTIFICATE_PROFILE_NAME}" endEntityProfileName: "${END_ENTITY_PROFILE_NAME}" endEntityName: "" EOF验证签发者的状态:
kubectl get clusterissuer.ejbca-issuer.keyfactor.com/clusterissuer-ejbca \ -o "custom-columns=NAME:.metadata.name,STATUS:.status.conditions[0].message"输出应如下所示:
NAME STATUS clusterissuer-ejbca Success
请求证书
如需验证集成,您可以部署标准 Kubernetes 证书资源,以测试端到端 cert-manager 流程,并确认 EJBCA 是否成功签名并预配所请求的证书:
创建测试 Certificate 资源以验证集成是否成功:
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: ejbca-test-certificate
namespace: ${EJBCA_NAMESPACE}
spec:
commonName: example.com
secretName: ejbca-certificate
issuerRef:
name: clusterissuer-ejbca
group: ejbca-issuer.keyfactor.com
kind: ClusterIssuer
EOF
验证证书是否已创建并准备就绪:
kubectl get certificates.cert-manager.io -n ${EJBCA_NAMESPACE}
输出应如下所示:
NAME READY SECRET AGE
ejbca-test-certificate True ejbca-certificate 12s
通过 DNS-01 验证自动执行 ACME
在本部分中,您将配置 EJBCA 的 ACME 服务,并利用 GDC 内部 DNS 资源自动执行网域验证证书颁发。这样一来,标准 cert-manager 或 Certbot 客户端便可使用标准自动化 ACME 协议请求证书。
为 ACME 配置 EJBCA
为准备服务器,您需要在 EJBCA 中启用 ACME 服务,并配置具有专用 DNS 解析器的 ACME 别名。这会准备 EJBCA 服务器,以便在 GDC 中处理和验证 DNS-01 质询响应:
- 在 EJBCA 管理界面中,依次前往系统配置 > ACME 配置。
- 点击添加,然后配置以下内容:
- 名称:
default - 最终实体配置文件:
GDC TLS SERVER EE PROFILE - 允许颁发通配符证书:选中
- 挑战响应 MPIC 验证 DNS 标识符挑战类型:选择
dns-01 - DNS 解析器:输入全局 DNS 的 IP。
- 验证 DNSSEC:通过(因为这是本地专用环境)
- 名称:
- 点击保存。
创建 ACME 环境变量
在本部分中,您将创建以下环境变量来配置 Certbot 客户端。根据需要修改这些值:
# ACME Alias created in the EJBCA configuration
export ACME_ALIAS="default"
# Arbitrary email address used for ACME registration
export ACME_EMAIL="your-email@example.com"
注册 Certbot 客户端
接下来,您需要安装标准 Certbot 客户端,并将其注册到 EJBCA 的私有 ACME 端点。这会建立执行自动化证书操作所需的受信任的客户账号:
在工作站上安装
certbot。例如,对于 macOS:brew install certbot创建用于存储配置和日志的本地文件夹:
mkdir -p ./certbot/config ./certbot/work ./certbot/logs向 EJBCA ACME 目录端点注册客户端:
certbot register \ --config-dir ./certbot/config \ --work-dir ./certbot/work \ --logs-dir ./certbot/logs \ --server https://${EJBCA_HOSTNAME}/ejbca/acme/${ACME_ALIAS}/directory \ --email ${ACME_EMAIL} \ --agree-tos \ --no-eff-email
使用 DNS 质询颁发证书
最后,您执行手动 Certbot 请求并部署临时 GDC DNS TXT 资源,以解决 DNS-01 质询。这会验证您对目标网域的所有权,并触发自动证书颁发:
运行手动验证命令:
certbot certonly \ --manual \ --preferred-challenges dns \ --key-type rsa \ --rsa-key-size 2048 \ --config-dir ./certbot/config \ --work-dir ./certbot/work \ --logs-dir ./certbot/logs \ --server https://${EJBCA_HOSTNAME}/ejbca/acme/${ACME_ALIAS}/directory \ -d test.${EJBCA_DNS_ZONE}终端将停止并显示质询值。输出示例:
Please deploy a DNS TXT record under the name: _acme-challenge.test.example.internal. with the following value: q3pCmzXfIhsTpT4f4JAulHmHaAR3udC_9Wf1G498ER0 Before continuing, verify the TXT record has been deployed.使用 Certbot 提供的字符串将 TXT 记录部署到您的全局 DNS。
等待大约 30 秒,让 DNS 传播完毕,然后返回 Certbot 终端,并按 Enter 键。
输出示例:
Successfully received certificate. Certificate is saved at:./certbot/config/live/test.example.internal/fullchain.pem Key is saved at:./certbot/config/live/test.example.internal/privkey.pem This certificate expires on 2026-11-16. These files will be updated when the certificate renews.验证证书是否已成功写入
./certbot/config/live/test.${EJBCA_DNS_ZONE}/。