Kubernetes 网络介绍(四)
Networkpolicy
Kubernetes 的默认行为是允许集群网络中任意两个 Pod 之间的流量。这种行为是为了易于采用和配置灵活性而特意设计的选择,但在实践中是非常不受欢迎的。允许任何系统建立(或接收)任意连接会产生风险。攻击者可以探测系统,并可能利用捕获的凭据或发现削弱身份验证。允许任意连接还可以更轻松地通过受损的工作负载从系统中窃取数据。
总而言之,我们强烈建议不要在没有 NetworkPolicy 的情况下运行真正的集群。由于所有 Pod 都可以与所有其他 Pod 进行通信,因此我们强烈建议应用程序所有者将 NetworkPolicy 对象与其他应用程序层安全措施(例如身份验证令牌或相互传输层安全性 (mTLS))一起用于任何网络通信。
NetworkPolicy 是 Kubernetes 中的一种资源类型,包含基于允许的防火墙规则。用户可以添加 NetworkPolicy 对象来限制与 Pod 的连接。
NetworkPolicy 资源充当 CNI 插件的配置,其本身负责确保 Pod 之间的连接。Kubernetes API 声明 NetworkPolicy 支持对于 CNI 驱动程序是可选的,这意味着某些 CNI 驱动程序不支持网络策略,如表 4-3 所示。如果开发人员在使用不支持 NetworkPolicy 对象的 CNI 驱动程序时创建 NetworkPolicy,则不会影响 pod 的网络安全。某些 CNI 驱动程序(例如企业产品或公司内部 CNI 驱动程序)可能会引入其等效的 NetworkPolicy。某些 CNI 驱动程序对 NetworkPolicy 规范的“解释”也可能略有不同。
表 4-3。常见的 CNI 插件和 NetworkPolicy 支持
CNI plugin | NetworkPolicy supported |
---|---|
Calico | 是的,并且支持其他特定于插件的策略 |
Cilium | 是的,并且支持其他特定于插件的策略 |
Flannel | No |
Kubenet | No |
示例 4-4 详细介绍了一个 NetworkPolicy 对象,其中包含 Pod 选择器、入口规则和出口规则。该策略将应用于与选择器标签匹配的 NetworkPolicy 位于同一命名空间中的所有 Pod。选择器标签的这种使用与其他 Kubernetes API 一致:规范通过标签而不是名称或父对象来识别 pod。
例 4-4。NetworkPolicy的大致结构
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo
namespace: default
spec:
podSelector:
matchLabels:
app: demo
policyTypes:
- Ingress
- Egress
ingress: []
egress: []
# Not expanded
在深入了解 API 之前,我们先来看一个创建 NetworkPolicy 以减少某些 Pod 的访问范围的简单示例。假设我们有两个不同的组件:demo 和 demo-DB。由于图 4-7 中我们没有现有的 NetworkPolicy,因此所有 Pod 都可以与所有其他 Pod 进行通信(包括假设不相关的 Pod,未显示)。
图 4-7。没有 NetworkPolicy对象的Pod
让我们限制 demo-DB 的访问级别。如果我们创建以下选择 demo-DB pod 的 NetworkPolicy,那么 demo-DB pod 将无法发送或接收任何流量:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
在图 4-8 中,我们现在可以看到带有标签 app=demo 的 Pod 无法再创建或接收连接。
图 4-8。带有 app:demo-db 标签的 Pod 无法接收或发送流量 对于大多数工作负载(包括我们的示例数据库)来说,没有网络访问权限是不受欢迎的。我们的 demo-db 应该(仅)能够接收来自 demo pod 的连接。为此,我们必须向 NetworkPolicy 添加入口规则:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: demo
现在 demo-db pod 只能接收来自 demo pod 的连接。此外,demo-db pod 无法建立连接(如图 4-9 所示)。
图 4-9。带有 app:demo-db 标签的 Pod 无法创建连接,它们只能接收来自 app:demo pod 的连接
如果用户可能无意或恶意更改标签,他们就可以更改 NetworkPolicy 对象应用于所有 Pod 的方式。在我们之前的示例中,如果攻击者能够在同一命名空间中的 pod 上编辑 app: demo-DB 标签,我们创建的 NetworkPolicy 将不再适用于该 pod。同样,如果攻击者可以将标签 app: demo 添加到受感染的 pod 中,则他们可以从该命名空间中的另一个 pod 获得访问权限。
前面的例子只是一个例子;使用 Cilium,我们可以为 Golang Web 服务器创建这些 NetworkPolicy 对象。
Cilium 的网络策略示例
我们的 Golang Web 服务器现在连接到没有 TLS 的 Postgres 数据库。此外,如果没有 NetworkPolicy 对象,网络上的任何 Pod 都可以嗅探 Golang Web 服务器和数据库之间的流量,这是一个潜在的安全风险。下面将部署我们的 Golang Web 应用程序及其数据库,然后部署仅允许从 Web 服务器连接到数据库的 NetworkPolicy 对象。使用 Cilium 已安装的相同 KIND 集群,让我们使用以下 YAML 和 kubectl 命令部署 Postgres 数据库:
$ kubectl apply -f database.yaml
service/postgres created
configmap/postgres-config created
statefulset.apps/postgres created
在这里,我们将 Web 服务器作为 Kubernetes 部署部署到 KIND 集群:
$ kubectl apply -f web.yaml
deployment.apps/app created
要在集群网络内运行连接测试,我们将部署并使用 dnsu tils pod,它具有 ping 和 curl 等基本网络工具:
$ kubectl apply -f dnsutils.yaml
pod/dnsutils created
由于我们没有部署具有入口的服务,因此我们可以使用 kubectl portforward 来测试与 Web 服务器的连接:
kubectl port-forward app-5878d69796-j889q 8080:8080
现在,从我们的本地终端,我们可以访问我们的 API:
$ curl localhost:8080/
Hello
$ curl localhost:8080/healthz
Healthy
$ curl localhost:8080/data
Database Connected
让我们测试从其他 Pod 到集群内 Web 服务器的连接。为此,我们需要获取 Web 服务器 Pod 的 IP 地址:
$ kubectl get pods -l app=app -o wide
NAME READY STATUS RESTARTS AGE IP NODE
app-5878d69796-j889q 1/1 Running 0 87m 10.244.1.188 kind-worker3
现在我们可以从 dnsutils pod 测试与 Web 服务器的 L4 和 L7 连接:
$ kubectl exec dnsutils -- nc -z -vv 10.244.1.188 8080
10.244.1.188 (10.244.1.188:8080) open
sent 0, rcvd 0
现在我们可以从 dnsutils pod 测试与 Web 服务器的 L4 和 L7 连接:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
0
我们还可以在数据库 Pod 上进行测试。首先,我们必须检索数据库 pod 的 IP 地址 10.244.2.189。我们可以使用 kubectl 结合标签和选项来获取此信息:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
1
再次,让我们使用 dnsutils pod 测试通过默认端口 5432 与 Postgres 数据库的连接:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
2
由于没有网络策略,该端口开放供所有人使用。现在让我们用 Cilium 网络策略来限制这一点。以下命令部署网络策略,以便我们可以测试安全的网络连接。首先,我们将对数据库 Pod 的访问限制为仅 Web 服务器。应用仅允许从 Web 服务器 Pod 到数据库的流量的网络策略:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
3
Cilium 对象的 Cilium 部署创建了可以检索的资源,就像使用 kubectl 的 pod 一样。使用 kubectl describe ciliumnetworkpolicies.cilium.io l3-rule-app-to-db,我们可以看到有关通过 YAML 部署的规则的所有信息:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
4
应用网络策略后,dnsutils pod 无法再到达数据库 pod;我们可以在尝试从 dnsutils pod 到达数据库端口的超时中看到这一点:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
5
当 Web 服务器 Pod 仍然连接到数据库 Pod 时,/data 路由将 Web 服务器连接到数据库,并且 NetworkPolicy 允许这样做:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
6
现在让我们应用第 7 层策略。Cilium 具有第 7 层感知能力,因此我们可以阻止或允许 HTTP URI 路径上的特定请求。在我们的示例策略中,我们允许在 / 和 /data 上进行 HTTP GET,但不允许在 /healthz 上进行 HTTP GET;让我们测试一下:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
7
我们可以看到应用的策略就像 API 中的任何其他 Kubernetes 对象一样:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
8
正如我们所看到的,/ 和 /data 可用,但 /healthz 不可用,这正是我们对 NetworkPolicy 的期望:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
9
这些小例子展示了 Cilium 网络策略如何强大地加强集群内部的网络安全。我们强烈建议管理员选择支持网络策略的 CNI,并强制开发人员使用网络策略。网络策略是命名空间的,如果团队有类似的设置,集群管理员可以而且应该强制开发人员定义网络策略以增加安全性。我们使用了 Kubernetes API 的两个方面:标签和选择器;在下一节中,我们将提供更多有关如何在集群中使用它们的示例。
Selecting Pods
Pod 在被 NetworkPolicy选择之前不受限制。如果选择,CNI 插件仅当匹配规则允许时才允许 Pod 入口或出口。NetworkPol icy 有一个spec.policyTypes 字段,其中包含策略类型(入口或出口)列表。例如,如果我们选择一个具有 NetworkPolicy 的 Pod,该 Pod 列出了入口但没有列出出口,那么入口将受到限制,而出口则不会。
spec.podSelector 字段将指示将 NetworkPolicy 应用到哪些 pod。一个空的标签选择器。(podSelector: {}) 将选择命名空间中的所有 pod。
我们将很快更详细地讨论标签选择器。
NetworkPolicy 对象是命名空间对象,这意味着它们存在于并应用于特定的命名空间。仅当 Pod 与 NetworkPolicy 位于同一命名空间中时,spec .podSelector 字段才能选择 Pod。这意味着选择 app: demo 将仅适用于当前命名空间,并且具有标签 app: demo 的另一个命名空间中的任何 pod 将不受影响。
有多种解决方法可以实现默认防火墙行为,包括以下内容:
为每个命名空间创建一个全面拒绝所有的 NetworkPolicy 对象,这将要求开发人员添加额外的 NetworkPolicy 对象以允许所需的流量。
添加故意违反默认开放 API 行为的自定义 CNI 插件。多个 CNI 插件具有公开此类行为的附加配置。
创建准入策略以要求工作负载具有 NetworkPolicy。
NetworkPolicy 对象严重依赖标签和选择器;因此,让我们深入研究更复杂的示例。
标签选择器类型
Kubernetes 中的每个对象都有一个元数据字段,类型为 ObjectMeta。这为每种类型提供了相同的元数据字段,例如标签。标签是键值字符串对的映射:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: demo
0
LabelSelector 通过当前标签(或不存在标签)来标识一组资源。
Kubernetes 中很少有资源会通过名称引用其他资源。相反,大多数资源(NetworkPolicy 对象、服务、部署和其他 Kubernetes 对象)。使用与 LabelSelector 匹配的标签。LabelSelectors 还可以在 API 和 kubectl 调用中使用,并避免返回不相关的对象。LabelSelector 有两个字段:matchExpressions 和 matchLabels。空 LabelSelector 的正常行为是选择范围内的所有对象,例如与 NetworkPolicy 位于同一名称空间中的所有 pod。matchLabels 是两者中更简单的一个。matchLabels 包含键值对的映射。对于要匹配的对象,每个键都必须存在于该对象上,并且该键必须具有相应的值。matchLabels 通常带有一个键(例如,app=example-thing),对于选择器来说通常就足够了。在示例 4-5 中,我们可以看到一个匹配对象,它同时具有标签 color=purple 和标签 shape=square。
例 4-5。匹配标签示例
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: demo
1
matchExpressions 更强大,但也更复杂。它包含标签选择器要求的列表。为了使对象匹配,所有要求都必须为真。表 4-4 显示了 matchExpressions 的所有必需字段。
表 4-4。LabelSelectorRequirement字段
Field | Description |
---|---|
key | 此要求所比较的标签键。 |
operator | Exists、DoesNotExist、In、NotIn 之一。存在:如果存在带有键的标签,则匹配对象,无论值如何。NotExists:如果没有带有键的标签,则匹配对象。In:如果存在带有键的标签,并且值是提供的值之一,则匹配对象。NotIn:如果键没有标签,或者键的值不是提供的值之一,则匹配对象。 |
values | 相关键的字符串值列表。当运算符为 In 或 NotIn 时,它必须为空。当运算符为 Exists 或 NotExists 时,它不能为空。 让我们看一下 matchExpressions 的两个简单示例。示例 4-6 中显示了与之前的 matchLabels 示例等效的 matchExpressions。 |
例 4-6。匹配表达式示例 1
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: demo
2
示例 4-7 中的 matchExpressions 将匹配颜色不等于红色、橙色或黄色且带有形状标签的对象。
例 4-7。匹配表达式示例 2
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: demo
3
现在我们已经涵盖了标签,我们可以讨论规则了。确定匹配后,规则将强制执行我们的网络策略。
Rules
NetworkPolicy 对象包含不同的入口和出口配置部分,其中分别包含入口规则和出口规则的列表。NetworkPolicy 规则充当因在策略中选择 pod 而导致的默认阻止的例外情况或“允许列表”。规则不能阻止访问;他们只能添加访问权限。如果多个 NetworkPolicy 对象选择一个 Pod,则每个 NetworkPolicy 对象中的所有规则都适用。对于同一组 Pod 使用多个 NetworkPolicy 对象可能是有意义的(例如,在一个策略中声明应用程序限额,在另一个策略中声明基础设施限额,例如遥测导出)。但是,请记住,它们不需要是单独的 NetworkPolicy 对象,并且如果 NetworkPolicy 对象过多,可能会变得难以推理。
为了支持来自 Kubelet 的运行状况检查和活动检查,CNI 插件必须始终允许来自 pod 节点的流量。如果攻击者有权访问节点(即使没有管理员权限),就有可能滥用标签。攻击者可以欺骗节点的 IP,并以该节点的 IP 地址作为源发送数据包。
入口规则和出口规则是 NetworkPolicy API 中的离散类型(Network PolicyIngressRule 和 NetworkPolicyEgressRule)。然而,它们的功能结构是相同的。每个 NetworkPolicyIngressRule/NetworkPolicyEgress 规则都包含一个端口列表和一个 NetworkPolicyPeers 列表。NetworkPolicyPeer 有四种方式让规则引用网络实体:ipBlock、namespaceSelector、podSelector 及其组合。
ipBlock 对于允许进出外部系统的流量非常有用。它只能在规则中单独使用,无需命名空间选择器或 podSelector。ipBlock 包含一个 CIDR 和一个可选的 CIDR 除外。except CIDR 将排除子 CIDR(它必须在 CIDR 范围内)。在示例 4-8 中,我们允许来自 10.0.0.0 到 10.0.0.255 范围内的所有 IP 地址(不包括 10.0.0.10)的流量。示例 4-9 允许来自任何标记为 group:x 的命名空间中的所有 Pod 的流量。
例 4-8。允许流量示例 1
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: demo
4
例 4-9。允许流量示例 2
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: demo
5
在示例 4-10 中,我们允许来自任何标记为服务的命名空间中的所有 pod 的流量:x.. podSelector 的行为类似于我们之前讨论的 spec.podSelector 字段。
如果没有namespaceSelector,它会选择与NetworkPolicy位于同一命名空间中的pod。
示例 4-10。允许流量示例 3
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: demo
6
如果我们指定一个namespaceSelector和一个podSelector,则该规则会选择所有具有指定命名空间标签的命名空间中具有指定pod标签的所有pod。保持较小的命名空间范围是很常见的,并且安全专家强烈建议这样做。典型的命名空间范围是针对每个应用程序或服务组或团队的。示例 4-11 中显示了第四个选项,其中包含命名空间和 pod 选择器。此选择器的行为类似于命名空间和 pod 选择器的 AND 条件:pod 必须具有匹配的标签,并且位于具有匹配标签的命名空间中。
例 4-11。允许流量示例 4
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: demo
7
请注意,这是 API 中的一种不同类型,尽管 YAML 语法看起来非常相似。至于 to 和 from 部分可以有多个选择器,单个字符可以区分 AND 和 OR,因此在编写策略时要小心。
我们之前关于 API 访问的安全警告也适用于此。如果用户可以自定义其名称空间上的标签,则他们可以将另一个名称空间中的 NetworkPolicy 以非预期的方式应用于其名称空间。在我们之前的选择器示例中,如果用户可以在任意名称空间上设置标签组:监视,他们就有可能发送或接收不应该发送或接收的流量。如果相关网络策略只有一个名称空间选择器,则该名称空间标签足以匹配该策略。如果 NetworkPolicy 选择器中也有 pod 标签,则用户将需要设置 pod 标签以匹配策略选择。然而,在典型的设置中,服务所有者将授予该服务命名空间中 Pod 的创建/更新权限(直接在 Pod 资源上或通过部署等可定义 Pod 的资源间接授予)。
典型的 NetworkPolicy 可能如下所示:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: demo
8
在此示例中,我们 store 命名空间中的所有 pod 只能从标记为 app: frontend 的命名空间中标记为 app: frontend 的 pod 接收连接。这些 Pod 只能创建与命名空间中的 Pod 的连接,其中 Pod 和命名空间都具有 app:downstream-1 或 app:downstream-2。在每种情况下,仅允许流向端口 8080 的流量。最后,请记住,此策略不保证下游 1 或下游 2 的匹配策略(请参阅下一个示例)。接受这些连接并不排除针对我们命名空间中的 pod 的其他策略,但会添加额外的例外:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-db
namespace: default
spec:
podSelector:
matchLabels:
app: demo-db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: demo
9
尽管它们是“稳定”资源(即网络/v1 API 的一部分),但我们相信 NetworkPolicy 对象仍然是 Kubernetes 中网络安全的早期版本。
配置 NetworkPolicy 对象的用户体验有些粗糙,并且默认的开放行为是非常不受欢迎的。目前有一个工作组正在讨论 NetworkPolicy 的未来以及 v2 API 将包含哪些内容。
CNI 和部署它们的人员使用标签和选择器来确定哪些 Pod 受到网络限制。正如我们在前面的许多示例中所看到的,它们是 Kubernetes API 的重要组成部分,开发人员和管理员都必须全面了解如何使用它们。
NetworkPolicy 对象是集群管理员工具箱中的一个重要工具。
它们是 Kubernetes API 原生的唯一可用于控制内部集群流量的工具。下一篇,我们将讨论另一个重要工具,以便管理员可以了解它在集群内的工作方式:域名系统( DNS)。
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……
还没有评论,来说两句吧...