Kubernetes Egress 网络策略指南

做者:Viswajith Venugopal

翻译:Bach才云web

校对:bot才云)、星空下的文仔才云api

Kubernetes 中的网络策略用于指定 Pod 组之间以及其与外部网络端点之间的通讯,它就像是 Kubernetes 的防火墙。与大多数 Kubernetes 对象同样,网络策略很是灵活,功能也很强大。若是了解应用程序中服务的确切通讯模式,咱们就能够经过网络策略将通讯限制在咱们想要范围以内。数组

Ingress 与 Egress安全

网络策略可用于指定 Pod 的入口(Ingress)流量出口(Egress)流量,其规则以下:服务器

  • 若是容许集群外部网络端点到 Pod 的通信,那么该端点能够访问 Pod。
  • 若是容许 Pod 到集群外部网络端点的通信,那么 Pod 也能够访问该端点。
  • 若是 Pod(A)到 Pod(B)的流量被容许,那么流量能够经过 A 的出口以及 B 的入口。注意这是单向的,流量从 B 到 A,那么只能从 B 的出口到 A 的入口。

设置 Ingress网络

在完成入口网络策略的设置并成功运行后,咱们再设置出口网络策略。这样作的缘由有两个:首先,一次执行两项操做比较困难,并且咱们很难知道是因为入口仍是出口配置致使的网络链接失败;其次,出口网络策略一般更难以实施。限制出口可能会引起各类错误,从而影响应用程序运行。app

虽然肯定网络端点到 Pod 的通信很是简单,但要肯定 Pod 到网络端点的链接方式会比较复杂。之因此出现这一问题,这是由于:ssh

  • 做为常规功能的一部分,Deployment 一般会查询一堆外部服务,根据它们在访问这些服务时处理超时的方式,功能可能会受到一些细微而又难以观察的影响。
  • Deployment 须要可以与 DNS 服务器通讯,以便和其余任何服务器通讯,除非这些服务器直接经过 IP 与服务联系。

对 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 教程以及更多的网络策略配置。

原文请点击:https://mp.weixin.qq.com/s/0F...

相关文章
相关标签/搜索