WEBKT

Kubernetes旧服务迁移:Calico强制性策略与多层级网络访问控制

44 0 0 0

在将遗留服务迁移到Kubernetes集群的过程中,网络安全无疑是核心关注点之一。我们不仅需要确保新旧服务之间的安全通信,更需要建立一套健壮、强制性的安全策略,防止任何未经授权的访问。特别是对于敏感资源如数据库集群,必须严格限制其访问源。用户提出的需求是定义一套全集群生效的强制性策略,例如只允许内部IP访问数据库集群,并且任何命名空间下的 NetworkPolicy 都不能“放宽”这个限制。同时,团队又能在这一基线之上,为自己的应用定义更具体的访问规则,例如特定端口的通信。

Calico作为Kubernetes环境中广泛使用的网络插件,其强大的网络策略管理能力,特别是策略优先级(Policy Order)机制,正是解决这一问题的理想方案。

Calico的网络策略模型概览

Calico提供了两种主要的网络策略类型:

  1. GlobalNetworkPolicy (GNP):全局网络策略,不限于特定命名空间,可以作用于整个集群。GNP通常用于定义集群范围内的安全基线或跨命名空间的策略。
  2. NetworkPolicy (NP):命名空间网络策略,作用于其所在的命名空间内部。NP通常用于团队或应用开发者为其服务定义细粒度的访问控制。

这两种策略都可以定义 Ingress(入站)和 Egress(出站)规则,通过 selector 匹配目标 Pod。关键在于,Calico允许为这些策略设置优先级,这就是实现层级管理的关键。

如何通过Calico策略优先级实现强制性基线

Calico策略的执行顺序是根据其 order 字段来决定的,order 值越小,优先级越高。策略的 action 字段(AllowDenyLogPass)决定了流量的处理方式。

要实现“强制性策略不能被放宽”的需求,我们可以遵循以下原则:

  1. 为强制性基线策略设置更高的优先级(更小的 order 值):使用 GlobalNetworkPolicy 来定义这些不可逾越的规则,并赋予它们一个非常小的 order 值(例如 50 或更小)。
  2. 为命名空间策略设置较低的优先级(更大的 order 值):团队定义的 NetworkPolicy 应该具有比基线策略更大的 order 值(例如 100 或更大)。

当流量通过时,Calico会从优先级最高的策略开始评估。一旦某个策略匹配到流量并设置了 action (例如 DenyAllow),则后续优先级较低的策略将不会再对该流量生效。这意味着,如果一个高优先级的 GlobalNetworkPolicy 拒绝了某个流量,那么即使低优先级的 NetworkPolicy 允许该流量,它也会被拒绝。

实践方案:强制性数据库访问限制与团队自定义规则

步骤一:定义强制性数据库访问基线(GlobalNetworkPolicy)

假设我们有一个数据库集群,只允许特定内部网络或特定命名空间(例如 backend-services 命名空间)的Pod访问。所有其他来源的访问都将被拒绝。

强制性策略YAML示例 (GlobalNetworkPolicy):

apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: deny-db-access-from-external
spec:
  order: 50 # 优先级很高,数字越小优先级越高
  selector: app == "my-database" # 匹配数据库Pod的标签
  types:
  - Ingress
  ingress:
  - action: Allow # 允许来自特定命名空间的访问
    source:
      selector: project == "internal-service" # 假设内部服务的Pod都有这个标签
    destination:
      ports:
      - 5432 # 数据库端口,例如PostgreSQL
  - action: Allow # 允许来自特定Pod的访问,例如后端服务
    source:
      selector: app == "backend-app" # 允许标记为后端应用的Pod访问
      namespaceSelector: name == "backend-services" # 且在backend-services命名空间中
    destination:
      ports:
      - 5432
  - action: Deny # 拒绝所有其他对数据库端口的入站连接
    destination:
      ports:
      - 5432

解释:

  • order: 50:赋予该策略较高的优先级,确保它在其他 NetworkPolicy 之前被评估。
  • selector: app == "my-database":此策略应用于所有带有 app: my-database 标签的Pod。
  • 第一个 action: Allow:允许所有带有 project: internal-service 标签的Pod访问数据库的5432端口。这可以是一个集群范围的内部服务标记。
  • 第二个 action: Allow:允许 backend-services 命名空间中带有 app: backend-app 标签的Pod访问数据库的5432端口。
  • 最后一个 action: Deny:这是一个“隐式拒绝”之前的“显式允许”之后的默认拒绝。任何不符合前两条 Allow 规则的对数据库5432端口的入站流量都将被拒绝。

部署这个 GlobalNetworkPolicy 后,除非明确被该策略的 Allow 规则匹配,否则任何Pod(包括其他命名空间下的Pod)都无法访问数据库的5432端口。

步骤二:团队定义更具体的应用访问规则(NetworkPolicy)

在上述强制性策略生效的基础上,团队可以为其在 backend-services 命名空间中的 backend-app 定义更具体的访问规则。例如,他们可能需要允许来自特定前端服务(frontend-app)的Pod访问其 backend-app 的8080端口。

