Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
373 changes: 284 additions & 89 deletions charts/kube-ovn-v2/README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ spec:
- --enable-ovn-lb-prefer-local={{- .Values.features.ENABLE_OVN_LB_PREFER_LOCAL }}
- --image={{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }}
- --non-primary-cni-mode={{- .Values.cni.nonPrimaryCNI }}
- --np-enforcement={{- .Values.networkPolicies.enforcement | quote }}
securityContext:
runAsUser: {{ include "kubeovn.runAsUser" . }}
privileged: false
Expand Down
12 changes: 12 additions & 0 deletions charts/kube-ovn-v2/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,18 @@ natGw:
# @section -- NAT gateways configuration
apiNadProvider: "{{ .Values.apiNad.name }}.{{ .Values.namespace }}.ovn"


# -- Configuration for network policies
# @section -- Network Policies
# @default -- "{}"
networkPolicies:
# -- Enforcement level of network policies when they get applied (can be: standard, lax).
# Enforcement "standard" blocks everything except what is allowed by the network policies.
# Enforcement "lax" is similar to "standard" with the exception that ARP/DHCPv4/DHCPv6/ICMPv4/ICMPv6
# is allowed by default. This mode is useful when using Kubevirt and VMs with IPs configured via Kube-OVN's DHCP.
# @section -- Network Policies
enforcement: "standard"

# -- API NetworkAttachmentDefinition to give some pods (CoreDNS, NAT GW) in custom VPCs access to the K8S API.
# This requires Multus to be installed.
# @section -- API Network Attachment Definition configuration
Expand Down
1 change: 1 addition & 0 deletions charts/kube-ovn/templates/controller-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ spec:
- --pod-nic-type={{- .Values.networking.POD_NIC_TYPE }}
- --enable-lb={{- .Values.func.ENABLE_LB }}
- --enable-np={{- .Values.func.ENABLE_NP }}
- --np-enforcement={{- .Values.func.NP_ENFORCEMENT }}
- --enable-eip-snat={{- .Values.networking.ENABLE_EIP_SNAT }}
- --enable-external-vpc={{- .Values.func.ENABLE_EXTERNAL_VPC }}
- --enable-ecmp={{- .Values.networking.ENABLE_ECMP }}
Expand Down
1 change: 1 addition & 0 deletions charts/kube-ovn/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ networking:
func:
ENABLE_LB: true
ENABLE_NP: true
NP_ENFORCEMENT: standard
ENABLE_EXTERNAL_VPC: false
HW_OFFLOAD: false
ENABLE_LB_SVC: false
Expand Down
46 changes: 38 additions & 8 deletions mocks/pkg/ovs/interface.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions pkg/controller/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ type Configuration struct {

// Non Primary CNI flag
EnableNonPrimaryCNI bool

// Enforcement level of network policies (standard, lax)
NetworkPolicyEnforcement string
}

