本教程介绍如何使用 Anthos Service Mesh 出站和入站网关,通过双向传输层安全协议 (mTLS) 来保护集群间流量。本教程适用于负责网络、安全和平台方面的 Kubernetes 集群管理员。对于具有更高安全要求或需要满足监管前提条件的组织,此处所述的控制措施可能尤为有用。本教程随附配套的概念指南。
本教程假定您熟悉 Kubernetes 和 Anthos Service Mesh。
目标
- 使用 Terraform 设置基础架构:
- 创建包含两个专用子网的自定义 VPC 网络。
- 创建两个启用 Anthos Service Mesh 的 Kubernetes 集群:
- 一个 GKE 集群
- 一个在自定义 VPC 网络中运行的 Kubernetes Operations (kOps) 集群
- 将集群注册到 GKE Hub。
- 在 GKE 集群上部署 MySQL 客户端。
- 在 kOps 集群上部署 MySQL 服务器。
- 配置出站网关和入站网关以使用 mTLS 公开服务器。
- 使用在不同集群或 VPC 中运行的 MySQL 客户端测试对 MySQL 服务器的访问。
费用
在本文档中,您将使用 Google Cloud 的以下收费组件:
您可使用价格计算器根据您的预计使用情况来估算费用。
完成本教程后,您可以删除所创建的资源以避免继续计费。如需了解详情,请参阅清理。
准备工作
在本教程中,您需要一个 Google Cloud 项目。您可创建一个新项目,也可选择已创建的项目:
-
在 Google Cloud Console 中,转到项目选择器页面。
-
选择或创建 Google Cloud 项目。
-
确保您的 Google Cloud 项目已启用结算功能。了解如何检查项目是否已启用结算功能。
在 Google Cloud 控制台中,转到 Cloud Shell。
Cloud Shell 会话随即会在 Google Cloud 控制台的底部打开,并显示命令行提示符。Cloud Shell 是一个已安装 Google Cloud CLI 的 Shell 环境,其中包括 Google Cloud CLI。该会话可能需要几秒钟来完成初始化。
- 在 Cloud Shell 中,请确保您正在自己创建或选择的项目中执行操作:
export PROJECT_ID=PROJECT_ID gcloud config set project ${PROJECT_ID}
将
PROJECT_ID
替换为您的项目 ID。 - 为您用于 Google Cloud 的电子邮件地址创建环境变量:
export GOOGLE_CLOUD_EMAIL_ADDRESS=GOOGLE_CLOUD_EMAIL_ADDRESS
将
GOOGLE_CLOUD_EMAIL_ADDRESS
替换为您在 Google Cloud 中使用的电子邮件地址。 - 为计算资源设置地区和区域:
export REGION=us-central1 export ZONE=us-central1-b gcloud config set compute/region ${REGION} gcloud config set compute/zone ${ZONE}
本教程使用
us-central1
作为区域,使用us-central1-b
作为可用区。您可以部署到您选择的区域。 - 设置所需的 Identity and Access Management (IAM) 角色。如果您是 Project Owner,则拥有完成安装所需的全部权限。否则,请让管理员在 Cloud Shell 中运行以下命令,授予您 Identity and Access Management (IAM) 角色:
ROLES=( 'roles/container.admin' \ 'roles/gkehub.admin' \ 'roles/iam.serviceAccountAdmin' \ 'roles/iam.serviceAccountKeyAdmin' \ 'roles/resourcemanager.projectIamAdmin' \ 'roles/compute.securityAdmin' \ 'roles/compute.instanceAdmin' \ 'roles/storage.admin' \ 'roles/serviceusage.serviceUsageAdmin' ) for role in "${ROLES[@]}" do gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member "user:${GOOGLE_CLOUD_EMAIL_ADDRESS}" \ --role="$role" done
- 启用本教程所需的 API:
gcloud services enable \ anthos.googleapis.com \ anthosgke.googleapis.com \ anthosaudit.googleapis.com \ compute.googleapis.com \ container.googleapis.com \ cloudresourcemanager.googleapis.com \ serviceusage.googleapis.com \ stackdriver.googleapis.com \ monitoring.googleapis.com \ logging.googleapis.com \ cloudtrace.googleapis.com \ meshca.googleapis.com \ meshconfig.googleapis.com \ iamcredentials.googleapis.com \ gkeconnect.googleapis.com \ gkehub.googleapis.com
准备环境
在 Cloud Shell 中,克隆以下 Git 代码库:
git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-samples cd anthos-service-mesh-samples/docs/mtls-egress-ingress
为环境更新 Terraform。默认情况下,Google Cloud 控制台附带 Terraform 0.12。本教程假定您已安装 Terraform 0.13.5 或更高版本。您可以通过运行以下命令暂时使用其他版本的 Terraform:
mkdir ~/bin curl https://releases.hashicorp.com/terraform/0.13.5/terraform_0.13.5_linux_amd64.zip -o ~/bin/terraform.zip unzip ~/bin/terraform.zip -d ~/bin/
转到
terraform
子文件夹并初始化 Terraform:cd terraform/ ~/bin/terraform init
创建一个
terraform.tfvars
文件(基于您之前创建的环境变量):cat << EOF > terraform.tfvars project_id = "${PROJECT_ID}" region = "${REGION}" zones = ["${ZONE}"] EOF
在下一步中,您将创建初始基础架构。为此,您需要为此配置创建并应用 Terraform 执行计划。此计划中的脚本和模块会创建以下内容:
- 包含两个专用子网的自定义 VPC 网络
- 两个启用 Anthos Service Mesh 的 Kubernetes 集群
- 一个 GKE 集群
- 一个在自定义 VPC 网络中运行的 kOps 集群
该执行计划还会将集群注册到 GKE Hub。
运行执行计划:
~/bin/terraform plan -out mtls-terraform-plan ~/bin/terraform apply "mtls-terraform-plan"
输出内容类似如下:
Apply complete! Resources: 27 added, 0 changed, 0 destroyed. Outputs: server_token = <sensitive>
<sensitive>
部分是 Terraform 输出变量,不显示在控制台中,但可以查询,例如~/bin/terraform output server_token
。从
terraform
目录获取您的服务器集群kubeconfig
文件。然后,将其与client-cluster
配置文件合并:cd .. export KUBECONFIG=client-server-kubeconfig cp ./terraform/server-kubeconfig $KUBECONFIG gcloud container clusters get-credentials client-cluster --zone ${ZONE} --project ${PROJECT_ID}
client-server-kubeconfig
文件现在包含这两个集群的配置,您可以通过运行以下命令进行验证:kubectl config view -ojson | jq -r '.clusters[].name'
输出如下所示:
gke_PROJECT_ID_us-central1-c_client-cluster server-cluster.k8s.local
获取这两个集群的上下文供稍后使用:
export CLIENT_CLUSTER=$(kubectl config view -ojson | jq -r '.clusters[].name' | grep client) export SERVER_CLUSTER=$(kubectl config view -ojson | jq -r '.clusters[].name' | grep server) echo -e "${CLIENT_CLUSTER}\n${SERVER_CLUSTER}"
输出(再次)如下所示:
gke_PROJECT_ID_us-central1-c_client-cluster server-cluster.k8s.local
现在,您可以将这些集群名称用作后续
kubectl
命令的上下文。引用客户端集群:
kubectl --context ${CLIENT_CLUSTER} get pods -n istio-system
引用服务器集群:
kubectl --context ${SERVER_CLUSTER} get pods -n istio-system
配置客户端
如概念指南中所述,客户端要求您在 Anthos Service Mesh 中配置出站网关。
在本部分中,您将配置 Anthos Service Mesh 元素,以根据来源识别外部流量并使用自定义证书加密通信。此外,您希望仅将该流量路由到其目的地(容器中的 MySQL 数据库)。通常使用 Kubernetes 中的 Service 来实现此目的。在此示例中,您需要在网格通信内捕获该流量。要捕获流量,您需要使用 Istio 元素创建特殊的服务定义。您需要定义以下元素:
- 出站网关
- 服务条目
- 虚拟服务
- TLS 证书(作为 Secret)
- 目标规则
在 Cloud Shell 中,使用服务器端的上下文(您之前创建的
$SERVER_CLUSTER
)查询istio-ingressgateway
服务的负载平衡器 IP 地址,从而获取服务器端入站网关的 IP 地址:INGRESS_HOST=$(kubectl -n istio-system --context ${SERVER_CLUSTER} get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
由于
INGRESS_HOST
只是主机的 IP 地址部分,您需要创建完全限定域名 (FQDN)。此步骤是必需的,因为证书需要域名才能发挥作用。在本教程中,您可以使用通配符 DNS 服务 nip.io 为入站 IP 地址创建 FQDN。此服务允许您无需拥有网域也可创建 FQDN。
将 FQDN 服务网址存储在环境变量中:
export SERVICE_URL="${INGRESS_HOST}.nip.io"
将
SERVICE_URL
定义为 FQDN 后,您可以开始定义客户端集群的 Istio 部分。
创建出站网关
首先,您需要创建出站网关,以侦听发往外部服务的流量。
在 Cloud Shell 中,创建以下 YAML 文件并将其命名为
client-egress-gateway.yaml
:cat <<EOF > client-egress-gateway.yaml apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: istio-egressgateway-mysql spec: selector: istio: egressgateway servers: - port: number: 15443 name: tls protocol: TLS hosts: - $SERVICE_URL tls: mode: ISTIO_MUTUAL EOF
将上述 YAML 文件应用于客户端集群:
kubectl --context ${CLIENT_CLUSTER} apply -f client-egress-gateway.yaml
注意端口。在此处,您将
default
端口用于出站服务器开关,即15443
。如果要使用其他端口,则需要修改出站网关service
对象以添加自定义端口。hosts
开关定义了端点,即流量的目的地。
定义服务条目
下一步是将外部服务告知服务网格。Istio 拥有自己的注册表,用于为网格存储服务端点。如果 Istio 安装在 Kubernetes 之上,集群中定义的服务会自动添加到 Istio 注册表中。通过服务条目定义,您可以将新端点添加到 Istio 注册表,如下图所示。
在 Cloud Shell 中,创建以下 YAML 文件并将其命名为
client-service-entry.yaml
:cat <<EOF > client-service-entry.yaml apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: mysql-external spec: hosts: - $SERVICE_URL location: MESH_EXTERNAL ports: - number: 3306 name: tcp protocol: TCP - number: 13306 name: tls protocol: TLS resolution: DNS endpoints: - address: $SERVICE_URL ports: tls: 13306 EOF
将上述 YAML 文件应用于客户端集群:
kubectl --context ${CLIENT_CLUSTER} apply -f client-service-entry.yaml
此 YAML 文件中的客户端定义会向服务指明预期的流量类型(MySQL L4 - 网络第 4 层,使用端口 3306)。您还定义通信将流向“网格外部”。在端点部分,您定义流量应流向您之前设置的 FQDN 地址
$SERVICE_URL
,该地址映射到服务器集群 (kOps) 上的入站网关。
定义虚拟服务
虚拟服务是定向到主机时要应用的流量路由规则。每条路由规则为特定协议的流量定义匹配条件。如果流量匹配,则被发送到注册表中定义的指定目标服务(或其子集或某个版本)。如需了解详情,请参阅 Istio 文档。
虚拟服务定义告诉 Istio 如何对访问外部服务的流量应用路由。通过以下定义,您告诉网格将流量从客户端路由到端口 15443
上的出站网关。然后,从出站网关将流量路由到端口 13306
(由服务器端入站网关侦听)上的主机 $SERVICE_URL
。
创建以下 YAML 文件并将其命名为
client-virtual-service.yaml
:cat <<EOF > client-virtual-service.yaml apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: direct-mysql-through-egress-gateway spec: hosts: - $SERVICE_URL gateways: - istio-egressgateway-mysql - mesh tcp: - match: - gateways: - mesh port: 3306 route: - destination: host: istio-egressgateway.istio-system.svc.cluster.local subset: mysql port: number: 15443 weight: 100 - match: - gateways: - istio-egressgateway-mysql port: 15443 route: - destination: host: $SERVICE_URL port: number: 13306 weight: 100 EOF
将该 YAML 定义应用于客户端集群:
kubectl --context ${CLIENT_CLUSTER} apply -f client-virtual-service.yaml
您可以通过修改 YAML 文件中的
gateways
开关来指定向哪些网关应用配置。此定义中的重要部分是保留字
mesh
的使用,这表示网格中的所有 Sidecar。根据 Istio 文档,如果省略此字段,则使用默认网关(网格),并将规则应用于网格中的所有 Sidecar。如果您提供网关名称列表,则规则仅应用于这些网关。要将规则应用于网关和 Sidecar,请将mesh
指定为网关名称之一。
在下一部分中,您将定义如何处理来自客户端 prod 代理 (match.gateways.mesh
) 的流量。您还将使用 match.gateways.istio-egressgateway-mysql
开关定义如何将来自出站网关的流量路由到外部服务。
定义目标规则(从客户端到出站网关)
您已定义如何将流量路由到外部服务,还需要定义适用的流量政策。您刚才定义的虚拟服务一次处理两个路由事件。一个处理从 Sidecar 代理到出站网关的流量,另一个处理从出站网关到外部服务的流量。
要将这些事件与目标规则相匹配,您需要两条单独的规则。下图显示了第一条规则,它处理从代理到出站网关的流量。在此定义中,您指示 Anthos Service Mesh 将默认证书用于 mTLS 通信。
在 Cloud Shell 中,创建以下 YAML 文件并将其命名为
client-destination-rule-to-egress-gateway.yaml
:cat <<EOF > client-destination-rule-to-egress-gateway.yaml apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: egressgateway-for-mysql spec: host: istio-egressgateway.istio-system.svc.cluster.local subsets: - name: mysql trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 15443 tls: mode: ISTIO_MUTUAL sni: $SERVICE_URL EOF
将上述 YAML 定义应用于客户端集群:
kubectl --context ${CLIENT_CLUSTER} apply -f client-destination-rule-to-egress-gateway.yaml
在上面的 YAML 文件中,您使用
hosts
开关来定义如何将流量从客户端代理路由到出站网关。此外,您将网格配置为在端口15443
上使用ISTIO_MUTUAL
,该端口是出站网关上自动打开的端口之一。
创建目标规则(从出站网关到外部服务)
下图展示了第二条目标规则,它告诉网格如何处理从出站网关到外部服务的流量。
您需要指示网格使用注入的证书与外部服务进行双向 TLS 通信。
在 Cloud Shell 中,从
anthos-service-mesh-samples/docs/mtls-egress-ingress
目录创建证书:./create-keys.sh
请务必在脚本要求时提供密码。
将生成的文件复制到当前目录:
cp ./certs/2_intermediate/certs/ca-chain.cert.pem ca-chain.cert.pem cp ./certs/4_client/private/$SERVICE_URL.key.pem client-$SERVICE_URL.key.pem cp ./certs/4_client/certs/$SERVICE_URL.cert.pem client-$SERVICE_URL.cert.pem
创建用于存储证书的 Kubernetes Secret,以便稍后在网关中引用它们:
kubectl --context ${CLIENT_CLUSTER} create secret -n istio-system \ generic client-credential \ --from-file=tls.key=client-$SERVICE_URL.key.pem \ --from-file=tls.crt=client-$SERVICE_URL.cert.pem \ --from-file=ca.crt=ca-chain.cert.pem
上述命令会将以下证书文件添加到 Secret 中:
client-$SERVICE_URL.key.pem client-$SERVICE_URL.cert.pem ca-chain.cert.pem
此处使用了 Secret Discovery Service (SDS)(而不是文件装载),这是分发证书的当前最佳做法。这种做法可以避免在添加新证书时重启 pod。从 Istio 1.8/1.9 开始,此技术使您不再需要网关 Secret 的读取权限 (RBAC)。
将证书添加到
DestinationRule
,并将其命名为client-destination-rule-to-external-service.yaml
:cat <<EOF > client-destination-rule-to-external-service.yaml apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: originate-mtls-for-mysql spec: host: $SERVICE_URL trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 13306 tls: mode: MUTUAL credentialName: client-credential sni: $SERVICE_URL EOF
将上述 YAML 定义应用于客户端集群:
kubectl --context ${CLIENT_CLUSTER} apply -f client-destination-rule-to-external-service.yaml
此规则仅在预先创建了 Secret 的情况下有效。Secret 可确保证书用于从出站网关到外部端点的 mTLS 加密。
完成这些步骤后,客户端设置即完成并如下图所示。
配置服务器端
如概念指南中所述,对于服务器端,您需要在 Anthos Service Mesh 中配置入站网关。在创建必要的文件之前,最好回顾一下实现解决方案的服务器部分所需的组件。
基本上,您希望根据来源和证书来识别传入流量。此外,您希望仅将该流量路由到其目的地,即容器中的 MySQL 数据库。通常使用 Kubernetes 中的 Service 来实现此目的,但在本示例中,您需要识别网格通信内的传入流量,因此需要特殊的服务定义,其中包括以下元素:
- TLS 证书(作为 Secret)
- 入站流量网关
- 虚拟服务
为入站网关创建 Secret
与出站网关一样,您需要相同的证书来保护入站网关的通信。为此,您需要将证书存储在 Secret 中,并使用入站网关对象定义此 Secret。
在 Cloud Shell 中,将生成的文件复制到您要执行下一个命令的位置:
cp ./certs/3_application/private/$SERVICE_URL.key.pem server-$SERVICE_URL.key.pem cp ./certs/3_application/certs/$SERVICE_URL.cert.pem server-$SERVICE_URL.cert.pem
创建服务器密 Secret:
kubectl --context ${SERVER_CLUSTER} create secret -n istio-system \ generic mysql-credential \ --from-file=tls.key=server-$SERVICE_URL.key.pem \ --from-file=tls.crt=server-$SERVICE_URL.cert.pem \ --from-file=ca.crt=ca-chain.cert.pem
您向 Secret 添加了以下证书文件:
server-$SERVICE_URL.key.pem server-$SERVICE_URL.cert.pem ca-chain.cert.pem
定义入站网关
要从客户端集群接收流量,您需要指定可以使用证书解密和验证 TLS 通信的入站网关。
上图显示了入站网关在集群中的位置。流量通过时,网关会检查其是否符合安全和转发条件。
在 Cloud Shell 中,使用以下 YAML 文件并将其命名为
server-ingress-gatway.yaml
:cat <<EOF > server-ingress-gatway.yaml apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: gateway-mysql spec: selector: istio: ingressgateway # Istio default gateway implementation servers: - port: number: 13306 name: tls-mysql protocol: TLS tls: mode: MUTUAL credentialName: mysql-credential hosts: - "$SERVICE_URL" EOF
将上述 YAML 定义应用于客户端集群:
kubectl --context ${SERVER_CLUSTER} apply -f server-ingress-gatway.yaml
请注意
tls:
部分,因为它特别重要。在本部分中,您定义要使用 mTLS。为确保按预期实现,您需要提供您创建的包含证书的 Secret。通过修补入站流量服务来启用端口
13306
。创建以下 JSON 文件并将其命名为gateway-patch.json
,以启用此端口:cat <<EOF > gateway-patch.json [{ "op": "add", "path": "/spec/ports/0", "value": { "name": "tls-mysql", "protocol": "TCP", "targetPort": 13306, "port": 13306 } }] EOF
将补丁程序应用于网关服务:
kubectl --context ${SERVER_CLUSTER} -n istio-system patch --type=json svc istio-ingressgateway -p "$(cat gateway-patch.json)"
现在您已在入站网关上打开端口,接下来需要提取来自新的入站网关的流量并将其定向到数据库 pod。您可以使用网格内部对象(虚拟服务)来实现此目的。
定义虚拟服务
如前所述,虚拟服务是影响网格内流量的流量匹配模式的定义。您需要正确识别来自入站网关的流量并将其转发到 MySQL 数据库服务,如下图所示。
在 Cloud Shell 中,创建以下 YAML 文件并将其命名为
server-virtual-service.yaml
:cat <<EOF > server-virtual-service.yaml apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: mysql-virtual-service spec: hosts: - "$SERVICE_URL" gateways: - gateway-mysql tcp: - route: - destination: port: number: 3306 host: mysql.default.svc.cluster.local EOF
此虚拟服务必须引用流量源自的入站网关,这一点很重要。网关命名为
gateway-mysql
。由于此虚拟服务应用于 L4,您需要提供
tcp
标志来描述 MySQL 流量。此标志实质上是告诉网格,此流量使用 L4。您可能已经注意到,入站流量服务使用端口
13306
转发流量。虚拟服务会提取该端口并将其转换回3306
。最后,流量被转发到服务器 Kubernetes 集群中的 MySQL 服务器。在本示例中,服务器侦听标准 MySQL 端口
3306
。将 YAML 定义应用于服务器集群:
kubectl --context ${SERVER_CLUSTER} apply -f server-virtual-service.yaml
这两个定义解密 mTLS 封装的 MySQL 客户端请求,并将其转发到网格内的 MySQL 数据库。
您有必要了解,网格内部转发也是使用加密完成的,但在这种情况下,加密基于网格内部证书。mTLS 终止发生在网关处。
现在,您已经拥有与 MySQL 服务器的完整的双向加密通信方法。这种加密形式对 MySQL 客户端和服务器是透明的,因此无需更改应用。这可以使更改或轮替证书等任务变得简单。此外,这种通信方式可用于许多不同的场景。
测试设置
客户端和服务器端已准备就绪,现在您可以测试设置了。
现在可以生成一些从客户端到服务器端的流量。您希望跟踪流量,并确保流量按预期路由、加密和解密。
在 Cloud Shell 中,将 MySQL 服务器部署到服务器集群中:
kubectl --context ${SERVER_CLUSTER} apply -f server/mysql-server/mysql.yaml
在客户端集群上启动 MySQL 客户端:
kubectl run --context ${CLIENT_CLUSTER} --env=SERVICE_URL=$SERVICE_URL -it --image=mysql:5.6 mysql-client-1 --restart=Never -- /bin/bash
容器启动后,您会看到一个如下所示的 shell:
root@mysql-client-1:/#
连接到 MySQL 服务器:
mysql -pyougottoknowme -h $SERVICE_URL
使用以下命令添加数据库和表:
CREATE DATABASE test_encrypted_connection; USE test_encrypted_connection; CREATE TABLE message (id INT, content VARCHAR(20)); INSERT INTO message (id,content) VALUES(1,"Crypto Hi");
连接并添加表后,退出 MySQL 连接和 pod:
exit exit
您需要输入两次 exit,第一次退出数据库连接,第二次退出 pod。如果 pod 在退出时停止响应,请按 Control+C 取消 bash shell。
通过以上步骤,您应该已经生成了一些有意义的日志记录输出,现在可以进一步分析。
在下一部分中,您将检查客户端流量是否通过代理和出站网关。您还将测试能否看到流量通过入站网关进入服务器端。
测试客户端代理和出站网关
在 Cloud Shell 中,在客户端代理上,检查是否可以看到 Istio 代理日志:
kubectl --context ${CLIENT_CLUSTER} logs -l run=mysql-client-1 -c istio-proxy -f
调试输出类似于以下内容:
[2021-02-10T21:19:08.292Z] "- - -" 0 - "-" "-" 176 115 10 - "-" "-" "-" "-" "192.168.1.4:15443" outbound|15443|mysql|istio-egressgateway.istio-system.svc.cluster.local 192.168.1.12:58614 34.66.165.46:3306 192.168.1.12:39642 - -
按 Ctrl+C 退出日志输出。
在此日志条目中,您可以看到客户端请求在 IP 地址
34.66.165.46
的端口3306
上运行的服务器。请求被转发 (outbound
) 到侦听 IP 地址192.168.1.4
端口15443
的istio-egressgateway
。您在虚拟服务 (client-virtual-service.yaml
) 中定义了此转发。读取出站网关代理日志:
kubectl --context ${CLIENT_CLUSTER} logs -n istio-system -l app=istio-egressgateway -f
调试输出类似于以下内容:
[2021-02-10T21:19:08.292Z] "- - -" 0 - "-" "-" 176 115 19 - "-" "-" "-" "-" "34.66.165.46:13306" outbound|13306||34.66.165.46.nip.io 192.168.1.4:53542 192.168.1.4:15443 192.168.1.12:58614 34.66.165.46.nip.io -
按 Ctrl+C 退出日志输出。
在此日志条目中,您可以看到路由到侦听 IP 地址
192.168.1.4
端口15443
的istio-egressgateway
的客户端请求被进一步路由到侦听 IP 地址34.66.165.46
端口13306.
的服务网格外部服务。您在虚拟服务 (client-virtual-service.yaml
) 的第二部分中定义了此转发。
测试服务器端入站网关
在 Cloud Shell 中,在服务器端,查看入站网关代理日志:
kubectl --context ${SERVER_CLUSTER} logs -n istio-system -l app=istio-ingressgateway -f
日志中的输出类似于以下内容:
[2021-02-10T21:22:27.381Z] "- - -" 0 - "-" "-" 0 78 5 - "-" "-" "-" "-" "100.96.4.8:3306" outbound|3306||mysql.default.svc.cluster.local 100.96.1.3:55730 100.96.1.3:13306 100.96.1.1:42244 34.66.165.46.nip.io -
按 Ctrl+C 退出日志输出。
在此日志条目中,您可以看到路由到侦听 IP 地址
34.66.165.46
端口13306
的istio-ingressgateway
的外部客户端请求被进一步路由到端口3306.
上的网格内 MySQL 服务mysql.default.svc.cluster.local
。您在入站网关 (server-ingress-gateway.yaml
) 中定义了此转发。对于 MySQL 服务器,查看 Istio 代理日志:
kubectl --context ${SERVER_CLUSTER} logs -l app=mysql -c istio-proxy -f
输出类似于以下内容:
[2021-02-10T21:22:27.382Z] "- - -" 0 - "-" "-" 1555 1471 4 - "-" "-" "-" "-" "127.0.0.1:3306" inbound|3306|mysql|mysql.default.svc.cluster.local 127.0.0.1:45894 100.96.4.8:3306 100.96.1.3:55730 outbound_.3306_._.mysql.default.svc.cluster.local -
按 Ctrl+C 退出日志输出。
在此日志条目中,您可以看到对侦听 IP 地址
100.96.4.8
端口3306
的 MySQL 数据库服务器的入站调用。该调用来自 IP 地址为100.96.1.3
的 Ingress pod。如需详细了解 Envoy 日志记录格式,请参阅获取 Envoy 的访问日志。
测试数据库以查看生成的输入:
MYSQL=$(kubectl --context ${SERVER_CLUSTER} get pods -n default | tail -n 1 | awk '{print $1}') kubectl --context ${SERVER_CLUSTER} exec $MYSQL -ti -- /bin/bash
验证创建的数据库:
mysql -pyougottoknowme USE test_encrypted_connection; SELECT * from message;
输出内容类似如下:
+------+-----------+ | id | content | +------+-----------+ | 1 | Crypto Hi | +------+-----------+ 1 row in set (0.00 sec)
退出 MySQL 数据库:
exit exit
您需要输入两次
exit
,第一次退出数据库连接,第二次退出 pod。
通过省略证书测试访问
您已经测试并验证,使用注入证书时,访问可正常进行,现在可以测试反过来的情况:如果省略出站网关和证书注入,会发生什么。此测试也称为负面测试。
要执行此测试,您可以在命名空间中启动另一个 pod,并且不启用代理注入。
在 Cloud Shell 中,创建一个新的命名空间:
kubectl --context ${CLIENT_CLUSTER} create ns unencrypted
创建 pod 并在容器内启动交互式 shell:
kubectl --context ${CLIENT_CLUSTER} run -it --image=mysql:5.6 \ mysql-client-2 --env=SERVICE_URL=$SERVICE_URL \ -n unencrypted --restart=Never -- /bin/bash
在交互式 shell 启动后尝试连接到数据库:
mysql -pyougottoknowme -h $SERVICE_URL
30 秒后,您将看到如下所示的输出:
Warning: Using a password on the command line interface can be insecure. ERROR 2003 (HY000): Can't connect to MySQL server on '104.154.164.12.nip.io' (110)
此警告是预期现象,因为此 pod 省略了出站网关,并尝试通过互联网直接访问入站网关 (
$SERVICE_URL
)。尝试解析服务 IP 地址:
resolveip $SERVICE_URL
输出类似于以下内容:您的 IP 地址会有所不同。
IP address of 104.154.164.12.nip.io is 104.154.164.12
这证明 FQDN 可解析,并且连接失败确实是缺少证书注入导致的。
退出 MySQL 连接和 MySQL 服务器 pod:
exit exit
进一步调查
本教程未介绍的一个主题是,出站配置通常由公司中的另一个角色或组织拥有,因为它们托管在 istio-system
命名空间中。请配置 Kubernetes RBAC 权限,使得只有网络管理员可以直接创建和修改本教程中讨论的资源。
您已经知道如何使用服务网格来确保安全通信,您可以将其与需要安全交换数据的应用搭配使用,或者在需要在证书层控制加密的使用场景中使用。首先,您可以安装 Anthos Service Mesh。
尝试使用两个 GKE 集群,并使用本教程中的技术将其组合到一起。此技术也适用于两个外部 Kubernetes 集群之间的 Anthos 平台。
服务网格是一种提高集群内部安全性和外部服务安全性的绝佳方法。最后一个尝试的使用场景是使用不是第二个 Kubernetes 集群而是第三方提供商(例如付款服务机构)的 mTLS 端点。
清除数据
为避免系统因本教程中使用的资源向您的 Google Cloud 帐号收取费用,您可以删除您的项目。
删除项目
- 在 Google Cloud 控制台中,转到管理资源页面:
- 在项目列表中,选择要删除的项目,然后点击删除。
- 在对话框中输入项目 ID,然后点击关闭以删除项目。
后续步骤
- 阅读配套概念指南。
- 如需了解配置出站网关的更多最佳做法,请参阅在 GKE 集群上使用 Anthos Service Mesh 出站网关:教程。
- 参阅 GKE 安全强化指南和随附的 Terraform 模块。
- 探索有关 Google Cloud 的参考架构、图表和最佳做法。查看我们的 Cloud Architecture Center。