团队自定义策略YAML示例 (NetworkPolicy):

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: backend-services # 此策略仅作用于backend-services命名空间
spec:
  podSelector:
    matchLabels:
      app: backend-app # 匹配backend-services命名空间内的backend-app Pod
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend-app # 允许来自带有app: frontend-app标签的Pod的连接
      namespaceSelector:
        matchLabels:
          name: frontend-services # 且该Pod在frontend-services命名空间中
    ports:
    - protocol: TCP
      port: 8080 # 允许访问backend-app的8080端口

解释:

  • 这是一个标准的Kubernetes NetworkPolicy,它只在 backend-services 命名空间中生效。
  • 它允许 frontend-services 命名空间中带有 app: frontend-app 标签的Pod访问 backend-services 命名空间中 app: backend-app 的8080端口。
  • 请注意,NetworkPolicy 没有 order 字段。在Calico中,NetworkPolicy 默认的 order 值通常比 GlobalNetworkPolicy 的默认值要大(优先级更低)。具体的默认值取决于Calico的配置,但通常 GlobalNetworkPolicyorder 默认是 0,而 NetworkPolicyorder 默认是 1000。我们上面将GNP的 order 设置为 50,远低于NP的默认值,确保其优先级更高。

Calico策略优先级如何工作

当Pod之间发生通信时,Calico会按照以下顺序评估策略:

  1. Ingress/Egress Pre-DNAT Policy (由 GlobalNetworkPolicy 定义,order 值非常低,如 -1000-100,在DNAT之前应用)。
  2. Ingress/Egress Policy (由 GlobalNetworkPolicyNetworkPolicy 定义,order 值通常在 01000 之间)。
  3. Ingress/Egress Post-DNAT Policy (由 GlobalNetworkPolicy 定义,order 值很高,如 10002000,在DNAT之后应用)。

对于我们这里讨论的场景,主要关注第二种“Ingress/Egress Policy”。

  • GlobalNetworkPolicy (deny-db-access-from-external) 的 order: 50
  • NetworkPolicy (allow-frontend-to-backend) 虽然没有显式设置 order,但其默认优先级会高于 50 (通常是 1000)。

因此,对数据库的任何访问尝试,都会首先被 deny-db-access-from-external 策略评估。如果该流量被 deny-db-access-from-external 明确拒绝,那么即使存在一个低优先级的 NetworkPolicy 试图允许它,流量也无法通过。

迁移旧服务时的注意事项

  1. 逐步实施:在全集群强制实施策略前,建议先在测试环境中充分验证。对于旧服务,可以先将其隔离在一个单独的命名空间,并针对该命名空间制定特定的 GlobalNetworkPolicy,确保其只能访问必要的旧系统资源。
  2. 细粒度标签:确保您的Pod和命名空间都有清晰、一致的标签。这是网络策略能够准确匹配目标的关键。例如,为所有数据库Pod打上 app: my-database 标签,为所有内部服务Pod打上 project: internal-service 标签。
  3. 监控与审计:部署策略后,务必配置网络流量监控和策略日志(Calico支持 action: Log),以便及时发现任何被意外拒绝的流量或潜在的安全漏洞。
  4. default-deny 策略:作为最佳实践,在每个命名空间内部署一个默认拒绝所有入站/出站流量的 NetworkPolicy,然后只允许必要的流量。对于 GlobalNetworkPolicy,可以设置一个低优先级的 Deny All 策略作为最终防护。
    • 示例 default-deny GlobalNetworkPolicy:
      apiVersion: projectcalico.org/v3
      kind: GlobalNetworkPolicy
      metadata:
        name: default-deny-all
      spec:
        order: 2000 # 较低优先级,作为最终的拒绝规则
        selector: all() # 匹配所有Pod
        types:
        - Ingress
        - Egress
        ingress:
        - action: Deny
        egress:
        - action: Deny
      
      请注意:通常不建议直接全局 Deny All,这会中断所有通信。更常见的做法是为每个命名空间部署 NetworkPolicy 来实现默认拒绝。Calico的 GlobalNetworkPolicy 更适合定义集群级的白名单或黑名单例外。对于迁移场景,可能需要更精细的控制,例如仅对旧服务所在命名空间默认拒绝。
  5. 服务发现与DNS:确保强制性策略不会阻断Kubernetes内部的服务发现机制(DNS)。通常,Calico策略默认允许对kube-dns的访问,但仍需验证。

总结

是的,Calico完全能够通过其 GlobalNetworkPolicyNetworkPolicy 的策略优先级机制,实现您所描述的层级管理需求。通过为集群范围内的强制性安全基线(如数据库访问限制)设置高优先级 GlobalNetworkPolicy (使用较小的 order 值),我们可以确保这些规则不会被低优先级的命名空间 NetworkPolicy 所“放宽”或覆盖。这为旧服务迁移提供了一个强大且灵活的网络安全框架,既保证了核心资产的安全性,又允许团队在安全基线之上拥有足够的灵活性来管理其应用的通信。

云深不知处 Kubernetes网络安全Calico

评论点评