本教程介绍了如何使用 Cloud Service Mesh 出站流量网关和其他 Google Cloud 控制措施来确保出站流量安全 (出站流量)来自部署在 Google Kubernetes Engine 集群上的工作负载。本教程是在 GKE 集群上使用 Cloud Service Mesh 出站流量网关的最佳实践的配套教程。
本教程的目标受众包括管理由一个或多个软件交付团队使用的 Google Kubernetes Engine 集群的网络、平台和安全工程师。对于必须展示其遵从了法规(例如 GDPR 和 PCI)的组织,此处介绍的控制措施尤为有用。
目标
- 设置用于运行 Cloud Service Mesh 的基础架构:
- 自定义 VPC 网络和专用子网
- 用于互联网访问的 Cloud NAT
- 专用 GKE 集群,具有用于出站流量网关 pod 的额外节点池
- 受限出站流量 VPC 防火墙规则;只有网关节点可以访问外部主机
- 用于连接到 Container Registry 和 Google API 的 专用 Google 访问通道
- 安装 Cloud Service Mesh。
- 安装在专用节点池上运行的出站流量网关代理。
- 为通过出站流量网关的外部流量配置多租户路由规则:
- 命名空间
team-x
中的应用可以连接到example.com
- 命名空间
team-y
中的应用可以连接到httpbin.org
- 命名空间
- 使用
Sidecar
资源限制每个命名空间的 Sidecar 代理出站流量配置的范围。 - 配置授权政策以强制执行出站规则。
- 配置出站流量网关,将纯文本 HTTP 请求升级为 TLS(TLS 源)。
- 配置出站流量网关以直通 TLS 流量。
- 设置 Kubernetes 网络政策作为额外的出站流量控制措施。
- 使用专用 Google 访问通道和 Identity and Access Management (IAM) 权限配置对 Google API 的直接访问。
费用
在本文档中,您将使用 Google Cloud 的以下收费组件:
- Compute Engine
- Google Kubernetes Engine (GKE)
- Container Registry
- Cloud Service Mesh
- Cloud Load Balancing
- Cloud NAT
- Networking
- Cloud Storage
您可使用价格计算器根据您的预计使用情况来估算费用。
完成本教程后,您可以删除所创建的资源以避免持续产生费用。如需了解详情,请参阅清理。
准备工作
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, activate Cloud Shell.
创建在学习本教程时使用的工作目录:
mkdir -p ~/WORKING_DIRECTORY cd ~/WORKING_DIRECTORY
创建一个 shell 脚本,用于为本教程初始化您的环境。根据您的项目和偏好替换和修改变量。如果 shell 会话过期,使用
source
命令运行此脚本来重新初始化您的环境:cat << 'EOF' > ./init-egress-tutorial.sh #! /usr/bin/env bash PROJECT_ID=YOUR_PROJECT_ID REGION=REGION ZONE=ZONE gcloud config set project ${PROJECT_ID} gcloud config set compute/region ${REGION} gcloud config set compute/zone ${ZONE} EOF
启用
compute.googleapis.com
:gcloud services enable compute.googleapis.com --project=YOUR_PROJECT_ID
将脚本设为可执行文件,并使用
source
命令运行该脚本来初始化您的环境。如果系统提示您启用compute.googleapis.com
,请选择Y
:chmod +x ./init-egress-tutorial.sh source ./init-egress-tutorial.sh
设置基础架构
创建 VPC 网络和子网
创建新的 VPC 网络:
gcloud compute networks create vpc-network \ --subnet-mode custom
创建集群运行的子网,并为 pod 和服务预先分配次要 IP 地址范围。启用专用 Google 访问通道,使仅具有内部 IP 地址的应用可以访问 Google API 和服务:
gcloud compute networks subnets create subnet-gke \ --network vpc-network \ --range 10.0.0.0/24 \ --secondary-range pods=10.1.0.0/16,services=10.2.0.0/20 \ --enable-private-ip-google-access
配置 Cloud NAT
Cloud NAT 允许没有外部 IP 地址的工作负载连接到互联网上的目标,并接收来自这些目标的入站响应。
创建 Cloud Router 路由器:
gcloud compute routers create nat-router \ --network vpc-network
向路由器添加 NAT 配置:
gcloud compute routers nats create nat-config \ --router nat-router \ --nat-all-subnet-ip-ranges \ --auto-allocate-nat-external-ips
为每个 GKE 节点池创建服务账号
创建两个服务账号供两个 GKE 节点池使用。系统会为每个节点池分配一个单独的服务账号,以便您可以将 VPC 防火墙规则应用于特定节点。
创建一个供默认节点池中的节点使用的服务账号:
gcloud iam service-accounts create sa-application-nodes \ --description="SA for application nodes" \ --display-name="sa-application-nodes"
创建一个供网关节点池中的节点使用的服务账号:
gcloud iam service-accounts create sa-gateway-nodes \ --description="SA for gateway nodes" \ --display-name="sa-gateway-nodes"
向服务账号授予权限
向应用和网关服务账号添加一组最少的 IAM 角色。日志记录、监控以及从 Container Registry 拉取私有容器映像需要这些角色。
project_roles=(
roles/logging.logWriter
roles/monitoring.metricWriter
roles/monitoring.viewer
roles/storage.objectViewer
)
for role in "${project_roles[@]}"
do
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="$role"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="$role"
done
创建防火墙规则
在以下步骤中,您将对 VPC 网络应用防火墙规则,从而默认拒绝所有出站流量。要使集群能够正常运行以及网关节点能够访问 VPC 外部的目标,需要进行特定的连接。一组最低的特定防火墙规则会覆盖默认的全部拒绝规则,以允许必要的连接。
创建默认(低优先级)防火墙规则,拒绝来自 VPC 网络的所有出站流量:
gcloud compute firewall-rules create global-deny-egress-all \ --action DENY \ --direction EGRESS \ --rules all \ --destination-ranges 0.0.0.0/0 \ --network vpc-network \ --priority 65535 \ --description "Default rule to deny all egress from the network."
创建一条规则,仅允许具有网关服务账号的节点访问互联网:
gcloud compute firewall-rules create gateway-allow-egress-web \ --action ALLOW \ --direction EGRESS \ --rules tcp:80,tcp:443 \ --target-service-accounts sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --network vpc-network \ --priority 1000 \ --description "Allow the nodes running the egress gateways to connect to the web"
允许节点访问 Kubernetes 控制层面:
gcloud compute firewall-rules create allow-egress-to-api-server \ --action ALLOW \ --direction EGRESS \ --rules tcp:443,tcp:10250 \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --destination-ranges 10.5.0.0/28 \ --network vpc-network \ --priority 1000 \ --description "Allow nodes to reach the Kubernetes API server."
可选:如果您使用代管式 Cloud Service Mesh,则不需要此防火墙规则。
在将 Sidecar 代理注入工作负载时,Cloud Service Mesh 使用网络钩子。允许 GKE API 服务器调用节点上运行的服务网格控制平面公开的网络钩子:
gcloud compute firewall-rules create allow-ingress-api-server-to-webhook \ --action ALLOW \ --direction INGRESS \ --rules tcp:15017 \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --source-ranges 10.5.0.0/28 \ --network vpc-network \ --priority 1000 \ --description "Allow the API server to call the webhooks exposed by istiod discovery"
允许节点与集群上运行的 Pod 之间建立出站流量连接。GKE 会自动创建相应的入站流量规则。Service 连接不需要规则,因为 iptables 路由链始终会将 Service IP 地址转换为 Pod IP 地址。
gcloud compute firewall-rules create allow-egress-nodes-and-pods \ --action ALLOW \ --direction EGRESS \ --rules all \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --destination-ranges 10.0.0.0/24,10.1.0.0/16 \ --network vpc-network \ --priority 1000 \ --description "Allow egress to other Nodes and Pods"
允许访问专用 Google 访问通道用于提供 Google API、Container Registry 和其他服务的预留 IP 地址集:
gcloud compute firewall-rules create allow-egress-gcp-apis \ --action ALLOW \ --direction EGRESS \ --rules tcp \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --destination-ranges 199.36.153.8/30 \ --network vpc-network \ --priority 1000 \ --description "Allow access to the VIPs used by Google Cloud APIs (Private Google Access)"
允许 Google Cloud 健康检查程序服务访问集群中运行的 pod。如需了解详情,请参阅健康检查。
gcloud compute firewall-rules create allow-ingress-gcp-health-checker \ --action ALLOW \ --direction INGRESS \ --rules tcp:80,tcp:443 \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --source-ranges 35.191.0.0/16,130.211.0.0/22,209.85.152.0/22,209.85.204.0/22 \ --network vpc-network \ --priority 1000 \ --description "Allow workloads to respond to Google Cloud health checks"
配置 Google Cloud API 的专用访问通道
启用专用 Google 访问通道后,只有内部 IP 地址的虚拟机和 pod 可以访问 Google API 和服务。虽然 Google API 和服务是从外部 IP 提供的,但在使用专用 Google 访问通道时,来自节点的流量始终不会离开 Google 网络。
启用 Cloud DNS API:
gcloud services enable dns.googleapis.com
创建专用 DNS 区域、CNAME
和 A
记录,以便节点和工作负载可以使用专用 Google 访问通道和 private.googleapis.com
主机名连接到 Google API 和服务:
gcloud dns managed-zones create private-google-apis \
--description "Private DNS zone for Google APIs" \
--dns-name googleapis.com \
--visibility private \
--networks vpc-network
gcloud dns record-sets transaction start --zone private-google-apis
gcloud dns record-sets transaction add private.googleapis.com. \
--name "*.googleapis.com" \
--ttl 300 \
--type CNAME \
--zone private-google-apis
gcloud dns record-sets transaction add "199.36.153.8" \
"199.36.153.9" "199.36.153.10" "199.36.153.11" \
--name private.googleapis.com \
--ttl 300 \
--type A \
--zone private-google-apis
gcloud dns record-sets transaction execute --zone private-google-apis
配置 Container Registry 的专用访问通道
创建专用 DNS 区域、CNAME
和 A
记录,以便节点可以使用专用 Google 访问通道和 gcr.io
主机名连接到 Container Registry:
gcloud dns managed-zones create private-gcr-io \
--description "private zone for Container Registry" \
--dns-name gcr.io \
--visibility private \
--networks vpc-network
gcloud dns record-sets transaction start --zone private-gcr-io
gcloud dns record-sets transaction add gcr.io. \
--name "*.gcr.io" \
--ttl 300 \
--type CNAME \
--zone private-gcr-io
gcloud dns record-sets transaction add "199.36.153.8" "199.36.153.9" "199.36.153.10" "199.36.153.11" \
--name gcr.io \
--ttl 300 \
--type A \
--zone private-gcr-io
gcloud dns record-sets transaction execute --zone private-gcr-io
创建专用 GKE 集群
找到您的 Cloud Shell 的外部 IP 地址,以便将其添加到允许访问集群的 API 服务器的网络列表:
SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com)
如果 Cloud Shell 虚拟机有一段时间处于不活动状态,其外部 IP 地址可能会更改。如果发生这种情况,您必须更新集群的授权网络列表。将以下命令添加到初始化脚本中:
cat << 'EOF' >> ./init-egress-tutorial.sh SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com) gcloud container clusters update cluster1 \ --enable-master-authorized-networks \ --master-authorized-networks ${SHELL_IP//\"}/32 EOF
启用 Google Kubernetes Engine API:
gcloud services enable container.googleapis.com
创建专用 GKE 集群:
gcloud container clusters create cluster1 \ --enable-ip-alias \ --enable-private-nodes \ --release-channel "regular" \ --enable-master-authorized-networks \ --master-authorized-networks ${SHELL_IP//\"}/32 \ --master-ipv4-cidr 10.5.0.0/28 \ --enable-dataplane-v2 \ --service-account "sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \ --machine-type "e2-standard-4" \ --network "vpc-network" \ --subnetwork "subnet-gke" \ --cluster-secondary-range-name "pods" \ --services-secondary-range-name "services" \ --workload-pool "${PROJECT_ID}.svc.id.goog" \ --zone ${ZONE}
创建集群可能需要几分钟时间。集群的专用节点具有内部 IP 地址。系统会向 pod 和服务分配您在创建 VPC 子网时定义的已命名次要范围内的 IP。
具有集群内控制平面的 Cloud Service Mesh 要求集群节点使用至少具有 4 个 vCPU 的机器类型。
Google 建议为集群订阅“常规”发布版本 确保节点运行的 Kubernetes 版本 Cloud Service Mesh 支持。
如需详细了解使用集群内控制平面运行 Cloud Service Mesh 的前提条件,请参阅集群内前提条件。
如需详细了解运行代管式 Cloud Service Mesh 的要求和限制,请参阅代管式 Cloud Service Mesh 支持的功能。
适用于 GKE 的 Workload Identity Federation 是 集群上启用的 IP 地址Cloud Service Mesh 需要适用于 GKE 的工作负载身份联合,以及 是从 GKE 访问 Google API 的推荐方法 工作负载
创建一个名为 gateway 的节点池。出站流量网关将部署在这个节点池中。将
dedicated=gateway:NoSchedule
污点 添加到网关节点池中的每个节点。gcloud container node-pools create "gateway" \ --cluster "cluster1" \ --machine-type "e2-standard-4" \ --node-taints dedicated=gateway:NoSchedule \ --service-account "sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \ --num-nodes "1"
Kubernetes 污点和容忍有助于确保网关节点池中的节点上只运行出站流量网关 pod。
下载凭据,以便您可以使用 kubectl 连接到集群:
gcloud container clusters get-credentials cluster1
验证网关节点是否具有正确的污点:
kubectl get nodes -l cloud.google.com/gke-nodepool=gateway -o yaml \ -o=custom-columns='name:metadata.name,taints:spec.taints[?(@.key=="dedicated")]'
输出类似于以下内容:
name taints gke-cluster1-gateway-9d65b410-cffs map[effect:NoSchedule key:dedicated value:gateway]
安装和设置 Cloud Service Mesh
按照 Cloud Service Mesh 的安装指南之一操作:
安装 Cloud Service Mesh 后,您可以停止并返回本教程,而无需安装入站流量或出站流量网关。
安装出站流量网关
为出站流量网关创建 Kubernetes 命名空间:
kubectl create namespace istio-egress
启用用于注入的命名空间。具体步骤取决于您的控制平面实现。
受管 (TD)
将默认注入标签应用于命名空间:
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwrite
受管理(Istiod)
推荐:运行以下命令可将默认注入标签应用于命名空间:
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwrite
如果您是使用 Managed Istiod 控制平面的现有用户: 我们建议您使用默认注入,但基于修订版本的注入 支持。请按照以下说明操作:
运行以下命令查找可用的发布渠道:
kubectl -n istio-system get controlplanerevision
输出类似于以下内容:
NAME AGE asm-managed-rapid 6d7h
在输出中,
NAME
列下的值是与 Cloud Service Mesh 版本的可用发布版本对应的修订版本标签。将修订版本标签应用于命名空间:
kubectl label namespace istio-egress \ istio-injection- istio.io/rev=REVISION_LABEL --overwrite
集群内
推荐:运行以下命令可将默认注入标签应用于命名空间:
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwrite
我们建议您使用默认注入,但支持基于修订版本的注入: 请按照以下说明操作:
使用以下命令查找
istiod
的修订版本标签:kubectl get deploy -n istio-system -l app=istiod -o \ jsonpath={.items[*].metadata.labels.'istio\.io\/rev'}'{"\n"}'
将修订版本标签应用于命名空间。在以下命令中,
REVISION_LABEL
是您在上一步中记下的istiod
修订版本标签的值。kubectl label namespace istio-egress \ istio-injection- istio.io/rev=REVISION_LABEL --overwrite
创建运算符清单 对于出站流量网关:
cat << EOF > egressgateway-operator.yaml apiVersion: install.istio.io/v1alpha1 kind: IstioOperator metadata: name: egressgateway-operator annotations: config.kubernetes.io/local-config: "true" spec: profile: empty revision: REVISION components: egressGateways: - name: istio-egressgateway namespace: istio-egress enabled: true values: gateways: istio-egressgateway: injectionTemplate: gateway tolerations: - key: "dedicated" operator: "Equal" value: "gateway" nodeSelector: cloud.google.com/gke-nodepool: "gateway" EOF
下载
istioctl
工具。您必须使用版本 1.16.2-asm.2 或更高版本,即使 (如果您使用的是 Cloud Service Mesh 1.15 或更低版本)。请参阅下载正确的 istioctl 版本。解压缩下载的归档文件后,设置一个环境变量来保存
istioctl
工具的路径,并将其添加到初始化脚本中:ISTIOCTL=$(find "$(pwd -P)" -name istioctl) echo "ISTIOCTL=\"${ISTIOCTL}\"" >> ./init-egress-tutorial.sh
使用 Operator 清单和
istioctl
创建出站流量网关安装清单:${ISTIOCTL} manifest generate \ --filename egressgateway-operator.yaml \ --output egressgateway \ --cluster-specific
安装出站流量网关:
kubectl apply --recursive --filename egressgateway/
检查出站流量网关是否在
gateway
节点池中的节点上运行:kubectl get pods -n istio-egress -o wide
出站流量网关 pod 对
gateway
节点池中的节点具有affinity
以及使其在污点网关节点上运行的容忍设置。检查出站流量网关 pod 的节点亲和性和容忍设置:kubectl -n istio-egress get pod -l istio=egressgateway \ -o=custom-columns='name:metadata.name,node-affinity:spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms,tolerations:spec.tolerations[?(@.key=="dedicated")]'
输出内容类似如下:
name node-affinity tolerations istio-egressgateway-754d9684d5-jjkdz [map[matchExpressions:[map[key:cloud.google.com/gke-nodepool operator:In values:[gateway]]]]] map[key:dedicated operator:Equal value:gateway]
启用 Envoy 访问日志记录
启用 Envoy 访问日志所需的步骤取决于您的 Cloud Service Mesh 类型(代管式或集群内):
代管式
集群内
准备网格和测试应用
确保已启用 STRICT 双向 TLS。为
istio-system
命名空间中的网格应用默认的PeerAuthentication
政策:cat <<EOF | kubectl apply -f - apiVersion: "security.istio.io/v1beta1" kind: "PeerAuthentication" metadata: name: "default" namespace: "istio-system" spec: mtls: mode: STRICT EOF
您可以通过在特定命名空间中创建
PeerAuthentication
资源来替换此配置。创建用于部署测试工作负载的命名空间。本教程的后续步骤介绍了如何为每个命名空间配置不同的出站流量路由规则。
kubectl create namespace team-x kubectl create namespace team-y
为命名空间添加标签,以便 Kubernetes 网络政策可以进行选择:
kubectl label namespace team-x team=x kubectl label namespace team-y team=y
为了让 Cloud Service Mesh 自动注入代理 Sidecar,您需要 在工作负载命名空间上设置控制平面修订版本标签:
kubectl label ns team-x istio.io/rev- istio-injection=enabled --overwrite kubectl label ns team-y istio.io/rev- istio-injection=enabled --overwrite
创建用于进行测试部署的 YAML 文件:
cat << 'EOF' > ./test.yaml apiVersion: v1 kind: ServiceAccount metadata: name: test --- apiVersion: v1 kind: Service metadata: name: test labels: app: test spec: ports: - port: 80 name: http selector: app: test --- apiVersion: apps/v1 kind: Deployment metadata: name: test spec: replicas: 1 selector: matchLabels: app: test template: metadata: labels: app: test spec: serviceAccountName: test containers: - name: test image: gcr.io/google.com/cloudsdktool/cloud-sdk:slim command: ["/bin/sleep", "infinity"] imagePullPolicy: IfNotPresent EOF
将测试应用部署到
team-x
命名空间:kubectl -n team-x create -f ./test.yaml
验证测试应用已部署到默认池中的节点,并已注入代理 Sidecar 容器。重复以下命令,直到 pod 的状态为
Running
:kubectl -n team-x get po -l app=test -o wide
输出内容类似如下:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES test-d5bdf6f4f-9nxfv 2/2 Running 0 19h 10.1.1.25 gke-cluster1-default-pool-f6c7a51f-wbzj
两个容器均为
Running
状态。一个容器是测试应用,另一个是代理 Sidecar。pod 在默认节点池中的节点上运行。
验证是否无法从测试容器向外部网站发出 HTTP 请求:
kubectl -n team-x exec -it \ $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \ -c test -- curl -v http://example.com
由于
global-deny-egress-all
防火墙规则拒绝上游连接,因此边车代理会生成错误消息。
使用 Sidecar 资源限制 Sidecar 代理配置的范围
您可以使用 Sidecar 资源来限制为 Sidecar 代理配置的出站流量监听器的范围。为了减少配置臃肿和内存用量,最好为每个命名空间应用默认的 Sidecar
资源。
Cloud Service Mesh 在 Sidecar 中运行的代理是 Envoy。在 Envoy 术语中,cluster
是一组逻辑上相似的上游端点,用作负载均衡的目标。
运行
istioctl proxy-config
命令,检查 Envoy Sidecar 代理中为测试 pod 配置的出站集群:${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outbound
列表中大约有 11 个 Envoy 集群,包括一些用于出站流量网关的集群。
将代理配置限制为 使用服务条目明确定义 出站流量和
team-x
命名空间中。将Sidecar
资源应用于team-x
命名空间:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Sidecar metadata: name: default namespace: team-x spec: outboundTrafficPolicy: mode: REGISTRY_ONLY egress: - hosts: - 'istio-egress/*' - 'team-x/*' EOF
将出站流量政策模式设置为
REGISTRY_ONLY
会限制代理配置,使其仅包含通过定义服务条目明确添加到网格服务注册表的外部主机。设置
egress.hosts
会指定边车代理仅选择使用exportTo
属性提供的出站流量命名空间中的路由。“team-x/*
”部分包含在team-x
命名空间中本地配置的任何路由。查看在 Envoy Sidecar 代理中配置的出站集群,并将它们与应用
Sidecar
资源之前配置的集群列表进行比较:${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outbound
您会看到用于出站流量网关的集群和一个用于测试 pod 本身的集群。
配置 Cloud Service Mesh 以通过出站流量网关路由流量
为端口 80 上的 HTTP 流量配置
Gateway
。Gateway
用于选择您部署到出站流量命名空间的出站流量网关代理。Gateway
配置会应用于出站流量命名空间并处理任何主机的流量。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: egress-gateway namespace: istio-egress spec: selector: istio: egressgateway servers: - port: number: 80 name: https protocol: HTTPS hosts: - '*' tls: mode: ISTIO_MUTUAL EOF
使用双向 TLS 为出站流量网关创建
DestinationRule
以进行身份验证和加密。对所有外部主机使用一个共享目标规则。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: target-egress-gateway namespace: istio-egress spec: host: istio-egressgateway.istio-egress.svc.cluster.local subsets: - name: target-egress-gateway-mTLS trafficPolicy: tls: mode: ISTIO_MUTUAL EOF
在出站流量命名空间中创建一个
ServiceEntry
,以明确在网格的服务注册表中为team-x
命名空间注册 example.com:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: example-com-ext namespace: istio-egress labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: example.com spec: hosts: - example.com ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'team-x' - 'istio-egress' EOF
创建
VirtualService
,通过出站流量网关将流量路由到 example.com。有两个匹配条件:第一个条件将流量定向到出站流量网关,第二个条件将流量从出站流量网关定向到目标主机。exportTo
属性控制哪些命名空间可以使用虚拟服务。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: example-com-through-egress-gateway namespace: istio-egress spec: hosts: - example.com gateways: - istio-egress/egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 weight: 100 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: example.com port: number: 80 weight: 100 exportTo: - 'istio-egress' - 'team-x' EOF
运行
istioctl analyze
检查是否存在配置错误:${ISTIOCTL} analyze -n istio-egress --revision REVISION
输出内容类似如下:
✔ No validation issues found when analyzing namespace: istio-egress.
通过出站流量网关向外部网站发送多个请求:
for i in {1..4} do kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- \ curl -s -o /dev/null -w "%{http_code}\n" http://example.com done
您将看到全部 4 个响应的状态代码均为
200
。检查代理访问日志,以验证请求是否通过出站流量网关定向。首先查看随测试应用部署的代理 Sidecar 的访问日志:
kubectl -n team-x logs -f $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) istio-proxy
对于您发送的每个请求,您将看到类似于以下内容的日志条目:
[2020-09-14T17:37:08.045Z] "HEAD / HTTP/1.1" 200 - "-" "-" 0 0 5 4 "-" "curl/7.67.0" "d57ea5ad-90e9-46d9-8b55-8e6e404a8f9b" "example.com" "10.1.4.12:8080" outbound|80||istio-egressgateway.istio-egress.svc.cluster.local 10.1.0.17:42140 93.184.216.34:80 10.1.0.17:60326 - -
查看出站流量网关访问日志:
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath="{.items[0].metadata.name}") istio-proxy
对于您发送的每个请求,您将看到类似于以下内容的出站流量网关访问日志条目:
[2020-09-14T17:37:08.045Z] "HEAD / HTTP/2" 200 - "-" "-" 0 0 4 3 "10.1.0.17" "curl/7.67.0" "095711e6-64ef-4de0-983e-59158e3c55e7" "example.com" "93.184.216.34:80" outbound|80||example.com 10.1.4.12:37636 10.1.4.12:8080 10.1.0.17:44404 outbound_.80_.target-egress-gateway-mTLS_.istio-egressgateway.istio-egress.svc.cluster.local -
为第二个命名空间配置不同的路由
为第二个外部主机配置路由,以了解如何为不同的团队配置不同的外部连接。
为
team-y
命名空间创建Sidecar
资源:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Sidecar metadata: name: default namespace: team-y spec: outboundTrafficPolicy: mode: REGISTRY_ONLY egress: - hosts: - 'istio-egress/*' - 'team-y/*' EOF
将测试应用部署到
team-y
命名空间:kubectl -n team-y create -f ./test.yaml
注册第二个外部主机,并将其导出到
team-x
和team-y
命名空间:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: httpbin-org-ext namespace: istio-egress labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: httpbin.org spec: hosts: - httpbin.org ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'istio-egress' - 'team-x' - 'team-y' EOF
创建虚拟服务,通过出站流量网关将流量路由到 httpbin.org:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpbin-org-through-egress-gateway namespace: istio-egress spec: hosts: - httpbin.org gateways: - istio-egress/egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 weight: 100 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: httpbin.org port: number: 80 weight: 100 exportTo: - 'istio-egress' - 'team-x' - 'team-y' EOF
运行
istioctl analyze
检查是否存在配置错误:${ISTIOCTL} analyze -n istio-egress --revision REVISION
您可以看到以下信息:
✔ No validation issues found when analyzing namespace: istio-egress.
从
team-y
测试应用向 httpbin.org 发出请求:kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test -o \ jsonpath={.items..metadata.name}) -c test -- curl -I http://httpbin.org
您会看到
200 OK
响应。从
team-x
测试应用向 httpbin.org 发出请求:kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://httpbin.org
您会看到
200 OK
响应。尝试从
team-y
命名空间向 example.com 发出请求:kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
由于没有为
example.com
主机配置出站路由,因此请求失败。
使用授权政策进一步控制流量
在本教程中,出站流量网关的授权政策是在 istio-egress
命名空间中创建的。您可以配置 Kubernetes RBAC,使得只有网络管理员才能访问 istio-egress
命名空间。
创建
AuthorizationPolicy
,使team-x
命名空间中的应用在使用端口 80 发送请求时,可以连接到 example.com,但不能连接到其他外部主机。出站流量网关 pod 上的对应targetPort
是 8080。cat <<EOF | kubectl apply -f - apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: egress-team-x-to-example-com namespace: istio-egress spec: action: ALLOW rules: - from: - source: namespaces: - 'team-x' to: - operation: hosts: - 'example.com' when: - key: destination.port values: ["8080"] EOF
验证
team-x
命名空间中的测试应用能否向 example.com 发出请求:kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
您会看到
200 OK
响应。尝试从
team-x
命名空间中的测试应用向 httpbin.org 发出请求:kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -s -w " %{http_code}\n" \ http://httpbin.org
请求失败并显示
RBAC: access denied
消息和 403 禁止访问状态代码。您可能需要等待几秒钟,因为授权政策通常要延迟一会儿才能生效。通过授权政策,您可以方便地控制要允许或拒绝哪些流量。应用以下授权政策,允许
team-y
命名空间中的应用在使用端口 80 向 httpbin.org 发送请求时,使用一个特定的网址路径。出站流量网关 pod 上的对应targetPort
是 8080。cat <<EOF | kubectl apply -f - apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: egress-team-y-to-httpbin-teapot namespace: istio-egress spec: action: ALLOW rules: - from: - source: namespaces: - 'team-y' to: - operation: hosts: - httpbin.org paths: ['/status/418'] when: - key: destination.port values: ["8080"] EOF
尝试从
team-y
命名空间中的测试应用连接到 httpbin.org:kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -s -w " %{http_code}\n" \ http://httpbin.org
请求失败并显示 RBAC: access denied 消息和 403 禁止访问状态代码。
现在,从同一个应用向 httpbin.org/status/418 发出请求:
kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl http://httpbin.org/status/418
由于路径与授权政策中的格式匹配,因此请求成功。输出内容类似如下:
-=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
出站流量网关上的 TLS 源
您可以将出站流量网关配置为 upgrade
(发起)对 TLS 或双向 TLS 的纯文本 HTTP 请求。与 Istio 双向 TLS 和 TLS 发源结合使用时,允许应用发出纯文本 HTTP 请求有几个好处。如需了解详情,请参阅最佳实践指南。
创建
DestinationRule. The DestinationRule
,指定网关发起到 example.com 的 TLS 连接。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: example-com-originate-tls namespace: istio-egress spec: host: example.com subsets: - name: example-com-originate-TLS trafficPolicy: portLevelSettings: - port: number: 443 tls: mode: SIMPLE sni: example.com EOF
更新 example.com 的虚拟服务,以使对网关上的端口 80 的请求在发送到目标主机时
upgraded
为端口 443 上的 TLS:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: example-com-through-egress-gateway namespace: istio-egress spec: hosts: - example.com gateways: - mesh - istio-egress/egress-gateway http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: example.com port: number: 443 subset: example-com-originate-TLS weight: 100 EOF
从
team-x
命名空间中的测试应用向 example.com 发出多个请求:for i in {1..4} do kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com done
和之前一样,请求成功并返回
200 OK
响应。查看出站流量网关日志,验证网关通过发起 TLS 连接将请求路由到目标主机:
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath=" {.items[0].metadata.name}") istio-proxy
输出内容类似如下:
[2020-09-24T17:58:02.548Z] "HEAD / HTTP/2" 200 - "-" "-" 0 0 6 5 "10.1.1.15" "curl/7.67.0" "83a77acb-d994-424d-83da-dd8eac902dc8" "example.com" "93.184.216.34:443" outbound|443|example-com-originate-TLS|example.com 10.1.4.31:49866 10.1.4.31:8080 10.1.1.15:37334 outbound_.80_.target-egress-gateway-mTLS_.istio-egressgateway.istio-egress.svc.cluster.local -
代理 Sidecar 使用端口 80 将请求发送到网关,使用端口 443 上发起的 TLS 将请求发送到目标主机。
HTTPS/TLS 连接的直通
在与外部服务通信时,您的现有应用可能已经在使用 TLS 连接。您可以将出站流量网关配置为直通 TLS 连接,而不进行解密。
修改配置,以便出站流量网关对到端口 443 的连接使用 TLS 直通:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: egress-gateway namespace: istio-egress spec: selector: istio: egressgateway servers: - port: number: 80 name: https protocol: HTTPS hosts: - '*' tls: mode: ISTIO_MUTUAL - port: number: 443 name: tls protocol: TLS hosts: - '*' tls: mode: PASSTHROUGH EOF
更新指向出站流量网关的
DestinationRule
,以便为网关上的端口 443 添加第二个子集。这个新子集不使用双向 TLS。TLS 连接的直通不支持 Istio 双向 TLS。端口 80 上的连接仍使用 mTLS:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: target-egress-gateway namespace: istio-egress spec: host: istio-egressgateway.istio-egress.svc.cluster.local subsets: - name: target-egress-gateway-mTLS trafficPolicy: portLevelSettings: - port: number: 80 tls: mode: ISTIO_MUTUAL - name: target-egress-gateway-TLS-passthrough EOF
更新 example.com 的虚拟服务,使端口 443 上的 TLS 流量直通网关:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: example-com-through-egress-gateway namespace: istio-egress spec: hosts: - example.com gateways: - mesh - istio-egress/egress-gateway http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: example.com port: number: 443 subset: example-com-originate-TLS weight: 100 tls: - match: - gateways: - mesh port: 443 sniHosts: - example.com route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-TLS-passthrough port: number: 443 - match: - gateways: - istio-egress/egress-gateway port: 443 sniHosts: - example.com route: - destination: host: example.com port: number: 443 weight: 100 exportTo: - 'istio-egress' - 'team-x' EOF
更新 httpbin.org 的虚拟服务,使端口 443 上的 TLS 流量直通网关:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpbin-org-through-egress-gateway namespace: istio-egress spec: hosts: - httpbin.org gateways: - istio-egress/egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 weight: 100 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: httpbin.org port: number: 80 weight: 100 tls: - match: - gateways: - mesh port: 443 sniHosts: - httpbin.org route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-TLS-passthrough port: number: 443 - match: - gateways: - istio-egress/egress-gateway port: 443 sniHosts: - httpbin.org route: - destination: host: httpbin.org port: number: 443 weight: 100 exportTo: - 'istio-egress' - 'team-x' - 'team-y' EOF
添加授权政策,以接受发送到出站流量网关服务的端口 443 的任何类型的流量。网关 pod 上的对应
targetPort
是 8443。cat <<EOF | kubectl apply -f - apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: egress-all-443 namespace: istio-egress spec: action: ALLOW rules: - when: - key: destination.port values: ["8443"] EOF
运行
istioctl analyze
检查是否存在配置错误:${ISTIOCTL} analyze -n istio-egress --revision REVISION
您可以看到以下信息:
✔ No validation issues found when analyzing namespace: istio-egress.
从
team-x
命名空间中的测试应用向 example.com 发出纯文本 HTTP 请求:kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
请求成功并返回
200 OK
响应。现在,从
team-x
命名空间中的测试应用发出多个 TLS (HTTPS) 请求:for i in {1..4} do kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -s -o /dev/null \ -w "%{http_code}\n" \ https://example.com done
您会看到 200 响应。
再次查看出站流量网关日志:
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath="{.items[0].metadata.name}") istio-proxy
您会看到类似如下内容的日志条目:
[2020-09-24T18:04:38.608Z] "- - -" 0 - "-" "-" 1363 5539 10 - "-" "-" "-" "-" "93.184.216.34:443" outbound|443||example.com 10.1.4.31:51098 10.1.4.31:8443 10.1.1.15:57030 example.com -
HTTPS 请求被视为 TCP 流量,通过网关直通到目标主机,因此日志中不包含 HTTP 信息。
将 Kubernetes NetworkPolicy 用作额外控制措施
在很多情况下,应用可以绕过 Sidecar 代理。您可以使用 Kubernetes NetworkPolicy
额外指定工作负载可以建立的连接。应用单个网络政策后,未明确允许的所有连接都会被拒绝。
本教程仅考虑网络政策的出站连接和出站流量选择器。如果您在自己的集群上使用网络政策控制入站流量,则必须创建与出站政策对应的入站政策。例如,如果您允许从 team-x
命名空间中的工作负载到 team-y
命名空间的出站流量,则还必须允许从 team-x
命名空间到 team-y
命名空间的入站流量。
允许部署在
team-x
命名空间中的工作负载和代理连接到istiod
和出站流量网关:cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-control-plane namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": istio-system podSelector: matchLabels: istio: istiod - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": istio-egress podSelector: matchLabels: istio: egressgateway EOF
允许工作负载和代理查询 DNS:
cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-dns namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": kube-system ports: - port: 53 protocol: UDP - port: 53 protocol: TCP EOF
允许工作负载和代理连接到提供 Google API 和服务的 IP,包括 Cloud Service Mesh 证书授权机构:
cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-google-apis namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - ipBlock: cidr: 199.36.153.4/30 - ipBlock: cidr: 199.36.153.8/30 EOF
允许工作负载和代理连接到 GKE 元数据服务器:
cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-metadata-server namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: # For GKE data plane v2 - ipBlock: cidr: 169.254.169.254/32 - to: # For GKE data plane v1 - ipBlock: cidr: 127.0.0.1/32 # Prior to 1.21.0-gke.1000 - ipBlock: cidr: 169.254.169.252/32 # 1.21.0-gke.1000 and later ports: - protocol: TCP port: 987 - protocol: TCP port: 988 EOF
可选:允许
team-x
命名空间中的工作负载和代理相互连接:cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-same-namespace namespace: team-x spec: podSelector: {} ingress: - from: - podSelector: {} egress: - to: - podSelector: {} EOF
可选:允许
team-x
命名空间中的工作负载和代理连接到其他团队部署的工作负载:cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-team-y namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": team-y EOF
Sidecar 代理之间的连接会持久保留。当您应用新网络政策时,现有连接不会关闭。重启 team-x 命名空间中的工作负载以确保关闭现有连接:
kubectl -n team-x rollout restart deployment
验证是否仍然可以从
team-x
命名空间中的测试应用向 example.com 发出 HTTP 请求:kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
请求成功并返回
200 OK
响应。
使用专用 Google 访问通道和 IAM 权限直接访问 Google API
Google 的 API 和服务使用外部 IP 地址公开。当具有 VPC 原生别名 IP 地址的 pod 使用专用 Google 访问通道连接到 Google API 时,流量始终不会离开 Google 的网络。
为本教程设置基础架构时,您可以为 GKE pod 使用的子网启用专用 Google 访问通道。如需允许访问专用 Google 访问通道使用的 IP 地址,您可以创建路由、VPC 防火墙规则和专用 DNS 区域。此配置可让 pod 直接访问 Google API,无需通过出站流量网关发送流量。您可以使用 适用于 GKE 的工作负载身份联合和 IAM 来控制哪些 API 可用于特定 Kubernetes 服务账号(以及命名空间)。Istio 授权不会生效,因为出站流量网关不处理与 Google API 的连接。
您必须先使用 IAM 授予权限,然后 pod 才能调用 Google API。您在本教程中使用的集群已配置为使用适用于 GKE 的工作负载身份联合,允许 Kubernetes 服务账号充当 Google 服务账号。
为您的应用创建 Google 服务账号:
gcloud iam service-accounts create sa-test-app-team-x
允许 Kubernetes 服务账号模拟 Google 服务账号:
gcloud iam service-accounts add-iam-policy-binding \ --role roles/iam.workloadIdentityUser \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[team-x/test]" \ sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com
针对
team-x
命名空间中的测试应用,使用 Google 服务账号的电子邮件地址为 Kubernetes 服务账号添加注释。cat <<EOF | kubectl apply -f - apiVersion: v1 kind: ServiceAccount metadata: annotations: iam.gke.io/gcp-service-account: sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com name: test namespace: team-x EOF
测试应用 pod 必须能够访问 Google 元数据服务器(作为 DaemonSet 运行),以获取调用 Google API 的临时凭据。为 GKE 元数据服务器创建服务条目:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: metadata-google-internal namespace: istio-egress labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: metadata.google.internal spec: hosts: - metadata.google.internal ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'istio-egress' - 'team-x' EOF
另外,为 private.googleapis.com 和 storage.googleapis.com 创建服务条目:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: private-googleapis-com namespace: istio-egress labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: googleapis.com spec: hosts: - private.googleapis.com - storage.googleapis.com ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'istio-egress' - 'team-x' EOF
验证 Kubernetes 服务账号是否配置正确,可以充当 Google 服务账号:
kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- gcloud auth list
您会看到 Google 服务账号列为有效且唯一的身份。
在 Cloud Storage 存储桶中创建测试文件:
echo "Hello, World!" > /tmp/hello gcloud storage buckets create gs://${PROJECT_ID}-bucket gcloud storage cp /tmp/hello gs://${PROJECT_ID}-bucket/
向服务账号授予列出和查看存储桶中的文件的权限:
gcloud storage buckets add-iam-policy-binding gs://${PROJECT_ID}-bucket/ \ --member=serviceAccount:sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com \ --role=roles/storage.objectViewer
验证测试应用是否可以访问测试存储桶:
kubectl -n team-x exec -it \ $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \ -c test \ -- gcloud storage cat gs://${PROJECT_ID}-bucket/hello
您可以看到以下信息:
Hello, World!
清理
为避免因本教程中使用的资源导致您的 Google Cloud 账号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。
为避免系统因本教程中使用的资源向您的 Google Cloud 账号收取费用,请完成以下各部分中的步骤:
删除项目
为避免支付费用,最简单的方法是删除您为本教程创建的项目。
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
后续步骤
- 阅读配套最佳做法指南。
- 参阅 GKE 安全强化指南。
- 了解如何使用 CA Service 自动管理 Cloud Service Mesh 入站流量网关的 TLS 证书。
- 了解如何使用 GKE Enterprise Configuration Management 管理基础架构中的配置和政策。
- 如需查看更多参考架构、图表和最佳实践,请浏览云架构中心。