K8s发现和负载均衡-NetworkPolicy

基于1.25

什么是NetworkPolicy

K8s的网络模型和各种网络方法关心是容器之间的联通,而NetworkPolicy负责网络隔离

  • NetworkPolicy网络隔离,在多租户和安全性要求比较高的情况下使用
  • NetworkPolicy使用在一端或者俩端于Pod的连接
  • NetworkPolicy的作用范围:Pod、命名空间、Ingress、Egress流量等
  • NetworkPolicy作为在L3/4层,目的是限制IP地址和端口的访问,如果需要对应用层访问限制,需要使用Istio这类的Service Mesh
  • NetworkPolicy对象 需要NetworkPolicy控制器才能生效

Pod的隔离类型

Pod有俩种隔离类型:出口隔离和入口隔离

  • 默认情况下,没有出口隔离
    • 通过设置NetworkPolicy在PolicyType设置为Egress,进行出口隔离
  • 默认情况下,没有入口隔离
    • 通过设置NetworkPolicy在PolicyType设置为Igress,进行入口隔离
  • 网络策略是相加的

NetworkPolicySpec

  • Ref:https://github.com/kubernetes/api/blob/6e61ea04c537767720172fb5a770236e6531ae53/networking/v1/types.go#L61

    // NetworkPolicySpec provides the specification of a NetworkPolicy
    type NetworkPolicySpec struct {
    // podSelector selects the pods to which this NetworkPolicy object applies.
    // The array of ingress rules is applied to any pods selected by this field.
    // Multiple network policies can select the same set of pods. In this case,
    // the ingress rules for each are combined additively.
    // This field is NOT optional and follows standard label selector semantics.
    // An empty podSelector matches all pods in this namespace.
    // 选择应用的NetworkPolicy的Pod
    // 空的匹配所有Pod
    PodSelector metav1.LabelSelector `json:"podSelector" protobuf:"bytes,1,opt,name=podSelector"`

    // ingress is a list of ingress rules to be applied to the selected pods.
    // Traffic is allowed to a pod if there are no NetworkPolicies selecting the pod
    // (and cluster policy otherwise allows the traffic), OR if the traffic source is
    // the pod's local node, OR if the traffic matches at least one ingress rule
    // across all of the NetworkPolicy objects whose podSelector matches the pod. If
    // this field is empty then this NetworkPolicy does not allow any traffic (and serves
    // solely to ensure that the pods it selects are isolated by default)
    // +optional
    // +listType=atomic
    // 入口规则列表
    // 字段为空,不允许任何流量进入
    Ingress []NetworkPolicyIngressRule `json:"ingress,omitempty" protobuf:"bytes,2,rep,name=ingress"`

    // egress is a list of egress rules to be applied to the selected pods. Outgoing traffic
    // is allowed if there are no NetworkPolicies selecting the pod (and cluster policy
    // otherwise allows the traffic), OR if the traffic matches at least one egress rule
    // across all of the NetworkPolicy objects whose podSelector matches the pod. If
    // this field is empty then this NetworkPolicy limits all outgoing traffic (and serves
    // solely to ensure that the pods it selects are isolated by default).
    // This field is beta-level in 1.8
    // +optional
    // +listType=atomic
    // 出口规则列表
    // 字段为空,限制所有穿出流量
    Egress []NetworkPolicyEgressRule `json:"egress,omitempty" protobuf:"bytes,3,rep,name=egress"`

    // policyTypes is a list of rule types that the NetworkPolicy relates to.
    // Valid options are ["Ingress"], ["Egress"], or ["Ingress", "Egress"].
    // If this field is not specified, it will default based on the existence of ingress or egress rules;
    // policies that contain an egress section are assumed to affect egress, and all policies
    // (whether or not they contain an ingress section) are assumed to affect ingress.
    // If you want to write an egress-only policy, you must explicitly specify policyTypes [ "Egress" ].
    // Likewise, if you want to write a policy that specifies that no egress is allowed,
    // you must specify a policyTypes value that include "Egress" (since such a policy would not include
    // an egress section and would otherwise default to just [ "Ingress" ]).
    // This field is beta-level in 1.8
    // +optional
    // +listType=atomic
    // 规则类型列表 Ingress 或者 Egress 或者 Ingress+Egress
    PolicyTypes []PolicyType `json:"policyTypes,omitempty" protobuf:"bytes,4,rep,name=policyTypes,casttype=PolicyType"`
    }

    NetworkPolicy的实现

    NetworkPolicy典型有俩种实现:iptables和eBPF

    iptables:对Pod进行隔离,通过宿主机上生成iptables实现

    eBPF:可编程、稳定、高效、安全,Clium就是基于eBPF

func (m *policyManager) OnUpdate(msg interface{}) {
switch msg := msg.(type) {
case *proto.ActivePolicyUpdate:
if m.rawEgressOnly && !msg.Policy.Untracked {
log.WithField("id", msg.Id).Debug("Clean up non-untracked policy.")
m.cleanUpPolicy(msg.Id)
return
}
log.WithField("id", msg.Id).Debug("Updating policy chains")
chains := m.ruleRenderer.PolicyToIptablesChains(msg.Id, msg.Policy, m.ipVersion)
if m.rawEgressOnly {
neededIPSets := set.New[string]()
filteredChains := []*generictables.Chain(nil)
for _, chain := range chains {
if strings.Contains(chain.Name, string(rules.PolicyOutboundPfx)) {
filteredChains = append(filteredChains, chain)
neededIPSets.AddAll(chain.IPSetNames())
}
}
chains = filteredChains
m.updateNeededIPSets(msg.Id, neededIPSets)
}
// We can't easily tell whether the policy is in use in a particular table, and, if the policy
// type gets changed it may move between tables. Hence, we put the policy into all tables.
// The iptables layer will avoid programming it if it is not actually used.
m.rawTable.UpdateChains(chains)
m.mangleTable.UpdateChains(chains)
m.filterTable.UpdateChains(chains)
case *proto.ActivePolicyRemove:
log.WithField("id", msg.Id).Debug("Removing policy chains")
m.cleanUpPolicy(msg.Id)
case *proto.ActiveProfileUpdate:
if m.rawEgressOnly {
log.WithField("id", msg.Id).Debug("Ignore non-untracked profile")
return
}
// 设置iptables规则
log.WithField("id", msg.Id).Debug("Updating profile chains")
inbound, outbound := m.ruleRenderer.ProfileToIptablesChains(msg.Id, msg.Profile, m.ipVersion)
m.filterTable.UpdateChains([]*generictables.Chain{inbound, outbound})
m.mangleTable.UpdateChains([]*generictables.Chain{outbound})
case *proto.ActiveProfileRemove:
// 清空iptables规则
log.WithField("id", msg.Id).Debug("Removing profile chains")
inName := rules.ProfileChainName(rules.ProfileInboundPfx, msg.Id)
outName := rules.ProfileChainName(rules.ProfileOutboundPfx, msg.Id)
m.filterTable.RemoveChainByName(inName)
m.filterTable.RemoveChainByName(outName)
m.mangleTable.RemoveChainByName(outName)
}
}