本教程介绍如何使用 Anthos Service Mesh 出站流量网关和其他 Google Cloud 控制措施保护来自 Google Kubernetes Engine 集群上部署的工作负载的出站流量。本教程是最佳做法指南的配套教程。
本教程的目标受众包括管理由一个或多个软件交付团队使用的 Google Kubernetes Engine 集群的网络、平台和安全工程师。对于必须展示其遵从了法规(例如 GDPR 和 PCI)的组织,此处介绍的控制措施尤为有用。
目标
- 设置运行 Anthos Service Mesh 的基础架构:
- 自定义 VPC 网络和专用子网
- 用于互联网访问的 Cloud NAT
- 专用 GKE 集群,具有用于出站流量网关 pod 的额外节点池
- 受限出站流量 VPC 防火墙规则;只有网关节点可以访问外部主机
- 用于连接到 Container Registry 和 Google API 的 专用 Google 访问通道
- 安装 Anthos Service Mesh,并使出站流量网关在专用节点池中运行。
- 为通过出站流量网关的外部流量配置多租户路由规则:
- 命名空间“team-x”中的应用可以连接到 example.com
- 命名空间“team-y”中的应用可以连接到 httpbin.org
- 使用
Sidecar
资源限制每个命名空间的边车代理出站流量配置的范围。 - 配置授权政策以强制执行出站规则。
- 配置出站流量网关,将纯文本 HTTP 请求升级为 TLS(TLS 源)。
- 配置出站流量网关以直通 TLS 流量。
- 设置 Kubernetes 网络政策作为额外的出站流量控制措施。
- 使用专用 Google 访问通道和 Identity and Access Management (IAM) 权限配置对 Google API 的直接访问。
费用
在本文档中,您将使用 Google Cloud 的以下收费组件:
- Compute Engine
- Google Kubernetes Engine (GKE)
- Container Registry
- Anthos Service Mesh
- Cloud Load Balancing
- Cloud NAT
- 网络
- Cloud Storage
您可使用价格计算器根据您的预计使用情况来估算费用。
完成本教程后,您可以删除所创建的资源以避免持续产生费用。如需了解详情,请参阅清理。
准备工作
-
In the Google Cloud console, on the project selector page, select or create a 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
将脚本设为可执行文件,并使用
source
命令运行该脚本来初始化您的环境:chmod +x ./init-egress-tutorial.sh source ./init-egress-tutorial.sh
设置所需的 Identity and Access Management (IAM) 角色。如果您是 Project Owner,则拥有完成安装所需的全部权限。如果您不是 Project Owner,请让管理员授予您以下 IAM 角色。在以下命令中,将 PROJECT_EMAIL_ADDRESS 更改为您用于登录 Google Cloud 的账号。
gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member user:PROJECT_EMAIL_ADDRESS \ --role=roles/editor \ --role=roles/compute.admin \ --role=roles/container.admin \ --role=roles/resourcemanager.projectIamAdmin \ --role=roles/iam.serviceAccountAdmin \ --role=roles/iam.serviceAccountKeyAdmin \ --role=roles/gkehub.admin \ --role=roles/serviceusage.serviceUsageAdmin
启用本教程所需的 API:
gcloud services enable \ dns.googleapis.com \ container.googleapis.com \ compute.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 \ cloudresourcemanager.googleapis.com \ stackdriver.googleapis.com
启用 API 可能需要 1 分钟或更长时间才能完成。启用这些 API 后,您将会看到如下所示的输出:
Operation "operations/acf.601db672-88e6-4f98-8ceb-aa3b5725533c" finished successfully.
设置基础架构
创建 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 \ --destination-ranges 10.5.0.0/28 \ --network vpc-network \ --priority 1000 \ --description "Allow nodes to reach the Kubernetes API server."
在将 Sidecar 代理注入工作负载时,Anthos Service Mesh 使用网络钩子。允许 GKE API 服务器调用节点上运行的服务网格控制平面公开的网络钩子:
gcloud compute firewall-rules create allow-ingress-api-server-to-webhook \ --action ALLOW \ --direction INGRESS \ --rules tcp:15017 \ --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 会自动创建相应的入站流量规则。
gcloud compute firewall-rules create allow-egress-pods-and-services \ --action ALLOW \ --direction EGRESS \ --rules all \ --destination-ranges 10.1.0.0/16,10.2.0.0/20 \ --network vpc-network \ --priority 1000 \ --description "Allow pods and services on nodes to reach each other"
名为 Calico 的服务为 GKE 提供
NetworkPolicy
API 功能。允许在子网内连接 Calico:gcloud compute firewall-rules create allow-egress-calico \ --action ALLOW \ --direction EGRESS \ --rules tcp:5473 \ --destination-ranges 10.0.0.0/24 \ --network vpc-network \ --priority 1000 \ --description "Allow Calico Typha within the subnet"
GKE 需要 kubelet 只读端口才能读取节点指标。允许在子网内对其进行访问:
gcloud compute firewall-rules create allow-egress-kubelet-readonly \ --action ALLOW \ --direction EGRESS \ --rules tcp:10255 \ --destination-ranges 10.0.0.0/24 \ --network vpc-network \ --priority 1000 \ --description "Allow access to the kubelet read-only port within the subnet"
允许访问专用 Google 访问通道用于提供 Google API、Container Registry 和其他服务的预留 IP 地址集:
gcloud compute firewall-rules create allow-egress-gcp-apis \ --action ALLOW \ --direction EGRESS \ --rules tcp \ --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 \ --source-ranges 130.211.0.0/22,35.191.0.0/16,35.191.0.0/16,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 网络。
创建一个专用 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
创建专用 GKE 集群:
gcloud container clusters create cluster1 \ --enable-ip-alias \ --enable-private-nodes \ --release-channel "regular" \ --no-enable-basic-auth \ --no-issue-client-certificate \ --enable-master-authorized-networks \ --master-authorized-networks ${SHELL_IP//\"}/32 \ --master-ipv4-cidr 10.5.0.0/28 \ --enable-network-policy \ --service-account "sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \ --machine-type "e2-standard-4" \ --num-nodes "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。
Anthos Service Mesh 要求集群节点使用至少具有 4 个 vCPU 的机器类型。Google 建议将集群订阅到“常规”发布渠道,以确保节点运行的是 Anthos Service Mesh 支持的 Kubernetes 版本。如需了解详情,请参阅 Anthos Service Mesh 安装指南。
集群启用了 Workload Identity。Anthos Service Mesh 需要 Workload Identity,这也是从 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]
安装和设置 Anthos Service Mesh
本教程使用 Anthos Service Mesh 的可选功能。如需了解如何使用脚本安装 Anthos Service Mesh,请参阅文档中的安装指南。
为要在其中部署的服务网格控制层面和出站流量网关创建命名空间:
kubectl create ns istio-system kubectl create ns istio-egress
为 istio-egres、istio-system 和 kube-system 命名空间添加标签:
kubectl label ns istio-egress istio=egress istio-injection=disabled kubectl label ns istio-system istio=system kubectl label ns kube-system kube-system=true
这些标签稍后用于应用 Kubernetes NetworkPolicy。运行
istioctl
分析时,istio-injection=disabled
标签可防止虚假警告。使用 Istio OperatorAPI 创建清单文件以自定义 Anthos Service Mesh 安装:
cat << 'EOF' > ./asm-custom-install.yaml apiVersion: install.istio.io/v1alpha1 kind: IstioOperator metadata: name: "egress-gateway" spec: meshConfig: accessLogFile: "/dev/stdout" components: egressGateways: - name: "istio-egressgateway" enabled: true namespace: "istio-egress" label: istio: "egress" k8s: tolerations: - key: "dedicated" operator: "Equal" value: "gateway" nodeSelector: cloud.google.com/gke-nodepool: "gateway" EOF
此文件作为安装脚本的参数提供,它指定以下配置:
- 运行在
istio-egress
命名空间中的入站流量网关部署具有容忍和 nodeSelector,因此它只能在gateway
节点上运行。 - 可以访问所有 Sidecar 代理发送到“stdout”的日志记录。
- 运行在
下载安装脚本:
curl -O https://storage.googleapis.com/csm-artifacts/asm/install_asm
让该脚本可执行:
chmod +x install_asm
运行以下脚本安装 Anthos Service Mesh:
./install_asm \ --mode install \ --project_id ${PROJECT_ID} \ --cluster_name cluster1 \ --cluster_location ${ZONE} \ --custom_overlay ./asm-custom-install.yaml \ --output_dir ./ \ --enable_all
脚本完成后,设置一个环境变量来保存
istioctl
工具的路径,并将其添加到初始化脚本中:ISTIOCTL=$(find "$(pwd -P)" -name istioctl) echo "ISTIOCTL=\"${ISTIOCTL}\"" >> ./init-egress-tutorial.sh
验证 Anthos Service Mesh 安装
检查 Anthos Service Mesh 控制层面组件是否在
istio-system
命名空间中运行:kubectl get pod -n istio-system
您会看到
istio-ingressgateway
和istiod-asm
pod 在运行。检查出站流量网关 pod 是否在
istio-egress
命名空间中和gateway
节点池中的节点上运行:kubectl get pods -n istio-egress -o wide
出站流量网关 pod 具有用于选择
gateway
节点池中节点的nodeSelector
以及使其在污点网关节点上运行的容忍。检查出站流量网关 pod 的 nodeSelector 和容忍:kubectl -n istio-egress get pod -l app=istio-egressgateway \ -o=custom-columns='name:metadata.name,nodeSelector:spec.nodeSelector,\ tolerations:spec.tolerations[?(@.key=="dedicated")]'
输出类似于以下内容:
name nodeSelector tolerations istio-egressgateway-74687946f5-dg9mp map[cloud.google.com/gke-nodepool:gateway] map[key:dedicated operator:Equal value:gateway]
准备网格和测试应用
确保已启用 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
为了使 Anthos Service Mesh 自动注入代理 Sidecar,您必须在工作负载命名空间上设置修订版本标签。修订版本标签必须与已部署到集群的 Anthos Service Mesh 控制层面的修订版本匹配。在
istiod
pod 上查找修订版本标签,并将其存储在环境变量中:REVISION_LABEL=$(kubectl get pod -n istio-system -l app=istiod \ -o jsonpath='{.items[0].metadata.labels.istio\.io/rev}')
在
team-x
和team-y
命名空间上设置修订版本标签:kubectl label ns team-x istio.io/rev=${REVISION_LABEL} kubectl label ns team-y istio.io/rev=${REVISION_LABEL}
创建用于进行测试部署的 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
资源。
Anthos Service Mesh 在 Sidecar 中运行的代理是 Envoy。在 Envoy 术语中,cluster
是一组逻辑上相似的上游端点,用作负载均衡的目标。
运行
istioctl proxy-config
命令,检查 Envoy 边车代理中为测试 pod 配置的出站集群:${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outbound
列表中大约有 20 个 Envoy 集群,包括多个用于出站流量网关的集群。
将代理配置限制为在
istio-egress
和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
会限制代理配置,使其仅包含通过定义服务条目明确添加到网格服务注册表的外部主机。“
istio-egress/*
”部分指定边车代理选择来自istio-egress
命名空间(使用exportTo
属性提供)的路由。“team-x/*
”部分包含在team-x
命名空间中本地配置的任何路由。查看在 Envoy 边车代理中配置的出站集群,并将它们与应用
Sidecar
资源之前配置的集群列表进行比较:${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outbound
输出中仅包含少量用于出站流量网关的集群和一个用于测试 pod 本身的集群。
配置 Anthos Service Mesh 以通过出站流量网关路由流量
为端口 80 上的 HTTP 流量配置
Gateway
。Gateway
会选择安装程序部署到istio-egress
命名空间的istio-egressgateway
代理。Gateway
配置应用于istio-egress
命名空间并处理任何主机的流量。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: egress-gateway namespace: istio-egress spec: selector: istio: egress 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: loadBalancer: simple: ROUND_ROBIN tls: mode: ISTIO_MUTUAL EOF
在
istio-egress
命名空间中创建一个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 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
输出类似于以下内容:
✔ 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=egress \ -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 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
您可以看到以下信息:
✔ 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: 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: 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 源
您可以将出站流量网关配置为将纯文本 HTTP 请求“升级”(发起)为 TSL。与 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: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 443 tls: mode: SIMPLE sni: example.com EOF
更新 example.com 的虚拟服务,在向目标主机发送请求时,发送到端口 80 的请求在网关上“升级”为端口 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=egress \ -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: egress 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: loadBalancer: simple: ROUND_ROBIN 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: rules: - when: - key: destination.port values: ["8443"] EOF
运行
istioctl analyze
检查是否存在配置错误:${ISTIOCTL} analyze -n istio-egress
您可以看到以下信息:
✔ 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=egress \ -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 用作额外控制措施
在很多情况下,应用可以绕过边车代理。您可以使用 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: istio: system podSelector: matchLabels: istio: istiod - namespaceSelector: matchLabels: istio: egress podSelector: matchLabels: istio: egress 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: kube-system: "true" ports: - port: 53 protocol: UDP - port: 53 protocol: TCP EOF
允许工作负载和代理连接到提供 Google API 和服务的 IP,包括 Mesh CA:
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 ports: - 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: 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,无需通过出站流量网关发送流量。您可以使用 Workload Identity 和 IAM 来控制哪些 API 可用于特定 Kubernetes 服务账号(以及命名空间)。Istio 授权不会生效,因为出站流量网关不处理与 Google API 的连接。
您必须先使用 IAM 授予权限,然后 pod 才能调用 Google API。您在本教程中使用的集群已配置为使用 Workload Identity,允许 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 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 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 gsutil mb gs://${PROJECT_ID}-bucket gsutil cp /tmp/hello gs://${PROJECT_ID}-bucket/
向服务账号授予列出和查看存储桶中的文件的权限:
gsutil iam ch \ serviceAccount:sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com:objectViewer \ gs://${PROJECT_ID}-bucket/
验证测试应用是否可以访问测试存储桶:
kubectl -n team-x exec -it \ $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \ -c test \ -- gsutil 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 安全强化指南。
- 了解如何使用 GKE Enterprise Configuration Management 管理基础架构中的配置和政策。
- 如需查看更多参考架构、图表和最佳做法,请浏览云架构中心。