// ParseFlags parses cmd args then init kubeclient and conf
Expand Down Expand Up @@ -184,6 +187,7 @@ func ParseFlags() (*Configuration, error) {
argPodNicType = pflag.String("pod-nic-type", "veth-pair", "The default pod network nic implementation type")
argEnableLb = pflag.Bool("enable-lb", true, "Enable load balancer")
argEnableNP = pflag.Bool("enable-np", true, "Enable network policy support")
argNPEnforcement = pflag.String("np-enforcement", "standard", "Network policy enforcement (standard, lax), default is standard")
argEnableEipSnat = pflag.Bool("enable-eip-snat", true, "Enable EIP and SNAT")
argEnableExternalVpc = pflag.Bool("enable-external-vpc", false, "Enable external vpc support")
argEnableEcmp = pflag.Bool("enable-ecmp", false, "Enable ecmp route for centralized subnet")
Expand Down Expand Up @@ -312,6 +316,7 @@ func ParseFlags() (*Configuration, error) {
TLSMaxVersion: *argTLSMaxVersion,
TLSCipherSuites: *argTLSCipherSuites,
EnableNonPrimaryCNI: *argNonPrimaryCNI,
NetworkPolicyEnforcement: *argNPEnforcement,
}
if config.OvsDbConnectTimeout >= config.OvsDbInactivityTimeout {
return nil, errors.New("OVS DB inactivity timeout value should be greater than reconnect timeout value")
Expand Down
41 changes: 39 additions & 2 deletions pkg/controller/network_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ import (
"github.com/kubeovn/kube-ovn/pkg/util"
)

const (
NetworkPolicyEnforcementStandard = "standard"
NetworkPolicyEnforcementLax = "lax"
)

func (c *Controller) enqueueAddNp(obj any) {
key := cache.MetaObjectToName(obj.(*netv1.NetworkPolicy)).String()
klog.V(3).Infof("enqueue add network policy %s", key)
Expand Down Expand Up @@ -174,12 +179,23 @@ func (c *Controller) handleUpdateNp(key string) error {

if hasIngressRule(np) {
if protocolSet.Size() > 0 {
blockACLOps, err := c.OVNNbClient.UpdateDefaultBlockACLOps(key, pgName, ovnnb.ACLDirectionToLport, logEnable)
enforcementLax := c.isNetworkPolicyEnforcementLax(np)

blockACLOps, err := c.OVNNbClient.UpdateDefaultBlockACLOps(key, pgName, ovnnb.ACLDirectionToLport, logEnable, enforcementLax)
if err != nil {
klog.Errorf("failed to set default ingress block acl: %v", err)
return fmt.Errorf("failed to set default ingress block acl: %w", err)
}
ingressACLOps = append(ingressACLOps, blockACLOps...)

if enforcementLax {
defaultBlockExceptions, err := c.OVNNbClient.UpdateDefaultBlockExceptionsACLOps(key, pgName, np.Namespace, ovnnb.ACLDirectionToLport)
if err != nil {
klog.Errorf("failed to set default block exceptions for ingress acl: %v", err)
return fmt.Errorf("failed to set default block exceptions for ingress acl: %w", err)
}
ingressACLOps = append(ingressACLOps, defaultBlockExceptions...)
}
}

for _, protocol := range protocolSet.List() {
Expand Down Expand Up @@ -312,12 +328,23 @@ func (c *Controller) handleUpdateNp(key string) error {

if hasEgressRule(np) {
if protocolSet.Size() > 0 {
blockACLOps, err := c.OVNNbClient.UpdateDefaultBlockACLOps(key, pgName, ovnnb.ACLDirectionFromLport, logEnable)
enforcementLax := c.isNetworkPolicyEnforcementLax(np)

blockACLOps, err := c.OVNNbClient.UpdateDefaultBlockACLOps(key, pgName, ovnnb.ACLDirectionFromLport, logEnable, enforcementLax)
if err != nil {
klog.Errorf("failed to set default egress block acl: %v", err)
return fmt.Errorf("failed to set default egress block acl: %w", err)
}
egressACLOps = append(egressACLOps, blockACLOps...)

if enforcementLax {
defaultBlockExceptions, err := c.OVNNbClient.UpdateDefaultBlockExceptionsACLOps(key, pgName, np.Namespace, ovnnb.ACLDirectionFromLport)
if err != nil {
klog.Errorf("failed to set default block exceptions for ingress acl: %v", err)
return fmt.Errorf("failed to set default block exceptions for ingress acl: %w", err)
}
egressACLOps = append(egressACLOps, defaultBlockExceptions...)
}
}

for _, protocol := range protocolSet.List() {
Expand Down Expand Up @@ -794,3 +821,13 @@ func isNamespaceMatchNetworkPolicy(ns *corev1.Namespace, policy *netv1.NetworkPo
}
return false
}

func (c *Controller) isNetworkPolicyEnforcementLax(policy *netv1.NetworkPolicy) bool {
// User provided a custom enforcement through annotations
if value, ok := policy.Annotations[util.NetworkPolicyEnforcementAnnotation]; ok {
return value == NetworkPolicyEnforcementLax
}

// Fallback to the configuration of the controller
return c.config.NetworkPolicyEnforcement == NetworkPolicyEnforcementLax
}
3 changes: 2 additions & 1 deletion pkg/ovs/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ type PortGroup interface {
}

type ACL interface {
UpdateDefaultBlockACLOps(netpol, pgName, direction string, loggingEnabled bool) ([]ovsdb.Operation, error)
UpdateDefaultBlockACLOps(npName, pgName, direction string, loggingEnabled, lax bool) ([]ovsdb.Operation, error)
UpdateDefaultBlockExceptionsACLOps(npName, pgName, npNamespace, direction string) ([]ovsdb.Operation, error)
UpdateIngressACLOps(pgName, asIngressName, asExceptName, protocol, aclName string, npp []netv1.NetworkPolicyPort, logEnable bool, logACLActions []ovnnb.ACLAction, namedPortMap map[string]*util.NamedPortInfo) ([]ovsdb.Operation, error)
UpdateEgressACLOps(pgName, asEgressName, asExceptName, protocol, aclName string, npp []netv1.NetworkPolicyPort, logEnable bool, logACLActions []ovnnb.ACLAction, namedPortMap map[string]*util.NamedPortInfo) ([]ovsdb.Operation, error)
CreateGatewayACL(lsName, pgName, gateway, u2oInterconnectionIP string) error
Expand Down
80 changes: 72 additions & 8 deletions pkg/ovs/ovn-nb-acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func setACLName(acl *ovnnb.ACL, name string) {
}

// UpdateDefaultBlockACLOps returns operations to update/create the default block ACL
func (c *OVNNbClient) UpdateDefaultBlockACLOps(netpol, pgName, direction string, loggingEnabled bool) ([]ovsdb.Operation, error) {
func (c *OVNNbClient) UpdateDefaultBlockACLOps(npName, pgName, direction string, loggingEnabled, lax bool) ([]ovsdb.Operation, error) {
portDirection := "outport"
priority := util.IngressDefaultDrop

Expand All @@ -63,14 +63,24 @@ func (c *OVNNbClient) UpdateDefaultBlockACLOps(netpol, pgName, direction string,
priority = util.EgressDefaultDrop
}

// Block everything IP related (IPv4/IPv6/ICMPv4/ICMPv6/...)
allIPMatch := NewAndACLMatch(
NewACLMatch(portDirection, "==", "@"+pgName, ""),
NewACLMatch("ip", "", "", ""),
)
var match ACLMatch

if lax {
// This is the "lax" enforcement mode, we block only TCP/UDP/SCTP
match = NewAndACLMatch(
NewACLMatch(portDirection, "==", "@"+pgName, ""),
NewACLMatch("(tcp || udp || sctp)", "", "", ""),
)
} else {
// This is the "standard" enforcement mode, we block everything IP related (IPv4/IPv6/ICMPv4/ICMPv6/...)
match = NewAndACLMatch(
NewACLMatch(portDirection, "==", "@"+pgName, ""),
NewACLMatch("ip", "", "", ""),
)
}

options := func(acl *ovnnb.ACL) {
setACLName(acl, netpol)
setACLName(acl, npName)
if loggingEnabled {
acl.Log = true
acl.Severity = ptr.To(ovnnb.ACLSeverityWarning)
Expand All @@ -84,7 +94,7 @@ func (c *OVNNbClient) UpdateDefaultBlockACLOps(netpol, pgName, direction string,
}
}

defaultDropACL, err := c.newACLWithoutCheck(pgName, direction, priority, allIPMatch.String(), ovnnb.ACLActionDrop, util.NetpolACLTier, options)
defaultDropACL, err := c.newACLWithoutCheck(pgName, direction, priority, match.String(), ovnnb.ACLActionDrop, util.NetpolACLTier, options)
if err != nil {
klog.Error(err)
return nil, fmt.Errorf("failed to create drop acl for port group %s: %w", pgName, err)
Expand All @@ -99,6 +109,60 @@ func (c *OVNNbClient) UpdateDefaultBlockACLOps(netpol, pgName, direction string,
return ops, nil
}

// UpdateDefaultBlockExceptionsACLOps updates the exceptions to the default block ACLs of a NetworkPolicy to allow DHCPv4/DHCPv6.
func (c *OVNNbClient) UpdateDefaultBlockExceptionsACLOps(npName, pgName, npNamespace, direction string) ([]ovsdb.Operation, error) {
portDirection := "outport"
dhcpv4UdpSrc, dhcpv4UdpDst := "67", "68"
dhcpv6UdpSrc, dhcpv6UdpDst := "547", "546"

if direction == ovnnb.ACLDirectionFromLport { // Egress rule
portDirection = "inport"
dhcpv4UdpSrc, dhcpv4UdpDst = dhcpv4UdpDst, dhcpv4UdpSrc
dhcpv6UdpSrc, dhcpv6UdpDst = dhcpv6UdpDst, dhcpv6UdpSrc
}

acls := make([]*ovnnb.ACL, 0)

newACL := func(match string) {
options := func(acl *ovnnb.ACL) {
setACLName(acl, npName)
}

acl, err := c.newACL(pgName, direction, util.IngressAllowPriority, match, ovnnb.ACLActionAllowRelated, util.NetpolACLTier, options)
if err != nil {
klog.Error(err)
klog.Errorf("failed to create new block exceptions acl for network policy %s/%s: %v", npNamespace, npName, err)
return
}
acls = append(acls, acl)
}

// Allow DHCPv6
dhcpv6Match := NewAndACLMatch(
NewACLMatch(portDirection, "==", "@"+pgName, ""),
NewACLMatch("udp.src", "==", dhcpv6UdpSrc, ""),
NewACLMatch("udp.dst", "==", dhcpv6UdpDst, ""),
NewACLMatch("ip6", "", "", ""),
)
newACL(dhcpv6Match.String())

// Allow DHCPv4
dhcpv4Match := NewAndACLMatch(
NewACLMatch(portDirection, "==", "@"+pgName, ""),
NewACLMatch("udp.src", "==", dhcpv4UdpSrc, ""),
NewACLMatch("udp.dst", "==", dhcpv4UdpDst, ""),
NewACLMatch("ip4", "", "", ""),
)
newACL(dhcpv4Match.String())

ops, err := c.CreateAclsOps(pgName, portGroupKey, acls...)
if err != nil {
klog.Error(err)
return nil, fmt.Errorf("failed to create block exceptions acl for port group %s: %w", pgName, err)
}
return ops, nil
}

// UpdateIngressACLOps return operation that creates an ingress ACL
func (c *OVNNbClient) UpdateIngressACLOps(pgName, asIngressName, asExceptName, protocol, aclName string, npp []netv1.NetworkPolicyPort, logEnable bool, logACLActions []ovnnb.ACLAction, namedPortMap map[string]*util.NamedPortInfo) ([]ovsdb.Operation, error) {
acls := make([]*ovnnb.ACL, 0)
Expand Down
Loading
Loading