做者:Viswajith Venugopal
Kubernetes 中的网络策略用于指定 Pod 组之间以及其与外部网络端点之间的通讯,它就像是 Kubernetes 的防火墙。与大多数 Kubernetes 对象同样,网络策略很是灵活,功能也很强大。若是了解应用程序中服务的确切通讯模式,咱们就能够经过网络策略将通讯限制在咱们想要范围以内。数组
Ingress 与 Egress安全
网络策略可用于指定 Pod 的入口(Ingress)流量和出口(Egress)流量,其规则以下:服务器
设置 Ingress网络
在完成入口网络策略的设置并成功运行后,咱们再设置出口网络策略。这样作的缘由有两个:首先,一次执行两项操做比较困难,并且咱们很难知道是因为入口仍是出口配置致使的网络链接失败;其次,出口网络策略一般更难以实施。限制出口可能会引起各类错误,从而影响应用程序运行。app
虽然肯定网络端点到 Pod 的通信很是简单,但要肯定 Pod 到网络端点的链接方式会比较复杂。之因此出现这一问题,这是由于:ssh
对 Pod Egress 进行隔离学习
每一个网络策略都有一个 podSelector 字段,该字段会选择一组(0 个或多个)Pod。当网络策略选择了一个 Pod 时,就称该网络策略适用于该 Pod。 spa
此外,每一个网络策略均可以根据 policyTypes 字段的值应用于入口和出口。若是 YAML 中未指定此字段,它的值会基于策略中的入口、出口规则默认设置,但默认设置并不靠谱,咱们最好进行明确的设置。
通常状况下,若是没有任何出口网络策略适用于 Pod,那么它就是非隔离的出口。这里要注意,隔离是针对入口和出口独立评估的。一个 Pod 的入口和出口能够都隔离,也能够都不隔离,甚至进行单个隔离。若是一个 Pod 的出口没有进行隔离,那么全部的流量均可以从这个 Pod 中出来。
当一个出口网络策略适用于某个 Pod 时,该 Pod 的出口就会被隔离。对于隔离的 Pod,只有在网络策略容许的状况下,才容许网络出口,也就是网络策略白名单。
设置出口网络策略的第一步是对 Pod 进行出口隔离。咱们最好先应用“默认拒绝全部”的策略,将全部 Pod 的出口都隔离了。
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-all-egress spec: podSelector: {} egress: - to: ports: - protocol: TCP port: 53 - protocol: UDP port: 53 policyTypes: - Egress
不过要注意,默认状况下这个策略容许流量链接到任意 IP 上的 53 端口,以方便 DNS 查找。所以,尽管它能够防止出口出现问题,但不能防止数据泄露,由于攻击者能够将数据发送到 53 端口。
若是想知道 Pod 使用的是哪些 DNS 服务器,咱们能够经过缩小访问范围进行肯定。例如,要将 DNS 范围缩小到仅提供 kube-dns 服务,能够执行如下操做:
标记 kube-system 命名空间:
kubectl label namespace kube-system networking/namespace=kube-system
应用如下网络策略:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-all-egress spec: podSelector: {} egress: - to: - namespaceSelector: matchLabels: networking/namespace: kube-system podSelector: matchLabels: k8s-app: kube-dns ports: - protocol: TCP port: 53 - protocol: UDP port: 53 policyTypes: - Egress
重要提示:因为网络策略是带命名空间资源,所以每一个命名空间都须要建立此策略。咱们能够运行如下命令:
kubectl -n <namespace> create -f <filename>
另外,最好不要将其应用于 kube-system 命名空间,由于它可能会影响集群功能。
明确 Pod 到互联网的出口
在每一个命名空间中都采用了 default-deny-all-egress (默认拒绝全部出口)策略后,Pod 将没法链接到互联网,可是在大多数的应用程序中,会有一些 Pod 须要链接到互联网。对此,有一种设置方法:为容许链接互联网的 Pod 指定标签,并建立一个针对这些标签的网络策略。例如,如下网络策略容许具备 networking/allow-internet-egress=true 标签的 Pod 发送流量至全部网络端点(包括集群外部的端点)。另外,仍是要注意,咱们必须为每一个命名空间建立该策略:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: internet-egress spec: podSelector: matchLabels: networking/allow-internet-egress: "true" egress: - {} policyTypes: - Egress
这个策略比默认设置具备更高的安全性。不过对于更严格的策略集,理想状况下最好指定更细粒度的 CIDR 块,并明确列出容许的端口和协议。
明确 Pod 间的点对点通讯
若是将 Pod 隔离,而后明确 Pod 到 Pod 之间的通讯以后,在应用正常工做时,咱们会发现,在使用 default-deny-all-egress 策略后,全部的通讯都被限制了。对此,咱们在入口方向上将每一个链接放入白名单后,还须要把出口方向上的链接也放入白名单。不管是遵循上面的建议,容许全部名称空间内部通讯,仍是将各个 Pod 之间的链接列入白名单,或者采用自定义的方法,对于构建的每一个入口策略,都须要制定相应的出口策略。
补充出口网络策略
对于从一组 Pod 到另外一组 Pod 之间进行通讯的入口策略,构建对应的出口策略很是简单。首先,将 policyTypes 字段更改成仅包含 Egress 的数组,将 spec.podSelector 放在 spec.egress.to.podSelector 中,删除 ingress.from,并将从中提取的 ingress.from.podSelector 放到新的出口策略 spec.podSelector 中。这样就完成了命名空间内的一个入口策略。
至于跨命名空间的策略,若是已经用 network/namespace: 用标签标记了每一个命名空间:
kubectl label namespace <name> networking/namespace=<name>
那么,咱们须要在入口策略中选择 ingress.from.namespaceselector 的命名空间做为出口策略的 metadata.namespace,并将在入口策略的 metadata.namespace 中指定的命名空间,放到出口策略的 egress.to.namespaceSelector 字段中。
这是一个例子:
最后,上述建议仅仅提供了一个学习网络策略的起点,实际上它会复杂得多。若是想更详细地对它们进行了解,最好多多查看 Kubernetes 教程以及更多的网络策略配置。