使用 Certificate Authority Service 自动管理 Cloud Service Mesh 入站流量网关的 TLS 证书
本教程介绍平台运营商如何使用 cert-manager 工具的 Certificate Authority Service (CA Service) 颁发者自动管理 Cloud Service Mesh 入站流量网关的 TLS 证书。通过这些证书,入站流量网关可终止源自 Virtual Private Cloud (VPC) 中但服务网格之外的客户端的 HTTPS 以及其他 TLS 和 mTLS 流量。本教程假定您对 Kubernetes 和 TLS 证书有基本的了解。
简介
Cloud Service Mesh 会为服务网格中的每个工作负载预配 TLS 证书。这些证书会在服务网格中的工作负载之间实现加密和双向身份验证的 TLS (mTLS) 通信。其中一个受支持的 CA 会颁发证书并为证书签名。
但是,对于进入服务网格的流量,Cloud Service Mesh 不会自动向入站流量网关预配证书。一种常见的解决方案是使用开源 cert-manager 工具自动管理入站流量网关证书。
cert-manager 工具会向代表证书授权机构 (CA) 的颁发者请求证书。CA Service 是一项 Google Cloud 服务,可让您创建自己的专用 CA。cert-manager 工具可以使用 CA Service 的开源外部颁发者向 CA Service 请求证书。
私有 CA 可以颁发 TLS 证书,对内部网络的流量进行身份验证和加密。Cloud Service Mesh 入站流量网关通常设置为允许来自 VPC 内部但位于服务网格外部的客户端的传入流量。对于内部网络流量,您可以使用 CA Service 中的私有 CA 为入站流量网关颁发证书。
本教程介绍如何设置 cert-manager 工具和 CA Service 颁发者,以自动为入站流量网关预配和续订 TLS 证书。cert-manager 工具会将证书预配为 TLS 类型的 Kubernetes Secret 资源。当 cert-manager 工具续订证书时,它会使用新证书更新 Secret 资源。入站流量网关运行 Envoy 代理,并且支持 Envoy 的 Secret 发现服务 (SDS)。SDS 允许入站流量网关开始使用新证书,而无需管理员重启或重新加载该进程。
属于网格的边车代理可以从 CA Service 或 Cloud Service Mesh 证书授权机构获取 TLS 证书。在本教程中,您要将 CA Service 用于边车代理和入站流量网关证书。这样,您就可以对所有 TLS 证书使用一个根 CA。
下图显示了您在本教程中预配的资源。您可以为入站流量网关预配内部直通网络负载均衡器。内部直通网络负载均衡器不是代理,因此不会终止 TCP 连接或执行 TLS 握手,而是会将连接路由到 istio-ingressgateway
部署的 pod。
hello-example-com-credential
Secret 包含证书和私钥。hello
网关会对 istio-ingressgateway
部署的 pod 进行配置,使其使用此证书和私钥对具有主机名 hello.example.com
的请求执行 TLS 握手。
cert-manager
命名空间中 google-cas-issuer
部署的 pod 向您在 CA Service 中创建的 CA 请求证书。您可以创建 Identity and Access Management 政策绑定,以允许 ca-service-isser
pod 使用 适用于 GKE 的工作负载身份联合 模拟 Google 服务账号。您可以通过针对 CA 池创建 IAM 政策绑定,为此 Google 服务账号授予向 CA Service 中的 CA 请求证书的权限。
目标
- 配置 CA Service
- 创建 GKE 集群
- 安装 Cloud Service Mesh 控制平面
- 安装入站流量网关
- 安装 cert-manager 工具
- 安装 CA Service 颁发者控制器
- 创建证书颁发者
- 部署一个示例应用
- 验证解决方案
- (可选)向信任库中添加 CA 证书
费用
本教程使用 Google Cloud 的以下收费组件:
如需根据您的预计使用量来估算费用,请使用价格计算器。Google Cloud 新用户可能有资格申请免费试用。
完成本教程后,您可以通过删除您创建的资源来避免继续计费。如需了解详情,请参阅清理。
准备工作
在 Google Cloud 控制台中,转到项目选择器页面,然后选择或创建一个项目。
在 Google Cloud 控制台中,转到 Cloud Shell。
Cloud Shell 会话随即会在 Google Cloud 控制台底部打开,并显示命令行提示符。您可以使用 Cloud Shell 运行本教程中的所有命令。
设置您要在本教程中使用的 Google Cloud 控制台项目:
gcloud config set core/project PROJECT_ID
将 PROJECT_ID 替换为您的 Cloud 项目 ID。
在“为 Cloud Shell 提供授权”对话框中,点击授权。点击授权,即表示您允许在 Cloud Shell 中运行的
gcloud
命令使用您的用户凭据来向 Google API 进行身份验证。启用 Resource Manager、GKE、GKE Hub、Cloud Service Mesh 证书授权机构和 CA Service API:
gcloud services enable \ cloudresourcemanager.googleapis.com \ container.googleapis.com \ gkehub.googleapis.com \ meshca.googleapis.com \ privateca.googleapis.com
配置 CA Service
在本部分中,您将在 CA Service 中创建一个根 CA 和两个从属 CA。一个从属 CA 用于向入站流量网关颁发证书,另一个从属 CA 用于向网格中的边车代理颁发证书。
为简单起见,在本教程中,您为 GKE 集群以及根 CA 和从属 CA 使用同一个项目。在您自己的环境中,您可以为 GKE 集群和 CA 使用其他项目。
在 Cloud Shell 中,创建用于根 CA 的 CA 池:
gcloud privateca pools create ROOT_CA_POOL \ --location CA_LOCATION \ --tier enterprise
- ROOT_CA_POOL 是 CA 池的名称。例如
root-ca-pool-tutorial
。 - CA_LOCATION 是 CA 池的位置。例如
us-central1
。
您可以使用以下命令列出可用的 CA Service 位置:
gcloud privateca locations list
- ROOT_CA_POOL 是 CA 池的名称。例如
创建和启用根 CA:
gcloud privateca roots create ROOT_CA \ --auto-enable \ --key-algorithm ec-p384-sha384 \ --location CA_LOCATION \ --pool ROOT_CA_POOL \ --subject "CN=Example Root CA, O=Example Organization" \ --use-preset-profile root_unconstrained
- ROOT_CA 是您要用于根 CA 的名称。例如
root-ca-tutorial
。
- ROOT_CA 是您要用于根 CA 的名称。例如
创建 CA 池,以用于向入站流量网关颁发证书的从属 CA:
gcloud privateca pools create SUBORDINATE_CA_POOL_GATEWAYS \ --location CA_LOCATION \ --tier devops
- SUBORDINATE_CA_POOL_GATEWAYS 是 CA 池的名称。例如
subordinate-ca-mtls-pool-gateways-tutorial
。
- SUBORDINATE_CA_POOL_GATEWAYS 是 CA 池的名称。例如
创建和启用向入站流量网关颁发证书的从属 CA:
gcloud privateca subordinates create SUBORDINATE_CA_GATEWAYS \ --auto-enable \ --issuer-location CA_LOCATION \ --issuer-pool ROOT_CA_POOL \ --key-algorithm ec-p256-sha256 \ --location CA_LOCATION \ --pool SUBORDINATE_CA_POOL_GATEWAYS \ --subject "CN=Example Gateway mTLS CA, O=Example Organization" \ --use-preset-profile subordinate_mtls_pathlen_0
- SUBORDINATE_CA_GATEWAYS 是您要用于从属 CA 的名称。例如
subordinate-ca-mtls-gateways-tutorial
。 --use-preset-profile
标志将从属 CA 配置为使用从属 mTLS 证书配置文件。此配置文件使从属 CA 能够为 mTLS 颁发客户端和服务器 TLS 证书。
如果您希望入站流量网关使用简单 TLS 而不是 mTLS,则从属 CA 只需要颁发服务器 TLS 证书。在这种情况下,您可以改用从属服务器 TLS (
subordinate_server_tls_pathlen_0
) 证书配置文件。- SUBORDINATE_CA_GATEWAYS 是您要用于从属 CA 的名称。例如
创建证书颁发政策:
cat << EOF > policy.yaml baselineValues: keyUsage: baseKeyUsage: digitalSignature: true keyEncipherment: true extendedKeyUsage: serverAuth: true clientAuth: true caOptions: isCa: false identityConstraints: allowSubjectPassthrough: false allowSubjectAltNamesPassthrough: true celExpression: expression: subject_alt_names.all(san, san.type == URI && san.value.startsWith("spiffe://PROJECT_ID.svc.id.goog/ns/") ) EOF
此颁发政策将 CA 限制为只能为网格中的工作负载颁发证书。
创建 CA 池,以用于向网格中的边车代理颁发证书的从属 CA。将发布政策应用于 CA 池:
gcloud privateca pools create SUBORDINATE_CA_POOL_SIDECARS \ --issuance-policy policy.yaml \ --location CA_LOCATION \ --tier devops
- SUBORDINATE_CA_POOL_SIDECARS 是 CA 池的名称。例如
subordinate-ca-mtls-pool-sidecars-tutorial
。
- SUBORDINATE_CA_POOL_SIDECARS 是 CA 池的名称。例如
创建和启用向网格中的边车代理颁发证书的从属 CA:
gcloud privateca subordinates create SUBORDINATE_CA_SIDECARS \ --auto-enable \ --issuer-location CA_LOCATION \ --issuer-pool ROOT_CA_POOL \ --key-algorithm ec-p256-sha256 \ --location CA_LOCATION \ --pool SUBORDINATE_CA_POOL_SIDECARS \ --subject "CN=Example Sidecar mTLS CA, O=Example Organization" \ --use-preset-profile subordinate_mtls_pathlen_0
- SUBORDINATE_CA_GATEWAYS 是您要用于从属 CA 的名称。例如
subordinate-ca-mtls-sidecars-tutorial
。
- SUBORDINATE_CA_GATEWAYS 是您要用于从属 CA 的名称。例如
创建一个 Google Kubernetes Engine 集群
在 Cloud Shell 中创建一个 GKE 集群:
gcloud container clusters create CLUSTER_NAME \ --enable-ip-alias \ --num-nodes 4 \ --release-channel regular \ --scopes cloud-platform \ --workload-pool PROJECT_ID.svc.id.goog \ --zone ZONE
将 CLUSTER_NAME 替换为您要用于集群的名称。例如
asm-ingress-cert-manager-ca-service
。将 ZONE 替换为您要用于集群的可用区。例如
us-central1-f
。对于该命令,请注意以下事项:
向您的用户账号授予集群管理员权限:
kubectl create clusterrolebinding cluster-admin-binding \ --clusterrole cluster-admin \ --user $(gcloud config get-value core/account)
您需要 Kubernetes
cluster-admin
ClusterRole 提供的权限才能为 Cloud Service Mesh 创建基于角色的访问权限控制 (RBAC) 规则,并安装 cert-manager 工具。
安装 Anthos Service Mesh 控制平面
在本教程中,您将为 Google Cloud 上的 GKE 集群安装托管式 Cloud Service Mesh,并将所有资源都保存在一个项目中。在您自己的环境中,您可以使用代管式 Cloud Service Mesh 或集群内控制平面来应用本文档中所述的解决方案。
Cloud Service Mesh 提供了适用于不同场景的一系列安装选项。完成本教程后,我们建议您查看安装指南,以选择最适合您的环境的选项。
在 Cloud Shell 中,下载
asmcli
安装工具:curl --location --output asmcli https://storage.googleapis.com/csm-artifacts/asm/asmcli_1.23 chmod +x asmcli
您可以使用
asmcli
安装 Cloud Service Mesh 控制平面。安装 Cloud Service Mesh 控制平面:
./asmcli install \ --ca gcp_cas \ --ca_pool projects/PROJECT_ID/locations/CA_LOCATION/caPools/SUBORDINATE_CA_POOL_SIDECARS \ --cluster_location ZONE \ --cluster_name CLUSTER_NAME \ --enable_all \ --enable_registration \ --fleet_id PROJECT_ID \ --managed \ --output_dir asm-files \ --project_id PROJECT_ID \ --verbose
--ca gcp_cas
和--ca_pool
标志用于将 Cloud Service Mesh 控制平面配置为使用 CA Service 中的边车 CA 池向网格中的边车代理颁发证书。--enable_registration
标志用于将 GKE 集群到项目中由--fleet_id
标志指定的舰队中。在本教程中,GKE 集群和舰队使用的是同一个项目。--managed
标志用于设置代管式 Cloud Service Mesh 控制平面。--output_dir
标志指定asmcli
用于下载安装 Cloud Service Mesh 所需的文件和配置的目录。在本教程的后面部分,您将使用这些文件。
安装需要几分钟时间。安装完成后,您会看到以下输出:
asmcli: Successfully installed ASM.
安装入站流量网关
在 Cloud Shell 中,为入站流量网关创建 Kubernetes 命名空间:
kubectl create namespace GATEWAY_NAMESPACE
- GATEWAY_NAMESPACE 是您要用于入站流量网关的命名空间的名称。例如
istio-ingress
。
- GATEWAY_NAMESPACE 是您要用于入站流量网关的命名空间的名称。例如
保留要用于入站流量网关内部直通网络负载均衡器的静态内部 IP 地址:
LOAD_BALANCER_IP=$(gcloud compute addresses create \ asm-ingress-gateway-ilb \ --region REGION \ --subnet default \ --format 'value(address)')
- 将 REGION 替换为包含 GKE 集群节点使用的一个或多个可用区的地区。例如,如果您的集群使用
us-central1-f
可用区,请将 REGION 替换为us-central1
。
此命令会保留您指定的地区内默认子网中的 IP 地址。
- 将 REGION 替换为包含 GKE 集群节点使用的一个或多个可用区的地区。例如,如果您的集群使用
为入站流量网关创建 Operator 清单:
cat << EOF > ingressgateway-operator.yaml apiVersion: install.istio.io/v1alpha1 kind: IstioOperator metadata: name: ingressgateway-operator annotations: config.kubernetes.io/local-config: "true" spec: profile: empty revision: asm-managed components: ingressGateways: - name: istio-ingressgateway namespace: GATEWAY_NAMESPACE enabled: true k8s: overlays: - apiVersion: apps/v1 kind: Deployment name: istio-ingressgateway patches: - path: spec.template.metadata.annotations value: inject.istio.io/templates: gateway - path: spec.template.metadata.labels.sidecar\.istio\.io/inject value: "true" - path: spec.template.spec.containers[name:istio-proxy] value: name: istio-proxy image: auto service: loadBalancerIP: $LOAD_BALANCER_IP serviceAnnotations: networking.gke.io/load-balancer-type: Internal networking.gke.io/internal-load-balancer-allow-global-access: "true" EOF
对于 Operator 清单,请注意以下事项:
revision
字段指定用于数据平面的代管式 Cloud Service Mesh 发布渠道。如果您使用控制平面的快速或稳定的发布渠道,请更改此字段的值。overlays
部分中指定的annotation
、label
和image
启用为入站流量网关部署自动注入代理配置。loadBalancerIP
字段指定负载均衡器使用的 IP 地址。如果您从清单中移除此字段,则负载均衡器将使用临时 IP 地址。针对入站流量网关的服务注解
networking.gke.io/load-balancer-type: Internal
意味着 GKE 在入站流量网关 Pod 前端预配了内部直通网络负载均衡器。如果您移除此注解,则 GKE 会改为预配外部直通网络负载均衡器。可选的服务注解
networking.gke.io/internal-load-balancer-allow-global-access: "true"
允许 VPC 中任何区域的客户端访问内部直通网络负载均衡器。如果您移除此注解,则内部直通网络负载均衡器仅接受来自 VPC 中同一区域内的客户端的流量。
使用 Operator 清单以及安装控制平面时
asmcli
脚本下载的istioctl
工具创建入站流量网关安装清单:./asm-files/istioctl manifest generate \ --filename ingressgateway-operator.yaml \ --output ingressgateway
安装入站流量网关:
kubectl apply --recursive --filename ingressgateway/
安装 cert-manager 工具
在 Cloud Shell 中,下载并应用 cert-manager 工具安装清单:
CERT_MANAGER_VERSION=v1.5.4 curl --location --output cert-manager.yaml "https://github.com/jetstack/cert-manager/releases/download/${CERT_MANAGER_VERSION}/cert-manager.yaml" kubectl apply --filename cert-manager.yaml
安装 cert-manager 工具大约需要一分钟的时间。
安装 CA Service 颁发者控制器
CA Service 颁发者控制器支持 cert-manager 工具使用 CA Service 请求证书。控制器使用 cert-manager 工具外部颁发者扩展程序机制。
在 Cloud Shell 中,创建一个 Google 服务账号:
gcloud iam service-accounts create CAS_ISSUER_GSA \ --display-name "CA Service issuer for cert-manager"
- CAS_ISSUER_GSA 是 Google 服务账号的名称。例如
cert-manager-ca-service-issuer
。
Certificate Authority Service 颁发者控制器使用此 Google 服务账号向 Certificate Authority Service API 进行身份验证。
- CAS_ISSUER_GSA 是 Google 服务账号的名称。例如
创建 Identity and Access Management 政策绑定,以允许 Certificate Authority Service 颁发者控制器 Google 服务账号从包含从属 CA 的 CA 池请求证书:
gcloud privateca pools add-iam-policy-binding SUBORDINATE_CA_POOL_GATEWAYS \ --location CA_LOCATION \ --member "serviceAccount:CAS_ISSUER_GSA@PROJECT_ID.iam.gserviceaccount.com" \ --role roles/privateca.certificateRequester
下载 Certificate Authority Service 颁发者控制器安装清单:
CAS_ISSUER_VERSION=v0.5.3 curl --location --output ca-service-issuer.yaml "https://github.com/jetstack/google-cas-issuer/releases/download/${CAS_ISSUER_VERSION}/google-cas-issuer-${CAS_ISSUER_VERSION}.yaml"
创建 IAM 政策绑定,以允许
cert-manager
命名空间中的ksa-google-cas-issuer
Kubernetes 服务账号使用 适用于 GKE 的工作负载身份联合模拟 Google 服务账号 (GSA):gcloud iam service-accounts add-iam-policy-binding \ CAS_ISSUER_GSA@PROJECT_ID.iam.gserviceaccount.com \ --member "serviceAccount:PROJECT_ID.svc.id.goog[cert-manager/ksa-google-cas-issuer]" \ --role roles/iam.workloadIdentityUser
CA Service 颁发者控制器 pod 使用的是
ksa-google-cas-issuer
Kubernetes 服务账号。在 GKE 集群中安装 CA Service 颁发者控制器:
kubectl apply --filename ca-service-issuer.yaml
将适用于 GKE 的工作负载身份联合注解
iam.gke.io/gcp-service-account
添加到 CA Service 颁发者控制器 pod 使用的 Kubernetes 服务账号:kubectl annotate serviceaccount ksa-google-cas-issuer --namespace cert-manager \ "iam.gke.io/gcp-service-account=CAS_ISSUER_GSA@PROJECT_ID.iam.gserviceaccount.com"
此注释告知 GKE Kubernetes 服务账号可以模拟 Google 服务账号来访问 Google API。
创建证书颁发者
在 Cloud Shell 中,创建并应用 GoogleCASIssuer 清单:
cat << EOF > gateway-cas-issuer.yaml apiVersion: cas-issuer.jetstack.io/v1beta1 kind: GoogleCASIssuer metadata: name: gateway-cas-issuer namespace: GATEWAY_NAMESPACE spec: caPoolId: SUBORDINATE_CA_POOL_GATEWAYS location: CA_LOCATION project: PROJECT_ID EOF kubectl apply --filename gateway-cas-issuer.yaml
颁发者支持 cert-manager 工具从入站流量网关命名空间中的从属 CA 池预配证书
部署一个示例应用
在本部分中,您将验证 cert-manager 工具是否可以使用 CA Service 颁发者从 CA Service 获取证书。为了进行验证,您可以使用请求路由配置和入站流量网关的证书部署示例应用。
在 Cloud Shell 中,为示例应用资源创建命名空间:
cat << EOF > sample-app-namespace.yaml apiVersion: v1 kind: Namespace metadata: name: APP_NAMESPACE annotations: mesh.cloud.google.com/proxy: '{"managed":"true"}' labels: istio.io/rev: asm-managed EOF kubectl apply --filename sample-app-namespace.yaml
- APP_NAMESPACE 是示例应用的命名空间名称。例如
sample-app
。
mesh.cloud.google.com/proxy
注解用于为命名空间启用代管式数据平面。istio.io/rev: asm-managed
标签用于为示例应用命名空间中的代管式数据平面选择常规发布渠道。如果您使用快速或稳定的发布渠道,请更改此标签的值。- APP_NAMESPACE 是示例应用的命名空间名称。例如
为示例应用创建 Deployment 资源:
cat << EOF > deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: hello namespace: APP_NAMESPACE labels: app: hello spec: replicas: 1 selector: matchLabels: app: hello template: metadata: labels: app: hello spec: containers: - image: gcr.io/google-samples/hello-app:1.0 name: hello-app ports: - containerPort: 8080 EOF kubectl apply --filename deployment.yaml
为示例应用创建 Service 资源:
cat << EOF > service.yaml apiVersion: v1 kind: Service metadata: name: SERVICE_NAME namespace: APP_NAMESPACE spec: ports: - name: http-hello port: 8080 selector: app: hello type: ClusterIP EOF kubectl apply --filename service.yaml
- SERVICE_NAME 是服务的名称。例如
hello
。
- SERVICE_NAME 是服务的名称。例如
使用证书颁发者为域名
hello.example.com
创建证书资源:cat << EOF > certificate.yaml apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: hello-example-com-certificate namespace: GATEWAY_NAMESPACE spec: secretName: hello-example-com-credential commonName: hello.example.com dnsNames: - hello.example.com duration: 24h renewBefore: 8h issuerRef: group: cas-issuer.jetstack.io kind: GoogleCASIssuer name: gateway-cas-issuer EOF kubectl apply --filename certificate.yaml
证书命名空间必须与入站流量网关命名空间匹配。通常,只有平台管理员可以更改此命名空间中的资源,因为更改可能会影响整个服务网格。cert-manager 工具在同一命名空间中为 TLS 证书创建 Secret 资源。这意味着应用管理员无需拥有入站流量网关命名空间的访问权限。
您可以在证书的
dnsNames
列表中添加其他主机名。这些主机名会以主题备用名称 (SAN) 的形式包含在证书中。为示例应用创建网关资源:
cat << EOF > gateway.yaml apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: GATEWAY_NAME namespace: GATEWAY_NAMESPACE spec: selector: istio: ingressgateway servers: - hosts: - APP_NAMESPACE/hello.example.com port: name: https-hello number: 443 protocol: HTTPS tls: credentialName: hello-example-com-credential mode: MUTUAL EOF kubectl apply --filename gateway.yaml
- GATEWAY_NAME 是网关名称。例如
hello
。 - 网关中的
credentialName
字段与证书中的secretName
字段匹配。cert-manager 工具使用 CA Service 中的 TLS 证书创建 Kubernetes Secret。此证书可让入站流量网关终止流向hello.example.com
的 TLS 流量。
网关清单会指定 MUTUAL TLS (mTLS)。如果要为常规 TLS 配置网关,请将网关的 TLS 模式设置为
SIMPLE
。- GATEWAY_NAME 是网关名称。例如
为示例应用创建 VirtualService 资源:
cat << EOF > virtual-service.yaml apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: hello namespace: APP_NAMESPACE spec: hosts: - hello.example.com gateways: - GATEWAY_NAMESPACE/GATEWAY_NAME http: - route: - destination: host: SERVICE_NAME port: number: 8080 EOF kubectl apply --filename virtual-service.yaml
网关和 VirtualService 使用的是不同的命名空间。此常见模式会施加限制,只允许有权更改入站流量网关命名空间中的资源的平台管理员更改网关中基于主机的路由。
有权在示例应用命名空间中修改 VirtualService 的应用管理员可以通过其他请求字段(如网址路径)更改路由,而无需与平台管理员协调。
如果要浏览其他配置选项,请阅读证书、网关和 VirtualService 资源的相关 API 文档。
您可以对通过入站流量网关进入服务网格的流量应用身份验证和授权政策。为此,请阅读 Istio PeerAuthentication 和 AuthorizationPolicy API 的相关文档。
验证解决方案
在本部分中,您将验证是否可以使用 mTLS 从服务网格外部向示例应用发送 HTTPS 请求。如需进行验证,请创建一个 Compute Engine 虚拟机实例,向 CA Service 请求客户端 TLS 证书,然后使用此证书对向示例应用发出的请求进行身份验证。
您需要通过 SSH 访问虚拟机实例。默认网络包含允许通过 SSH 访问的防火墙规则。如果您没有通过 SSH 进行访问的权限,请按照防火墙规则文档创建防火墙规则,以允许在端口 22 上建立传入的 TCP 连接。
在 Cloud Shell 中,创建一个 Google 服务账号:
gcloud iam service-accounts create CLIENT_VM_GSA \ --display-name "CA Service tutorial VM instance service account"
- CLIENT_VM_GSA 是 Google 服务账号的名称。例如
cas-tutorial-client
。
您可以将此 Google 服务账号分配给 Compute Engine 虚拟机实例。
- CLIENT_VM_GSA 是 Google 服务账号的名称。例如
将网关从属 CA 池中的 CA Service Certificate Requester 角色授予 Google 服务账号:
gcloud privateca pools add-iam-policy-binding SUBORDINATE_CA_POOL_GATEWAYS \ --location CA_LOCATION \ --member "serviceAccount:CLIENT_VM_GSA@PROJECT_ID.iam.gserviceaccount.com" \ --role roles/privateca.certificateRequester
此角色提供从 CA 池请求证书的权限。
在 GKE 集群所在的同一 VPC 中创建 Compute Engine 虚拟机实例:
gcloud compute instances create cas-tutorial-client \ --scopes cloud-platform \ --service-account CLIENT_VM_GSA@PROJECT_ID.iam.gserviceaccount.com \ --zone ZONE
虚拟机实例需要
cloud-platform
范围才能访问 CA Service API。将入站流量网关内部直通网络负载均衡器的 IP 地址保存到文件中:
kubectl get services istio-ingressgateway \ --namespace GATEWAY_NAMESPACE \ --output jsonpath='{.status.loadBalancer.ingress[0].ip}' > ilb-ip.txt
将根 CA 的公钥证书保存到文件中:
gcloud privateca roots describe ROOT_CA \ --location CA_LOCATION \ --pool ROOT_CA_POOL \ --format 'value(pemCaCertificates)' > root-ca-cert.pem
将根 CA 证书和包含入站流量网关内部直通网络负载均衡器的 IP 地址的文件复制到虚拟机实例:
gcloud compute scp root-ca-cert.pem ilb-ip.txt cas-tutorial-client:~ \ --zone ZONE
使用 SSH 连接到虚拟机实例:
gcloud compute ssh cas-tutorial-client --zone ZONE
在 SSH 会话中运行本部分中的其余命令。
安装
ca-certificates
和coreutils
软件包,以及curl
、openssl
和jq
命令行工具:sudo apt-get update --yes sudo apt-get install --yes ca-certificates coreutils curl jq openssl
为客户端 TLS 证书创建密钥对:
openssl genrsa -out private-key.pem 2048 openssl rsa -in private-key.pem -pubout -out public-key.pem
查询元数据服务器,以获取关联到虚拟机实例的 Google 服务账号身份的电子邮件地址:
GSA_EMAIL=$(curl --silent --header "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/email)
创建在通过 Certificate Authority Service API 请求客户端 TLS 证书时用作请求正文的 JSON 文件:
cat << EOF > request.json { "config": { "publicKey": { "format": "PEM", "key": "$(base64 --wrap 0 public-key.pem)" }, "subjectConfig": { "subject": { "commonName": "$(hostname --short)", "organization": "Example Organization" }, "subjectAltName": { "dnsNames": [ "$(hostname --fqdn)" ], "emailAddresses": [ "$GSA_EMAIL" ] } }, "x509Config": { "caOptions": { "isCa": false }, "keyUsage": { "baseKeyUsage": { "digitalSignature": true, "keyEncipherment": true }, "extendedKeyUsage": { "clientAuth": true } } } }, "lifetime": "86400s" } EOF
如需详细了解配置部分中的字段,请参阅 CA Service API 文档中的
CertificateConfig
类型。从元数据服务器请求 OAuth 2.0 访问令牌:
TOKEN=$(curl --silent --header "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token | jq --raw-output ".access_token")
此访问令牌提供向关联到虚拟机实例的 Google 服务账号授予的权限。
通过 CA Service API 请求客户端 TLS 证书,并将响应正文存储在文件中:
curl --silent --request POST \ --header "Authorization: Bearer $TOKEN" \ --header "Content-Type: application/json" \ --data @request.json \ --output response.json \ "https://privateca.googleapis.com/v1/projects/PROJECT_ID/locations/CA_LOCATION/caPools/SUBORDINATE_CA_POOL_GATEWAYS/certificates"
该命令使用访问令牌对 API 请求进行身份验证。
将客户端证书和证书链保存到文件中:
jq --raw-output --join-output ".pemCertificate , .pemCertificateChain[]" response.json > client-cert-chain.pem
使用
curl
从虚拟机实例向示例应用发送 HTTPS 请求:curl --cert client-cert-chain.pem --key private-key.pem \ --cacert root-ca-cert.pem \ --resolve hello.example.com:443:$(cat ilb-ip.txt) \ --silent https://hello.example.com | head -n1
输出如下所示:
Hello, world!
此响应显示
curl
已成功使用 mTLS 发送 HTTPS 请求。示例应用使用您在终端输出中看到的消息进行了响应。curl
命令执行以下操作:--cert
和--key
标志指示curl
使用客户端 TLS 证书和私钥来对请求进行身份验证。客户端证书文件包含完整的证书链(从客户端证书到根 CA)。--cacert
标志指示curl
验证您在本教程中创建的根 CA 或其某个从属 CA 是否颁发了服务器证书。如果省略此标志,
curl
将尝试使用操作系统的默认 CA 软件包(例如 Debian 上ca-certificates
软件包)验证服务器证书。验证失败,因为默认 CA 软件包不包含您在本教程中创建的根 CA。--resolve
标志指示curl
使用内部直通网络负载均衡器 IP 地址作为在端口 443 上托管hello.example.com
的请求的目标。如果您省略此标志,则
curl
会尝试使用 DNS 来解析hello.example.com
主机名。DNS 解析失败,因为此主机名没有 DNS 条目。在您自己的环境中,我们建议您创建指向内部直通网络负载均衡器 IP 地址 (
$LOAD_BALANCER_IP
) 的 DNS A 记录。您可以按照有关管理记录的文档的说明,使用 Cloud DNS 创建此记录。--silent
标志禁止在终端输出中报告响应下载进度。该命令将 curl 输出传送到
head -n1
。结果是终端中的输出仅包含响应正文的第一行。
退出 SSH 会话:
exit
在本部分中,您直接通过 CA Service API 请求客户端 TLS 证书。如果客户端是单独的 Kubernetes 集群中其他服务网格的出站流量网关,您可以使用 cert-manager 工具和具有相同根 CA 的 Certificate Authority Service 颁发者来提供向出站流量网关提供客户端证书。
在其他情况下,您可以使用 Hashicorp Vault、Terraform 或 gcloud
等工具为服务网格外部的工作负载请求客户端 TLS 证书。如需了解详情,请参阅 CA Service 文档查看示例解决方案,并参阅 gcloud
文档了解 CA Service。
(可选)向信任库中添加 CA 证书
此可选部分介绍了如何将 CA 证书添加到 Linux Debian 发行版的可信 CA 证书存储区。这些说明也适用于源自 Debian 的发行版,例如 Ubuntu。
将 CA 证书添加到此存储区意味着在使用 curl
、Python、Go 和 Ruby 发送 HTTPS 请求时无需指定可信 CA 证书的位置。
使用 SSH 连接到虚拟机实例:
gcloud compute ssh cas-tutorial-client --zone ZONE
在 SSH 会话中运行本部分中的其余命令。
将根 CA 证书复制到
/usr/local/share/ca-certificates
目录,并确保文件扩展名为.crt
:sudo cp root-ca-cert.pem /usr/local/share/ca-certificates/cas-rootca.crt
设置文件权限,以便所有用户都能读取根 CA 证书文件:
sudo chmod 644 /usr/local/share/ca-certificates/cas-rootca.crt
运行
update-ca-certificates
脚本:sudo update-ca-certificates
此脚本会将证书添加到
/etc/ssl/certs
目录中的可信证书集以及/etc/ssl/certs/ca-certificates.crt
文件中。输出如下所示:
Updating certificates in /etc/ssl/certs... 1 added, 0 removed; done. Running hooks in /etc/ca-certificates/update.d... done.
使用
curl
从虚拟机实例向示例应用发送 HTTPS 请求:curl --cert client-cert-chain.pem --key private-key.pem \ --resolve hello.example.com:443:$(cat ilb-ip.txt) \ --silent https://hello.example.com | head -n1
输出如下所示:
Hello, world!
此响应显示
curl
已成功使用 mTLS 发送 HTTPS 请求,并使用默认 CA 证书存储区验证了来自入站流量网关的服务器 TLS 证书。退出 SSH 会话:
exit
问题排查
如果 CA Service 颁发者控制器未创建 TLS 证书 Secret,请查看 CA Service 颁发者控制器的日志:
kubectl logs deployment/google-cas-issuer --namespace cert-manager
如果您在安装 Cloud Service Mesh 时遇到问题,请运行 asmcli
工具验证您的 Cloud 项目和 GKE 集群。
如果您在使用本教程时遇到其他问题,我们建议您查看以下文档:
- CA Service 常见问题解答
- 逐步排查 Cloud Service Mesh 问题
- 解决托管式 Cloud Service Mesh 问题
- Istio 操作常见问题
- GKE 问题排查
- Kubernetes 集群问题排查
清理
为避免系统因本教程中使用的资源而导致您的 Google Cloud 账号继续产生费用,您可以删除项目或删除各个资源。
删除项目
在 Cloud Shell 中,删除项目:
gcloud projects delete PROJECT_ID
删除资源
如果您希望保留在本教程中使用的 Google Cloud 项目,请删除单个资源:
在 Cloud Shell 中,从 GKE Hub 取消注册 GKE 集群:
gcloud container hub memberships unregister CLUSTER_NAME \ --gke-cluster ZONE/CLUSTER_NAME
删除 GKE 集群:
gcloud container clusters delete CLUSTER_NAME \ --zone ZONE --async --quiet
删除针对从属 CA 池的 IAM 政策绑定:
gcloud privateca pools remove-iam-policy-binding SUBORDINATE_CA_POOL_GATEWAYS \ --location CA_LOCATION \ --member "serviceAccount:CAS_ISSUER_GSA@PROJECT_ID.iam.gserviceaccount.com" \ --role roles/privateca.certificateRequester gcloud privateca pools remove-iam-policy-binding SUBORDINATE_CA_POOL_GATEWAYS \ --location CA_LOCATION \ --member "serviceAccount:CLIENT_VM_GSA@PROJECT_ID.iam.gserviceaccount.com" \ --role roles/privateca.certificateRequester
停用从属 CA 和根 CA 并安排将其删除:
gcloud privateca subordinates disable SUBORDINATE_CA_GATEWAYS \ --location CA_LOCATION \ --pool SUBORDINATE_CA_POOL_GATEWAYS \ --quiet gcloud privateca subordinates delete SUBORDINATE_CA_GATEWAYS \ --location CA_LOCATION \ --pool SUBORDINATE_CA_POOL_GATEWAYS \ --ignore-active-certificates \ --quiet gcloud privateca subordinates disable SUBORDINATE_CA_SIDECARS \ --location CA_LOCATION \ --pool SUBORDINATE_CA_POOL_SIDECARS \ --quiet gcloud privateca subordinates delete SUBORDINATE_CA_SIDECARS \ --location CA_LOCATION \ --pool SUBORDINATE_CA_POOL_SIDECARS \ --ignore-active-certificates \ --quiet gcloud privateca roots disable ROOT_CA \ --location CA_LOCATION \ --pool ROOT_CA_POOL \ --quiet gcloud privateca roots delete ROOT_CA \ --location CA_LOCATION \ --pool ROOT_CA_POOL \ --ignore-active-certificates \ --quiet
删除 CA Service 颁发者控制器 Google 服务账号的 IAM 政策绑定:
gcloud iam service-accounts remove-iam-policy-binding \ CAS_ISSUER_GSA@PROJECT_ID.iam.gserviceaccount.com \ --member "serviceAccount:PROJECT_ID.svc.id.goog[cert-manager/ksa-google-cas-issuer]" \ --role roles/iam.workloadIdentityUser
删除 Google 服务账号:
gcloud iam service-accounts delete --quiet \ CAS_ISSUER_GSA@PROJECT_ID.iam.gserviceaccount.com gcloud iam service-accounts delete --quiet \ CLIENT_VM_GSA@PROJECT_ID.iam.gserviceaccount.com
删除预留的负载均衡器 IP 地址:
gcloud compute addresses delete asm-ingress-gateway-ilb \ --region REGION --quiet
删除 Compute Engine 虚拟机实例:
gcloud compute instances delete cas-tutorial-client \ --zone ZONE --quiet
后续步骤
- 浏览其他 Certificate Authority Service 方法指南。
- 详细了解 Cloud Service Mesh,这是一款基于 Istio 的工具套件,可帮助您在本地和 Google Cloud 上监控和管理可靠的服务网格。
- 浏览 Cloud Service Mesh 方法指南。