不幸的是,由于 Calico 的限制,GKE 不支持具有“开箱即用”的基于 DNS 名称的出口过滤的网络策略:基于 CIDR 的过滤不灵活且容易出错,并且不适用于外部资源。GitHub 上有一个功能请求DNSSelector
,日期为 2017 年,用于在 Kubernetes API中引入对新参数的支持。
目前,第三方解决方案 Cilium CNI 插件提供基于 DNS 的出口过滤。重要的是,它支持通配符。
简要步骤:
- 为当前项目启用 GKE API(如果尚未启用)。
- 构建一个没有网络策略支持的标准 3 节点 GKE 集群(带有
kubenet
)。
- 连接到新创建的 Kubernetes 集群。
- 在 GKE 中创建集群管理员绑定。
- 如有必要,为您的工作负载创建自定义命名空间。
- 如有必要,为外部资源创建无头服务。
- 运行 Busybox 容器以检查网络策略效果。
- 安装 Helm。
- 使用 Helm 部署 Cilium。
- 在应用网络策略之前检查外部资源的可用性。
- 创建和部署 Cilium 网络策略。
- 应用网络策略后检查外部资源的可用性。
在命名空间中创建第一个网络策略后,所有其他流量都会被拒绝。不需要无头服务类型ExternalName
,但如果您更喜欢使用它,通过此类服务的受限访问也可以。kube-dns
负责名称解析。网络策略授予对它的访问权限。
详细步骤:
- 为当前项目启用 GKE API(如果尚未启用)。
$ gcloud services enable --project "mylab" container.googleapis.com
- 构建一个没有网络策略支持的标准 3 节点 GKE 集群(带有
kubenet
)。一个参数--username
导致启用基本身份验证。
$ gcloud container --project "mylab" clusters create "standard-cluster-1" --username "admin" --zone "europe-west3-c"
- 连接到新创建的 Kubernetes 集群
$ gcloud auth list
$ gcloud auth login
$ gcloud container clusters get-credentials standard-cluster-1 --zone europe-west3-c --project mylab
$ kubectl config get-clusters
$ kubectl cluster-info`
- 在 GKE 中创建集群管理员绑定。
$ kubectl create clusterrolebinding cluster-admin-binding --clusterrole cluster-admin --user youraccount@google.com
- 为您的工作负载创建自定义命名空间
np-test
并为其添加标签:
$ kubectl create namespace np-test
$ kubectl label namespace/np-test namespace=np-test
$ kubectl get namespace/np-test --show-labels`
example.com
如果需要,为外部资源创建无头服务。
$ vi example-service.yaml
apiVersion: v1
kind: Service
metadata:
name: example-service
namespace: np-test
spec:
type: ExternalName
externalName: example.com
$ kubectl apply -f example-service.yaml
$ kubectl get services -n np-test
- 运行 Busybox 容器以检查网络策略效果。
$ vi busybox-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: busybox-pod
namespace: np-test
labels:
namespace: np-test
spec:
containers:
- image: radial/busyboxplus:curl
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox-container
restartPolicy: Always
$ kubectl create -f ./busybox-pod.yaml
$ kubectl get pods -n np-test --show-labels
- 在 CloudShell 实例或您正在使用的工作站上安装 Helm:
$ curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
$ chmod 700 get_helm.sh
$ ./get_helm.sh
$ helm version
- 使用 Helm 部署 Cilium。
$ curl -LO https://github.com/cilium/cilium/archive/1.6.5.tar.gz
$ tar xzvf 1.6.5.tar.gz
$ cd cilium-1.6.5/install/kubernetes
生成所需的 YAML 文件:
$ helm template cilium \
--namespace cilium \
--set global.nodeinit.enabled=true \
--set nodeinit.reconfigureKubelet=true \
--set nodeinit.removeCbrBridge=true \
--set global.cni.binPath=/home/kubernetes/bin \
> cilium.yaml
$ kubectl create namespace cilium
$ kubectl get namespaces
$ kubectl create -f cilium.yaml
重新启动命名空间中的所有 pod,kube-system
以便它们可以由 Cilium 管理:
$ kubectl delete pods -n kube-system $(kubectl get pods -n kube-system -o custom-columns=NAME:.metadata.name,HOSTNETWORK:.spec.hostNetwork --no-headers=true | grep '<none>' | awk '{ print $1 }')
$ kubectl -n cilium get pods
- 在应用网络策略之前,从 Busybox pod 中检查外部资源的可用性。
$ kubectl exec -n np-test busybox-pod -- curl -kL google.com
$ kubectl exec -n np-test busybox-pod -- curl -kL yahoo.com
$ kubectl exec -n np-test busybox-pod -- curl -kL example.com
$ kubectl exec -n np-test busybox-pod -- curl -kL -H 'host: example.com' example-service
$ kubectl exec -n np-test busybox-pod -- nslookup example.com
$ kubectl exec -n np-test busybox-pod -- nslookup example-service
请注意,它example-service
被解析为相同的IPexample.com
- 创建和部署 Cilium 网络策略。现在是时候限制从 Pod 到 Internet 的访问了,
example.com
只允许访问。
$ vi dns-policy.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "dns-policy"
namespace: np-test
spec:
endpointSelector:
matchLabels:
namespace: np-test
egress:
- toFQDNs:
- matchName: "example.com"
- toEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": kube-system
"k8s:k8s-app": kube-dns
toPorts:
- ports:
- port: "53"
protocol: ANY
rules:
dns:
- matchPattern: "*"
$ kubectl create -f dns-policy.yaml
$ kubectl get CiliumNetworkPolicy -n np-test
- 检查网络策略的效果。应用网络策略后,从 Busybox pod 中检查外部资源的可用性。
$ kubectl exec -n np-test busybox-pod -- ping -c 3 google.com
100% packet loss
$ kubectl exec -n np-test busybox-pod -- ping -c 3 yahoo.com
100% packet loss
$ kubectl exec -n np-test busybox-pod -- ping -c 3 example-service
0% packet loss
$ kubectl exec -n np-test busybox-pod -- ping -c 3 example.com
0% packet loss
$ kubectl exec -n np-test busybox-pod -- curl -kL google.com
Connection timed out
$ kubectl exec -n np-test busybox-pod -- curl -kL yahoo.com
Connection timed out
$ kubectl exec -n np-test busybox-pod -- curl -kL example.com
OK
$ kubectl exec -n np-test busybox-pod -- curl -kL -H 'host: example.com' example-service
OK
如您所见,Cilium 网络策略允许example.com
直接或通过无头服务访问,而对其他站点的访问受到限制。
这种方法允许在 GKE 上获得基于 DNS 名称的出口过滤。
以下链接提供了有关所描述解决方案的更多详细信息:
GKE:网络概览
Kubernetes 服务:无头服务
Kubernetes 服务:输入 ExternalName
Kubernetes 服务:DNS 入口
GKE:创建集群网络策略
Kubernetes:网络策略
带有 CIDRSelector 和 DNSSelector 的 NetworkPolicy Egress #50453
Kubernetes:声明网络策略
使用 Cilium 的开源 DNS 感知 Kubernetes 网络策略
在 Google GKE 上安装 Cilium
安装 Helm
Cilium:使用基于 DNS 的策略锁定外部访问