From 65a8a892cdf620c1b06532e1492548675a10c4b9 Mon Sep 17 00:00:00 2001 From: Bowei Du Date: Wed, 24 Sep 2025 11:49:22 -0700 Subject: [PATCH 1/7] Update ports to protocols Makes the `ports` clause a more generic `protocols` block to allow for future expansion. Example ```yaml apiVersion: policy.networking.k8s.io/v1alpha2 kind: ClusterNetworkPolicy metadata: name: pub-svc-delegate-example spec: tier: Admin priority: 20 subject: namespaces: {} egress: - action: Pass to: - pods: namespaceSelector: matchLabels: kubernetes.io/metadata.name: bar-ns-1 podSelector: matchLabels: app: svc-pub protocols: #< - protocol: TCP #< port: #< number: 8080 #< ``` Another example: ``` protocols: - protocol: TCP port: range: start: 1000 end: 2000 - protocol: UDP port: number: 53 ``` Ref: https://github.com/kubernetes-sigs/network-policy-api/issues/187 --- apis/v1alpha2/clusternetworkpolicy_types.go | 77 ++++---- apis/v1alpha2/zz_generated.deepcopy.go | 57 +++--- ...working.k8s.io_clusternetworkpolicies.yaml | 175 +++++++----------- ...working.k8s.io_clusternetworkpolicies.yaml | 153 ++++++--------- .../clusternetworkpolicyingressrule.go | 26 +-- .../apis/v1alpha2/clusternetworkpolicyport.go | 30 +-- .../v1alpha2/clusternetworkpolicyprotocol.go | 52 ++++++ .../apis/v1alpha2/portrange.go | 17 +- pkg/client/applyconfiguration/utils.go | 4 +- 9 files changed, 287 insertions(+), 304 deletions(-) create mode 100644 pkg/client/applyconfiguration/apis/v1alpha2/clusternetworkpolicyprotocol.go diff --git a/apis/v1alpha2/clusternetworkpolicy_types.go b/apis/v1alpha2/clusternetworkpolicy_types.go index 5a08859a..fcc4ad10 100644 --- a/apis/v1alpha2/clusternetworkpolicy_types.go +++ b/apis/v1alpha2/clusternetworkpolicy_types.go @@ -206,16 +206,15 @@ type ClusterNetworkPolicyIngressRule struct { // +kubebuilder:validation:MaxItems=25 From []ClusterNetworkPolicyIngressPeer `json:"from"` - // Ports allows for matching traffic based on port and protocols. - // This field is a list of ports which should be matched on - // the pods selected for this policy i.e the subject of the policy. - // So it matches on the destination port for the ingress traffic. - // If Ports is not set then the rule does not filter traffic via port. + // Protocols this rule matches. This rule matches if any of + // the elements in the list match the incoming traffic. + // + // This field must contain at least one item. // // +optional // +kubebuilder:validation:MinItems=1 - // +kubebuilder:validation:MaxItems=25 - Ports *[]ClusterNetworkPolicyPort `json:"ports,omitempty"` + // +kubebuilder:validation:MaxItems=100 + Protocols *[]ClusterNetworkPolicyProtocol `json:"protocols,omitempty"` } // ClusterNetworkPolicyEgressRule describes an action to take on a particular @@ -320,29 +319,49 @@ type ClusterNetworkPolicyIngressPeer struct { Pods *NamespacedPod `json:"pods,omitempty"` } -// ClusterNetworkPolicyPort describes how to select destination network ports. -// Exactly one field must be set. +// ClusterNetworkPolicyProtocol describes how to select traffic by +// protocol-specific attributes. +// +// +kubebuilder:validation:XValidation:rule="!(self.protocol in ['TCP', 'UDP', 'SCTP']) || has(self.port)",message="port must be specified for protocols that support ports" +type ClusterNetworkPolicyProtocol struct { + // Protocol is the network protocol (TCP, UDP, or SCTP) which + // traffic must match. If not specified, this field defaults + // to TCP. + // + // +kubebuilder:default=TCP + Protocol corev1.Protocol `json:"protocol,omitempty"` + + // Specific port to match against. + // + // +optional + Port *ClusterNetworkPolicyPort `json:"port,omitempty"` +} + +// ClusterNetworkPolicyPort describes how to match by port. This can +// only be used with protocols that use port numbers (e.g. TCP, UDP). +// +// Exactly one of the fields in this struct must be set. +// // +kubebuilder:validation:MaxProperties=1 // +kubebuilder:validation:MinProperties=1 type ClusterNetworkPolicyPort struct { - // Port selects a destination port based on protocol and port number. + // Port selects the port by number. // // +optional - PortNumber *Port `json:"portNumber,omitempty"` + Number *int32 `json:"number,omitempty"` - // PortRange selects a destination port range based on protocol and - // start and end port numbers. + // PortRange selects the port by range. // // +optional - PortRange *PortRange `json:"portRange,omitempty"` + Range *PortRange `json:"range,omitempty"` - // NamedPort selects a destination port on a pod based on the ContainerPort - // name. You can't use this in a rule with Nodes or Networks peers, - // because they do not have named ports. + // NamedPort selects a destination port on a pod based on the + // ContainerPort name. You can't use this in a rule with Nodes + // or Networks peers, because they do not have named ports. // // // +optional - NamedPort *string `json:"namedPort,omitempty"` + Name *string `json:"name,omitempty"` } // ClusterNetworkPolicyEgressPeer defines a peer to allow traffic to. @@ -428,32 +447,13 @@ type NamespacedPod struct { PodSelector metav1.LabelSelector `json:"podSelector"` } -type Port struct { - // Protocol is the network protocol (TCP, UDP, or SCTP) which traffic must - // match. If not specified, this field defaults to TCP. - // +kubebuilder:default=TCP - // - Protocol corev1.Protocol `json:"protocol"` - - // Number defines a network port value. - // +kubebuilder:validation:Minimum=1 - // +kubebuilder:validation:Maximum=65535 - // - Port int32 `json:"port"` -} - // PortRange defines an inclusive range of ports from the assigned // Start value to End value. // +kubebuilder:validation:XValidation:rule="self.start < self.end", message="Start port must be less than End port" type PortRange struct { - // Protocol is the network protocol (TCP, UDP, or SCTP) which traffic must - // match. If not specified, this field defaults to TCP. - // +kubebuilder:default=TCP - // - Protocol corev1.Protocol `json:"protocol,omitempty"` - // Start defines a network port that is the start of a port range, the Start // value must be less than End. + // // +kubebuilder:validation:Minimum=1 // +kubebuilder:validation:Maximum=65535 // @@ -461,6 +461,7 @@ type PortRange struct { // End defines a network port that is the end of a port range, the End value // must be greater than Start. + // // +kubebuilder:validation:Minimum=1 // +kubebuilder:validation:Maximum=65535 // diff --git a/apis/v1alpha2/zz_generated.deepcopy.go b/apis/v1alpha2/zz_generated.deepcopy.go index df671c5b..dbd24c31 100644 --- a/apis/v1alpha2/zz_generated.deepcopy.go +++ b/apis/v1alpha2/zz_generated.deepcopy.go @@ -160,12 +160,12 @@ func (in *ClusterNetworkPolicyIngressRule) DeepCopyInto(out *ClusterNetworkPolic (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.Ports != nil { - in, out := &in.Ports, &out.Ports - *out = new([]ClusterNetworkPolicyPort) + if in.Protocols != nil { + in, out := &in.Protocols, &out.Protocols + *out = new([]ClusterNetworkPolicyProtocol) if **in != nil { in, out := *in, *out - *out = make([]ClusterNetworkPolicyPort, len(*in)) + *out = make([]ClusterNetworkPolicyProtocol, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } @@ -218,18 +218,18 @@ func (in *ClusterNetworkPolicyList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterNetworkPolicyPort) DeepCopyInto(out *ClusterNetworkPolicyPort) { *out = *in - if in.PortNumber != nil { - in, out := &in.PortNumber, &out.PortNumber - *out = new(Port) + if in.Number != nil { + in, out := &in.Number, &out.Number + *out = new(int32) **out = **in } - if in.PortRange != nil { - in, out := &in.PortRange, &out.PortRange + if in.Range != nil { + in, out := &in.Range, &out.Range *out = new(PortRange) **out = **in } - if in.NamedPort != nil { - in, out := &in.NamedPort, &out.NamedPort + if in.Name != nil { + in, out := &in.Name, &out.Name *out = new(string) **out = **in } @@ -245,6 +245,26 @@ func (in *ClusterNetworkPolicyPort) DeepCopy() *ClusterNetworkPolicyPort { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterNetworkPolicyProtocol) DeepCopyInto(out *ClusterNetworkPolicyProtocol) { + *out = *in + if in.Port != nil { + in, out := &in.Port, &out.Port + *out = new(ClusterNetworkPolicyPort) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterNetworkPolicyProtocol. +func (in *ClusterNetworkPolicyProtocol) DeepCopy() *ClusterNetworkPolicyProtocol { + if in == nil { + return nil + } + out := new(ClusterNetworkPolicyProtocol) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterNetworkPolicySpec) DeepCopyInto(out *ClusterNetworkPolicySpec) { *out = *in @@ -339,21 +359,6 @@ func (in *NamespacedPod) DeepCopy() *NamespacedPod { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Port) DeepCopyInto(out *Port) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Port. -func (in *Port) DeepCopy() *Port { - if in == nil { - return nil - } - out := new(Port) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PortRange) DeepCopyInto(out *PortRange) { *out = *in diff --git a/config/crd/experimental/policy.networking.k8s.io_clusternetworkpolicies.yaml b/config/crd/experimental/policy.networking.k8s.io_clusternetworkpolicies.yaml index 624f160d..ff819bce 100644 --- a/config/crd/experimental/policy.networking.k8s.io_clusternetworkpolicies.yaml +++ b/config/crd/experimental/policy.networking.k8s.io_clusternetworkpolicies.yaml @@ -107,43 +107,27 @@ spec: If Ports is not set then the rule does not filter traffic via port. items: description: |- - ClusterNetworkPolicyPort describes how to select destination network ports. - Exactly one field must be set. + ClusterNetworkPolicyPort describes how to match by port. This can + only be used with protocols that use port numbers (e.g. TCP, UDP). + + Exactly one of the fields in this struct must be set. maxProperties: 1 minProperties: 1 properties: - namedPort: + name: description: |- - NamedPort selects a destination port on a pod based on the ContainerPort - name. You can't use this in a rule with Nodes or Networks peers, - because they do not have named ports. + NamedPort selects a destination port on a pod based on the + ContainerPort name. You can't use this in a rule with Nodes + or Networks peers, because they do not have named ports. type: string - portNumber: - description: Port selects a destination port based on - protocol and port number. - properties: - port: - description: Number defines a network port value. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - protocol: - default: TCP - description: |- - Protocol is the network protocol (TCP, UDP, or SCTP) which traffic must - match. If not specified, this field defaults to TCP. - type: string - required: - - port - - protocol - type: object - portRange: - description: |- - PortRange selects a destination port range based on protocol and - start and end port numbers. + number: + description: Port selects the port by number. + format: int32 + type: integer + range: + description: PortRange selects the port by range. properties: end: description: |- @@ -153,12 +137,6 @@ spec: maximum: 65535 minimum: 1 type: integer - protocol: - default: TCP - description: |- - Protocol is the network protocol (TCP, UDP, or SCTP) which traffic must - match. If not specified, this field defaults to TCP. - type: string start: description: |- Start defines a network port that is the start of a port range, the Start @@ -723,84 +701,75 @@ spec: for any applied AdminNetworkPolicies. maxLength: 100 type: string - ports: + protocols: description: |- - Ports allows for matching traffic based on port and protocols. - This field is a list of ports which should be matched on - the pods selected for this policy i.e the subject of the policy. - So it matches on the destination port for the ingress traffic. - If Ports is not set then the rule does not filter traffic via port. + Protocols this rule matches. This rule matches if any of + the elements in the list match the incoming traffic. + + This field must contain at least one item. items: description: |- - ClusterNetworkPolicyPort describes how to select destination network ports. - Exactly one field must be set. - maxProperties: 1 - minProperties: 1 + ClusterNetworkPolicyProtocol describes how to select traffic by + protocol-specific attributes. properties: - namedPort: - description: |- - NamedPort selects a destination port on a pod based on the ContainerPort - name. You can't use this in a rule with Nodes or Networks peers, - because they do not have named ports. - - - type: string - portNumber: - description: Port selects a destination port based on - protocol and port number. + port: + description: Specific port to match against. + maxProperties: 1 + minProperties: 1 properties: - port: - description: Number defines a network port value. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - protocol: - default: TCP + name: description: |- - Protocol is the network protocol (TCP, UDP, or SCTP) which traffic must - match. If not specified, this field defaults to TCP. - type: string - required: - - port - - protocol - type: object - portRange: - description: |- - PortRange selects a destination port range based on protocol and - start and end port numbers. - properties: - end: - description: |- - End defines a network port that is the end of a port range, the End value - must be greater than Start. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - protocol: - default: TCP - description: |- - Protocol is the network protocol (TCP, UDP, or SCTP) which traffic must - match. If not specified, this field defaults to TCP. + NamedPort selects a destination port on a pod based on the + ContainerPort name. You can't use this in a rule with Nodes + or Networks peers, because they do not have named ports. + + type: string - start: - description: |- - Start defines a network port that is the start of a port range, the Start - value must be less than End. + number: + description: Port selects the port by number. format: int32 - maximum: 65535 - minimum: 1 type: integer - required: - - end - - start + range: + description: PortRange selects the port by range. + properties: + end: + description: |- + End defines a network port that is the end of a port range, the End value + must be greater than Start. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + start: + description: |- + Start defines a network port that is the start of a port range, the Start + value must be less than End. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - end + - start + type: object + x-kubernetes-validations: + - message: Start port must be less than End port + rule: self.start < self.end type: object - x-kubernetes-validations: - - message: Start port must be less than End port - rule: self.start < self.end + protocol: + default: TCP + description: |- + Protocol is the network protocol (TCP, UDP, or SCTP) which + traffic must match. If not specified, this field defaults + to TCP. + type: string type: object - maxItems: 25 + x-kubernetes-validations: + - message: port must be specified for protocols that support + ports + rule: '!(self.protocol in [''TCP'', ''UDP'', ''SCTP'']) + || has(self.port)' + maxItems: 100 minItems: 1 type: array required: diff --git a/config/crd/standard/policy.networking.k8s.io_clusternetworkpolicies.yaml b/config/crd/standard/policy.networking.k8s.io_clusternetworkpolicies.yaml index 2b69f911..8cadbda9 100644 --- a/config/crd/standard/policy.networking.k8s.io_clusternetworkpolicies.yaml +++ b/config/crd/standard/policy.networking.k8s.io_clusternetworkpolicies.yaml @@ -107,35 +107,19 @@ spec: If Ports is not set then the rule does not filter traffic via port. items: description: |- - ClusterNetworkPolicyPort describes how to select destination network ports. - Exactly one field must be set. + ClusterNetworkPolicyPort describes how to match by port. This can + only be used with protocols that use port numbers (e.g. TCP, UDP). + + Exactly one of the fields in this struct must be set. maxProperties: 1 minProperties: 1 properties: - portNumber: - description: Port selects a destination port based on - protocol and port number. - properties: - port: - description: Number defines a network port value. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - protocol: - default: TCP - description: |- - Protocol is the network protocol (TCP, UDP, or SCTP) which traffic must - match. If not specified, this field defaults to TCP. - type: string - required: - - port - - protocol - type: object - portRange: - description: |- - PortRange selects a destination port range based on protocol and - start and end port numbers. + number: + description: Port selects the port by number. + format: int32 + type: integer + range: + description: PortRange selects the port by range. properties: end: description: |- @@ -145,12 +129,6 @@ spec: maximum: 65535 minimum: 1 type: integer - protocol: - default: TCP - description: |- - Protocol is the network protocol (TCP, UDP, or SCTP) which traffic must - match. If not specified, this field defaults to TCP. - type: string start: description: |- Start defines a network port that is the start of a port range, the Start @@ -617,76 +595,67 @@ spec: for any applied AdminNetworkPolicies. maxLength: 100 type: string - ports: + protocols: description: |- - Ports allows for matching traffic based on port and protocols. - This field is a list of ports which should be matched on - the pods selected for this policy i.e the subject of the policy. - So it matches on the destination port for the ingress traffic. - If Ports is not set then the rule does not filter traffic via port. + Protocols this rule matches. This rule matches if any of + the elements in the list match the incoming traffic. + + This field must contain at least one item. items: description: |- - ClusterNetworkPolicyPort describes how to select destination network ports. - Exactly one field must be set. - maxProperties: 1 - minProperties: 1 + ClusterNetworkPolicyProtocol describes how to select traffic by + protocol-specific attributes. properties: - portNumber: - description: Port selects a destination port based on - protocol and port number. + port: + description: Specific port to match against. + maxProperties: 1 + minProperties: 1 properties: - port: - description: Number defines a network port value. + number: + description: Port selects the port by number. format: int32 - maximum: 65535 - minimum: 1 type: integer - protocol: - default: TCP - description: |- - Protocol is the network protocol (TCP, UDP, or SCTP) which traffic must - match. If not specified, this field defaults to TCP. - type: string - required: - - port - - protocol + range: + description: PortRange selects the port by range. + properties: + end: + description: |- + End defines a network port that is the end of a port range, the End value + must be greater than Start. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + start: + description: |- + Start defines a network port that is the start of a port range, the Start + value must be less than End. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - end + - start + type: object + x-kubernetes-validations: + - message: Start port must be less than End port + rule: self.start < self.end type: object - portRange: + protocol: + default: TCP description: |- - PortRange selects a destination port range based on protocol and - start and end port numbers. - properties: - end: - description: |- - End defines a network port that is the end of a port range, the End value - must be greater than Start. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - protocol: - default: TCP - description: |- - Protocol is the network protocol (TCP, UDP, or SCTP) which traffic must - match. If not specified, this field defaults to TCP. - type: string - start: - description: |- - Start defines a network port that is the start of a port range, the Start - value must be less than End. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - end - - start - type: object - x-kubernetes-validations: - - message: Start port must be less than End port - rule: self.start < self.end + Protocol is the network protocol (TCP, UDP, or SCTP) which + traffic must match. If not specified, this field defaults + to TCP. + type: string type: object - maxItems: 25 + x-kubernetes-validations: + - message: port must be specified for protocols that support + ports + rule: '!(self.protocol in [''TCP'', ''UDP'', ''SCTP'']) + || has(self.port)' + maxItems: 100 minItems: 1 type: array required: diff --git a/pkg/client/applyconfiguration/apis/v1alpha2/clusternetworkpolicyingressrule.go b/pkg/client/applyconfiguration/apis/v1alpha2/clusternetworkpolicyingressrule.go index b1885ab4..830c99b5 100644 --- a/pkg/client/applyconfiguration/apis/v1alpha2/clusternetworkpolicyingressrule.go +++ b/pkg/client/applyconfiguration/apis/v1alpha2/clusternetworkpolicyingressrule.go @@ -25,10 +25,10 @@ import ( // ClusterNetworkPolicyIngressRuleApplyConfiguration represents a declarative configuration of the ClusterNetworkPolicyIngressRule type for use // with apply. type ClusterNetworkPolicyIngressRuleApplyConfiguration struct { - Name *string `json:"name,omitempty"` - Action *apisv1alpha2.ClusterNetworkPolicyRuleAction `json:"action,omitempty"` - From []ClusterNetworkPolicyIngressPeerApplyConfiguration `json:"from,omitempty"` - Ports *[]ClusterNetworkPolicyPortApplyConfiguration `json:"ports,omitempty"` + Name *string `json:"name,omitempty"` + Action *apisv1alpha2.ClusterNetworkPolicyRuleAction `json:"action,omitempty"` + From []ClusterNetworkPolicyIngressPeerApplyConfiguration `json:"from,omitempty"` + Protocols *[]ClusterNetworkPolicyProtocolApplyConfiguration `json:"protocols,omitempty"` } // ClusterNetworkPolicyIngressRuleApplyConfiguration constructs a declarative configuration of the ClusterNetworkPolicyIngressRule type for use with @@ -66,22 +66,22 @@ func (b *ClusterNetworkPolicyIngressRuleApplyConfiguration) WithFrom(values ...* return b } -func (b *ClusterNetworkPolicyIngressRuleApplyConfiguration) ensureClusterNetworkPolicyPortApplyConfigurationExists() { - if b.Ports == nil { - b.Ports = &[]ClusterNetworkPolicyPortApplyConfiguration{} +func (b *ClusterNetworkPolicyIngressRuleApplyConfiguration) ensureClusterNetworkPolicyProtocolApplyConfigurationExists() { + if b.Protocols == nil { + b.Protocols = &[]ClusterNetworkPolicyProtocolApplyConfiguration{} } } -// WithPorts adds the given value to the Ports field in the declarative configuration +// WithProtocols adds the given value to the Protocols field in the declarative configuration // and returns the receiver, so that objects can be build by chaining "With" function invocations. -// If called multiple times, values provided by each call will be appended to the Ports field. -func (b *ClusterNetworkPolicyIngressRuleApplyConfiguration) WithPorts(values ...*ClusterNetworkPolicyPortApplyConfiguration) *ClusterNetworkPolicyIngressRuleApplyConfiguration { - b.ensureClusterNetworkPolicyPortApplyConfigurationExists() +// If called multiple times, values provided by each call will be appended to the Protocols field. +func (b *ClusterNetworkPolicyIngressRuleApplyConfiguration) WithProtocols(values ...*ClusterNetworkPolicyProtocolApplyConfiguration) *ClusterNetworkPolicyIngressRuleApplyConfiguration { + b.ensureClusterNetworkPolicyProtocolApplyConfigurationExists() for i := range values { if values[i] == nil { - panic("nil value passed to WithPorts") + panic("nil value passed to WithProtocols") } - *b.Ports = append(*b.Ports, *values[i]) + *b.Protocols = append(*b.Protocols, *values[i]) } return b } diff --git a/pkg/client/applyconfiguration/apis/v1alpha2/clusternetworkpolicyport.go b/pkg/client/applyconfiguration/apis/v1alpha2/clusternetworkpolicyport.go index d0831978..7d8f7ba1 100644 --- a/pkg/client/applyconfiguration/apis/v1alpha2/clusternetworkpolicyport.go +++ b/pkg/client/applyconfiguration/apis/v1alpha2/clusternetworkpolicyport.go @@ -21,9 +21,9 @@ package v1alpha2 // ClusterNetworkPolicyPortApplyConfiguration represents a declarative configuration of the ClusterNetworkPolicyPort type for use // with apply. type ClusterNetworkPolicyPortApplyConfiguration struct { - PortNumber *PortApplyConfiguration `json:"portNumber,omitempty"` - PortRange *PortRangeApplyConfiguration `json:"portRange,omitempty"` - NamedPort *string `json:"namedPort,omitempty"` + Number *int32 `json:"number,omitempty"` + Range *PortRangeApplyConfiguration `json:"range,omitempty"` + Name *string `json:"name,omitempty"` } // ClusterNetworkPolicyPortApplyConfiguration constructs a declarative configuration of the ClusterNetworkPolicyPort type for use with @@ -32,26 +32,26 @@ func ClusterNetworkPolicyPort() *ClusterNetworkPolicyPortApplyConfiguration { return &ClusterNetworkPolicyPortApplyConfiguration{} } -// WithPortNumber sets the PortNumber field in the declarative configuration to the given value +// WithNumber sets the Number field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the PortNumber field is set to the value of the last call. -func (b *ClusterNetworkPolicyPortApplyConfiguration) WithPortNumber(value *PortApplyConfiguration) *ClusterNetworkPolicyPortApplyConfiguration { - b.PortNumber = value +// If called multiple times, the Number field is set to the value of the last call. +func (b *ClusterNetworkPolicyPortApplyConfiguration) WithNumber(value int32) *ClusterNetworkPolicyPortApplyConfiguration { + b.Number = &value return b } -// WithPortRange sets the PortRange field in the declarative configuration to the given value +// WithRange sets the Range field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the PortRange field is set to the value of the last call. -func (b *ClusterNetworkPolicyPortApplyConfiguration) WithPortRange(value *PortRangeApplyConfiguration) *ClusterNetworkPolicyPortApplyConfiguration { - b.PortRange = value +// If called multiple times, the Range field is set to the value of the last call. +func (b *ClusterNetworkPolicyPortApplyConfiguration) WithRange(value *PortRangeApplyConfiguration) *ClusterNetworkPolicyPortApplyConfiguration { + b.Range = value return b } -// WithNamedPort sets the NamedPort field in the declarative configuration to the given value +// WithName sets the Name field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the NamedPort field is set to the value of the last call. -func (b *ClusterNetworkPolicyPortApplyConfiguration) WithNamedPort(value string) *ClusterNetworkPolicyPortApplyConfiguration { - b.NamedPort = &value +// If called multiple times, the Name field is set to the value of the last call. +func (b *ClusterNetworkPolicyPortApplyConfiguration) WithName(value string) *ClusterNetworkPolicyPortApplyConfiguration { + b.Name = &value return b } diff --git a/pkg/client/applyconfiguration/apis/v1alpha2/clusternetworkpolicyprotocol.go b/pkg/client/applyconfiguration/apis/v1alpha2/clusternetworkpolicyprotocol.go new file mode 100644 index 00000000..2506f055 --- /dev/null +++ b/pkg/client/applyconfiguration/apis/v1alpha2/clusternetworkpolicyprotocol.go @@ -0,0 +1,52 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + v1 "k8s.io/api/core/v1" +) + +// ClusterNetworkPolicyProtocolApplyConfiguration represents a declarative configuration of the ClusterNetworkPolicyProtocol type for use +// with apply. +type ClusterNetworkPolicyProtocolApplyConfiguration struct { + Protocol *v1.Protocol `json:"protocol,omitempty"` + Port *ClusterNetworkPolicyPortApplyConfiguration `json:"port,omitempty"` +} + +// ClusterNetworkPolicyProtocolApplyConfiguration constructs a declarative configuration of the ClusterNetworkPolicyProtocol type for use with +// apply. +func ClusterNetworkPolicyProtocol() *ClusterNetworkPolicyProtocolApplyConfiguration { + return &ClusterNetworkPolicyProtocolApplyConfiguration{} +} + +// WithProtocol sets the Protocol field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Protocol field is set to the value of the last call. +func (b *ClusterNetworkPolicyProtocolApplyConfiguration) WithProtocol(value v1.Protocol) *ClusterNetworkPolicyProtocolApplyConfiguration { + b.Protocol = &value + return b +} + +// WithPort sets the Port field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Port field is set to the value of the last call. +func (b *ClusterNetworkPolicyProtocolApplyConfiguration) WithPort(value *ClusterNetworkPolicyPortApplyConfiguration) *ClusterNetworkPolicyProtocolApplyConfiguration { + b.Port = value + return b +} diff --git a/pkg/client/applyconfiguration/apis/v1alpha2/portrange.go b/pkg/client/applyconfiguration/apis/v1alpha2/portrange.go index 1accaad9..63521957 100644 --- a/pkg/client/applyconfiguration/apis/v1alpha2/portrange.go +++ b/pkg/client/applyconfiguration/apis/v1alpha2/portrange.go @@ -18,16 +18,11 @@ limitations under the License. package v1alpha2 -import ( - v1 "k8s.io/api/core/v1" -) - // PortRangeApplyConfiguration represents a declarative configuration of the PortRange type for use // with apply. type PortRangeApplyConfiguration struct { - Protocol *v1.Protocol `json:"protocol,omitempty"` - Start *int32 `json:"start,omitempty"` - End *int32 `json:"end,omitempty"` + Start *int32 `json:"start,omitempty"` + End *int32 `json:"end,omitempty"` } // PortRangeApplyConfiguration constructs a declarative configuration of the PortRange type for use with @@ -36,14 +31,6 @@ func PortRange() *PortRangeApplyConfiguration { return &PortRangeApplyConfiguration{} } -// WithProtocol sets the Protocol field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Protocol field is set to the value of the last call. -func (b *PortRangeApplyConfiguration) WithProtocol(value v1.Protocol) *PortRangeApplyConfiguration { - b.Protocol = &value - return b -} - // WithStart sets the Start field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the Start field is set to the value of the last call. diff --git a/pkg/client/applyconfiguration/utils.go b/pkg/client/applyconfiguration/utils.go index 3a13c94a..8db91783 100644 --- a/pkg/client/applyconfiguration/utils.go +++ b/pkg/client/applyconfiguration/utils.go @@ -84,6 +84,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apisv1alpha2.ClusterNetworkPolicyIngressRuleApplyConfiguration{} case v1alpha2.SchemeGroupVersion.WithKind("ClusterNetworkPolicyPort"): return &apisv1alpha2.ClusterNetworkPolicyPortApplyConfiguration{} + case v1alpha2.SchemeGroupVersion.WithKind("ClusterNetworkPolicyProtocol"): + return &apisv1alpha2.ClusterNetworkPolicyProtocolApplyConfiguration{} case v1alpha2.SchemeGroupVersion.WithKind("ClusterNetworkPolicySpec"): return &apisv1alpha2.ClusterNetworkPolicySpecApplyConfiguration{} case v1alpha2.SchemeGroupVersion.WithKind("ClusterNetworkPolicyStatus"): @@ -92,8 +94,6 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apisv1alpha2.ClusterNetworkPolicySubjectApplyConfiguration{} case v1alpha2.SchemeGroupVersion.WithKind("NamespacedPod"): return &apisv1alpha2.NamespacedPodApplyConfiguration{} - case v1alpha2.SchemeGroupVersion.WithKind("Port"): - return &apisv1alpha2.PortApplyConfiguration{} case v1alpha2.SchemeGroupVersion.WithKind("PortRange"): return &apisv1alpha2.PortRangeApplyConfiguration{} From 64ffe54a6dcdfc2eee08093eed6bc0cd391770a2 Mon Sep 17 00:00:00 2001 From: Bowei Du Date: Wed, 15 Oct 2025 10:34:04 -0700 Subject: [PATCH 2/7] Make egress consistent with ingress --- apis/v1alpha2/clusternetworkpolicy_types.go | 14 +-- ...working.k8s.io_clusternetworkpolicies.yaml | 104 ++++++++++-------- ...working.k8s.io_clusternetworkpolicies.yaml | 90 ++++++++------- .../clusternetworkpolicyegressrule.go | 26 ++--- 4 files changed, 131 insertions(+), 103 deletions(-) diff --git a/apis/v1alpha2/clusternetworkpolicy_types.go b/apis/v1alpha2/clusternetworkpolicy_types.go index fcc4ad10..9d689eec 100644 --- a/apis/v1alpha2/clusternetworkpolicy_types.go +++ b/apis/v1alpha2/clusternetworkpolicy_types.go @@ -257,14 +257,14 @@ type ClusterNetworkPolicyEgressRule struct { // +kubebuilder:validation:MaxItems=25 To []ClusterNetworkPolicyEgressPeer `json:"to"` - // Ports allows for matching traffic based on port and protocols. - // This field is a list of destination ports for the outgoing egress traffic. - // If Ports is not set then the rule does not filter traffic via port. + // Protocols allows for matching traffic based on port and protocols. This + // field is a list of destination protocol/ports for the outgoing egress + // traffic. If this field is not set then the rule does not filter traffic + // via protocol/port. This field must contain at least one item if set. // - // +optional - // +kubebuilder:validation:MinItems=1 - // +kubebuilder:validation:MaxItems=25 - Ports *[]ClusterNetworkPolicyPort `json:"ports,omitempty"` + // +optional +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=100 + Protocols *[]ClusterNetworkPolicyProtocol `json:"protocols,omitempty"` } // ClusterNetworkPolicyRuleAction string describes the ClusterNetworkPolicy diff --git a/config/crd/experimental/policy.networking.k8s.io_clusternetworkpolicies.yaml b/config/crd/experimental/policy.networking.k8s.io_clusternetworkpolicies.yaml index ff819bce..d24f94eb 100644 --- a/config/crd/experimental/policy.networking.k8s.io_clusternetworkpolicies.yaml +++ b/config/crd/experimental/policy.networking.k8s.io_clusternetworkpolicies.yaml @@ -100,61 +100,75 @@ spec: for any applied AdminNetworkPolicies. maxLength: 100 type: string - ports: + protocols: description: |- - Ports allows for matching traffic based on port and protocols. - This field is a list of destination ports for the outgoing egress traffic. - If Ports is not set then the rule does not filter traffic via port. + Protocols allows for matching traffic based on port and protocols. This + field is a list of destination protocol/ports for the outgoing egress + traffic. If this field is not set then the rule does not filter traffic + via protocol/port. This field must contain at least one item if set. items: description: |- - ClusterNetworkPolicyPort describes how to match by port. This can - only be used with protocols that use port numbers (e.g. TCP, UDP). - - Exactly one of the fields in this struct must be set. - maxProperties: 1 - minProperties: 1 + ClusterNetworkPolicyProtocol describes how to select traffic by + protocol-specific attributes. properties: - name: - description: |- - NamedPort selects a destination port on a pod based on the - ContainerPort name. You can't use this in a rule with Nodes - or Networks peers, because they do not have named ports. - - - type: string - number: - description: Port selects the port by number. - format: int32 - type: integer - range: - description: PortRange selects the port by range. + port: + description: Specific port to match against. + maxProperties: 1 + minProperties: 1 properties: - end: - description: |- - End defines a network port that is the end of a port range, the End value - must be greater than Start. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - start: + name: description: |- - Start defines a network port that is the start of a port range, the Start - value must be less than End. + NamedPort selects a destination port on a pod based on the + ContainerPort name. You can't use this in a rule with Nodes + or Networks peers, because they do not have named ports. + + + type: string + number: + description: Port selects the port by number. format: int32 - maximum: 65535 - minimum: 1 type: integer - required: - - end - - start + range: + description: PortRange selects the port by range. + properties: + end: + description: |- + End defines a network port that is the end of a port range, the End value + must be greater than Start. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + start: + description: |- + Start defines a network port that is the start of a port range, the Start + value must be less than End. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - end + - start + type: object + x-kubernetes-validations: + - message: Start port must be less than End port + rule: self.start < self.end type: object - x-kubernetes-validations: - - message: Start port must be less than End port - rule: self.start < self.end + protocol: + default: TCP + description: |- + Protocol is the network protocol (TCP, UDP, or SCTP) which + traffic must match. If not specified, this field defaults + to TCP. + type: string type: object - maxItems: 25 - minItems: 1 + x-kubernetes-validations: + - message: port must be specified for protocols that support + ports + rule: '!(self.protocol in [''TCP'', ''UDP'', ''SCTP'']) + || has(self.port)' + maxItems: 100 type: array to: description: |- diff --git a/config/crd/standard/policy.networking.k8s.io_clusternetworkpolicies.yaml b/config/crd/standard/policy.networking.k8s.io_clusternetworkpolicies.yaml index 8cadbda9..9d532774 100644 --- a/config/crd/standard/policy.networking.k8s.io_clusternetworkpolicies.yaml +++ b/config/crd/standard/policy.networking.k8s.io_clusternetworkpolicies.yaml @@ -100,53 +100,67 @@ spec: for any applied AdminNetworkPolicies. maxLength: 100 type: string - ports: + protocols: description: |- - Ports allows for matching traffic based on port and protocols. - This field is a list of destination ports for the outgoing egress traffic. - If Ports is not set then the rule does not filter traffic via port. + Protocols allows for matching traffic based on port and protocols. This + field is a list of destination protocol/ports for the outgoing egress + traffic. If this field is not set then the rule does not filter traffic + via protocol/port. This field must contain at least one item if set. items: description: |- - ClusterNetworkPolicyPort describes how to match by port. This can - only be used with protocols that use port numbers (e.g. TCP, UDP). - - Exactly one of the fields in this struct must be set. - maxProperties: 1 - minProperties: 1 + ClusterNetworkPolicyProtocol describes how to select traffic by + protocol-specific attributes. properties: - number: - description: Port selects the port by number. - format: int32 - type: integer - range: - description: PortRange selects the port by range. + port: + description: Specific port to match against. + maxProperties: 1 + minProperties: 1 properties: - end: - description: |- - End defines a network port that is the end of a port range, the End value - must be greater than Start. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - start: - description: |- - Start defines a network port that is the start of a port range, the Start - value must be less than End. + number: + description: Port selects the port by number. format: int32 - maximum: 65535 - minimum: 1 type: integer - required: - - end - - start + range: + description: PortRange selects the port by range. + properties: + end: + description: |- + End defines a network port that is the end of a port range, the End value + must be greater than Start. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + start: + description: |- + Start defines a network port that is the start of a port range, the Start + value must be less than End. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - end + - start + type: object + x-kubernetes-validations: + - message: Start port must be less than End port + rule: self.start < self.end type: object - x-kubernetes-validations: - - message: Start port must be less than End port - rule: self.start < self.end + protocol: + default: TCP + description: |- + Protocol is the network protocol (TCP, UDP, or SCTP) which + traffic must match. If not specified, this field defaults + to TCP. + type: string type: object - maxItems: 25 - minItems: 1 + x-kubernetes-validations: + - message: port must be specified for protocols that support + ports + rule: '!(self.protocol in [''TCP'', ''UDP'', ''SCTP'']) + || has(self.port)' + maxItems: 100 type: array to: description: |- diff --git a/pkg/client/applyconfiguration/apis/v1alpha2/clusternetworkpolicyegressrule.go b/pkg/client/applyconfiguration/apis/v1alpha2/clusternetworkpolicyegressrule.go index 520a3516..1f7427da 100644 --- a/pkg/client/applyconfiguration/apis/v1alpha2/clusternetworkpolicyegressrule.go +++ b/pkg/client/applyconfiguration/apis/v1alpha2/clusternetworkpolicyegressrule.go @@ -25,10 +25,10 @@ import ( // ClusterNetworkPolicyEgressRuleApplyConfiguration represents a declarative configuration of the ClusterNetworkPolicyEgressRule type for use // with apply. type ClusterNetworkPolicyEgressRuleApplyConfiguration struct { - Name *string `json:"name,omitempty"` - Action *apisv1alpha2.ClusterNetworkPolicyRuleAction `json:"action,omitempty"` - To []ClusterNetworkPolicyEgressPeerApplyConfiguration `json:"to,omitempty"` - Ports *[]ClusterNetworkPolicyPortApplyConfiguration `json:"ports,omitempty"` + Name *string `json:"name,omitempty"` + Action *apisv1alpha2.ClusterNetworkPolicyRuleAction `json:"action,omitempty"` + To []ClusterNetworkPolicyEgressPeerApplyConfiguration `json:"to,omitempty"` + Protocols *[]ClusterNetworkPolicyProtocolApplyConfiguration `json:"protocols,omitempty"` } // ClusterNetworkPolicyEgressRuleApplyConfiguration constructs a declarative configuration of the ClusterNetworkPolicyEgressRule type for use with @@ -66,22 +66,22 @@ func (b *ClusterNetworkPolicyEgressRuleApplyConfiguration) WithTo(values ...*Clu return b } -func (b *ClusterNetworkPolicyEgressRuleApplyConfiguration) ensureClusterNetworkPolicyPortApplyConfigurationExists() { - if b.Ports == nil { - b.Ports = &[]ClusterNetworkPolicyPortApplyConfiguration{} +func (b *ClusterNetworkPolicyEgressRuleApplyConfiguration) ensureClusterNetworkPolicyProtocolApplyConfigurationExists() { + if b.Protocols == nil { + b.Protocols = &[]ClusterNetworkPolicyProtocolApplyConfiguration{} } } -// WithPorts adds the given value to the Ports field in the declarative configuration +// WithProtocols adds the given value to the Protocols field in the declarative configuration // and returns the receiver, so that objects can be build by chaining "With" function invocations. -// If called multiple times, values provided by each call will be appended to the Ports field. -func (b *ClusterNetworkPolicyEgressRuleApplyConfiguration) WithPorts(values ...*ClusterNetworkPolicyPortApplyConfiguration) *ClusterNetworkPolicyEgressRuleApplyConfiguration { - b.ensureClusterNetworkPolicyPortApplyConfigurationExists() +// If called multiple times, values provided by each call will be appended to the Protocols field. +func (b *ClusterNetworkPolicyEgressRuleApplyConfiguration) WithProtocols(values ...*ClusterNetworkPolicyProtocolApplyConfiguration) *ClusterNetworkPolicyEgressRuleApplyConfiguration { + b.ensureClusterNetworkPolicyProtocolApplyConfigurationExists() for i := range values { if values[i] == nil { - panic("nil value passed to WithPorts") + panic("nil value passed to WithProtocols") } - *b.Ports = append(*b.Ports, *values[i]) + *b.Protocols = append(*b.Protocols, *values[i]) } return b } From c6c47cce2e53791d6916cf4e51ef97c8c2ac6807 Mon Sep 17 00:00:00 2001 From: Bowei Du Date: Wed, 15 Oct 2025 10:45:32 -0700 Subject: [PATCH 3/7] regenerate deepcopy --- apis/v1alpha2/zz_generated.deepcopy.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apis/v1alpha2/zz_generated.deepcopy.go b/apis/v1alpha2/zz_generated.deepcopy.go index dbd24c31..e3df66e4 100644 --- a/apis/v1alpha2/zz_generated.deepcopy.go +++ b/apis/v1alpha2/zz_generated.deepcopy.go @@ -102,12 +102,12 @@ func (in *ClusterNetworkPolicyEgressRule) DeepCopyInto(out *ClusterNetworkPolicy (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.Ports != nil { - in, out := &in.Ports, &out.Ports - *out = new([]ClusterNetworkPolicyPort) + if in.Protocols != nil { + in, out := &in.Protocols, &out.Protocols + *out = new([]ClusterNetworkPolicyProtocol) if **in != nil { in, out := *in, *out - *out = make([]ClusterNetworkPolicyPort, len(*in)) + *out = make([]ClusterNetworkPolicyProtocol, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } From 10a760226b0319d4a1abada05901c5dd2891f14f Mon Sep 17 00:00:00 2001 From: Bowei Du Date: Wed, 15 Oct 2025 12:41:40 -0700 Subject: [PATCH 4/7] Update conformance tests to match new Protocols structure --- .../tests/admin-network-policy-experimental-egress-rules.go | 6 ++++-- .../admin-network-policy-experimental-ingress-rules.go | 6 ++++-- ...seline-admin-network-policy-experimental-egress-rules.go | 6 ++++-- ...eline-admin-network-policy-experimental-ingress-rules.go | 6 ++++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/conformance/tests/admin-network-policy-experimental-egress-rules.go b/conformance/tests/admin-network-policy-experimental-egress-rules.go index ef84a163..5bcdc442 100644 --- a/conformance/tests/admin-network-policy-experimental-egress-rules.go +++ b/conformance/tests/admin-network-policy-experimental-egress-rules.go @@ -67,9 +67,11 @@ var CNPAdminTierEgressNamedPort = suite.ConformanceTest{ namedPortRule := mutate.Spec.Egress[5] webPort := "web" // replace the tcp port 8080 rule as named port rule which translate to tcp port 80 instead - namedPortRule.Ports = &[]api.ClusterNetworkPolicyPort{ + namedPortRule.Protocols = &[]api.ClusterNetworkPolicyProtocol{ { - NamedPort: &webPort, + Port: &api.ClusterNetworkPolicyPort{ + Name: &webPort, + }, }, } mutate.Spec.Egress[5] = namedPortRule diff --git a/conformance/tests/admin-network-policy-experimental-ingress-rules.go b/conformance/tests/admin-network-policy-experimental-ingress-rules.go index 636c802e..73ef4c5f 100644 --- a/conformance/tests/admin-network-policy-experimental-ingress-rules.go +++ b/conformance/tests/admin-network-policy-experimental-ingress-rules.go @@ -60,9 +60,11 @@ var CNPAdminTierIngressNamedPort = suite.ConformanceTest{ dnsPortRule := mutate.DeepCopy().Spec.Ingress[5] dnsPort := "dns" // rewrite the udp port 53 rule as named port rule - dnsPortRule.Ports = &[]api.ClusterNetworkPolicyPort{ + dnsPortRule.Protocols = &[]api.ClusterNetworkPolicyProtocol{ { - NamedPort: &dnsPort, + Port: &api.ClusterNetworkPolicyPort{ + Name: &dnsPort, + }, }, } mutate.Spec.Ingress[5] = dnsPortRule diff --git a/conformance/tests/baseline-admin-network-policy-experimental-egress-rules.go b/conformance/tests/baseline-admin-network-policy-experimental-egress-rules.go index 3e9bc11c..403bf97d 100644 --- a/conformance/tests/baseline-admin-network-policy-experimental-egress-rules.go +++ b/conformance/tests/baseline-admin-network-policy-experimental-egress-rules.go @@ -67,9 +67,11 @@ var CNPBaselineTierEgressNamedPort = suite.ConformanceTest{ dnsPortRule := mutate.Spec.Egress[3] dnsPort := "dns" // rewrite the udp port 53 rule as named port rule - dnsPortRule.Ports = &[]api.ClusterNetworkPolicyPort{ + dnsPortRule.Protocols = &[]api.ClusterNetworkPolicyProtocol{ { - NamedPort: &dnsPort, + Port: &api.ClusterNetworkPolicyPort{ + Name: &dnsPort, + }, }, } mutate.Spec.Egress[3] = dnsPortRule diff --git a/conformance/tests/baseline-admin-network-policy-experimental-ingress-rules.go b/conformance/tests/baseline-admin-network-policy-experimental-ingress-rules.go index e674e8a8..2196886b 100644 --- a/conformance/tests/baseline-admin-network-policy-experimental-ingress-rules.go +++ b/conformance/tests/baseline-admin-network-policy-experimental-ingress-rules.go @@ -66,9 +66,11 @@ var CNPBaselineTierIngressNamedPort = suite.ConformanceTest{ namedPortRule := mutate.Spec.Ingress[3] webPort := "web" // rewrite the tcp port 80 rule as named port rule - namedPortRule.Ports = &[]api.ClusterNetworkPolicyPort{ + namedPortRule.Protocols = &[]api.ClusterNetworkPolicyProtocol{ { - NamedPort: &webPort, + Port: &api.ClusterNetworkPolicyPort{ + Name: &webPort, + }, }, } mutate.Spec.Ingress[3] = namedPortRule From 53eef9d37e146ee19c5546a857bea9226bdbebe2 Mon Sep 17 00:00:00 2001 From: Bowei Du Date: Wed, 15 Oct 2025 12:42:04 -0700 Subject: [PATCH 5/7] Extract the github workflow to a script This allows a user to run the github workflow manually without github --- .github/workflows/conformance.yml | 68 ++-------- hack/run-conformance.sh | 203 ++++++++++++++++++++++++++++++ 2 files changed, 211 insertions(+), 60 deletions(-) create mode 100755 hack/run-conformance.sh diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml index 32605b6e..cb135ee6 100644 --- a/.github/workflows/conformance.yml +++ b/.github/workflows/conformance.yml @@ -38,83 +38,31 @@ jobs: - name: Enable ipv4 and ipv6 forwarding run: | - sudo sysctl -w net.ipv6.conf.all.forwarding=1 - sudo sysctl -w net.ipv4.ip_forward=1 + ./hack/run-conformance.sh enable_ipv4_and_ipv6_forwarding - name: Set up environment (download dependencies) run: | - TMP_DIR=$(mktemp -d) - # kubectl - curl -L https://dl.k8s.io/${{ env.K8S_VERSION }}/bin/linux/amd64/kubectl -o ${TMP_DIR}/kubectl - # kind - curl -Lo ${TMP_DIR}/kind https://kind.sigs.k8s.io/dl/${{ env.KIND_VERSION }}/kind-linux-amd64 - # Install - sudo cp ${TMP_DIR}/kubectl /usr/local/bin/kubectl - sudo cp ${TMP_DIR}/kind /usr/local/bin/kind - sudo chmod +x /usr/local/bin/kubectl /usr/local/bin/kind + ./hack/run-conformance.sh setup_environment - name: Create multi node cluster run: | - # output_dir - mkdir -p _artifacts - # create cluster - cat < _artifacts/kubeconfig.conf + ./hack/run-conformance.sh create_multinode_cluster - name: Install network policy APIs run: | - /usr/local/bin/kubectl apply -f ./config/crd/standard/policy.networking.k8s.io_clusternetworkpolicies.yaml + ./hack/run-conformance.sh install_network_policy_apis - name: Install kube-network-policies from main run: | - TEMP_DIR=$(mktemp -d) - cleanup() { rm -rf "${TEMP_DIR}"; } - trap cleanup EXIT INT TERM - ( - cd $TEMP_DIR - # Clone the repo - git clone --depth 1 https://github.com/kubernetes-sigs/kube-network-policies.git - cd kube-network-policies/ - # Build the image with the network policy API support - REGISTRY="registry.k8s.io/networking" IMAGE_NAME="kube-network-policies" TAG="test" make image-build-npa-${{ env.NPAPI_VERSION }} - # Preload the image in the kind cluster - /usr/local/bin/kind load docker-image registry.k8s.io/networking/kube-network-policies:test-npa-${{ env.NPAPI_VERSION }} --name ${{ env.KIND_CLUSTER_NAME}} - # Install kube-network-policies with the image built from main - sed -i s#registry.k8s.io/networking/kube-network-policies.*#registry.k8s.io/networking/kube-network-policies:test-npa-${{ env.NPAPI_VERSION }}# install-cnp.yaml - /usr/local/bin/kubectl apply -f ./install-cnp.yaml - ) + ./hack/run-conformance.sh install_kube_network_policies_from_main - name: Get Cluster status run: | - # wait network is ready - sleep 5 - /usr/local/bin/kubectl get nodes -o wide - /usr/local/bin/kubectl get pods -A - /usr/local/bin/kubectl wait --timeout=1m --for=condition=ready pods --namespace=kube-system -l k8s-app=kube-dns - /usr/local/bin/kubectl wait --timeout=1m --for=condition=ready pods --namespace=kube-system -l app=kube-network-policies + ./hack/run-conformance.sh get_cluster_status - name: Run tests run: | - go mod download - REPO_VERSION=$(git describe --always --dirty) - go test -v ./conformance -run TestConformanceProfiles -args --conformance-profiles=ClusterNetworkPolicy --organization=kubernetes --project=kube-network-policies --url=https://github.com/kubernetes-sigs/kube-network-policies --version=${REPO_VERSION} --contact=https://github.com/kubernetes-sigs/kube-network-policies/issues/new --additional-info=https://github.com/kubernetes-sigs/kube-network-policies + ./hack/run-conformance.sh run_tests - name: Upload Junit Reports if: always() @@ -126,7 +74,7 @@ jobs: - name: Export logs if: always() run: | - /usr/local/bin/kind export logs --name ${KIND_CLUSTER_NAME} -v7 ./_artifacts/logs + ./hack/run-conformance.sh export_logs - name: Upload logs if: always() diff --git a/hack/run-conformance.sh b/hack/run-conformance.sh new file mode 100755 index 00000000..76fca8c4 --- /dev/null +++ b/hack/run-conformance.sh @@ -0,0 +1,203 @@ +#!/usr/bin/env bash + +# Copyright 2024 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script is a helper script to run the conformance tests locally. +# It is a translation of the .github/workflows/conformance.yml file. + +set -o errexit +set -o nounset +set -o pipefail + +# +# All the following variables are inherited from the github workflow +# +# The github workflow sets the IP_FAMILY using the matrix strategy. +# For this script we default to ipv4, but can be overridden by setting the +# IP_FAMILY environment variable. +IP_FAMILY="${IP_FAMILY:-ipv4}" +GO_VERSION="${GO_VERSION:-1.24}" +K8S_VERSION="${K8S_VERSION:-v1.33.0}" +KIND_VERSION="${KIND_VERSION:-v0.30.0}" +IMAGE_NAME="${IMAGE_NAME:-registry.k8s.io/networking/kube-network-policies}" +KIND_CLUSTER_NAME="${KIND_CLUSTER_NAME:-kind}" +NPAPI_VERSION="${NPAPI_VERSION:-v1alpha2}" + +# +# The following functions are a translation of the steps in the github workflow +# +enable_ipv4_and_ipv6_forwarding() { + echo "Enabling ipv4 and ipv6 forwarding" + sudo sysctl -w net.ipv6.conf.all.forwarding=1 + sudo sysctl -w net.ipv4.ip_forward=1 +} + +setup_environment() { + echo "Setting up environment (download dependencies)" + TMP_DIR=$(mktemp -d) + # kubectl + curl -L https://dl.k8s.io/"${K8S_VERSION}"/bin/linux/amd64/kubectl -o "${TMP_DIR}"/kubectl + # kind + curl -Lo "${TMP_DIR}"/kind https://kind.sigs.k8s.io/dl/"${KIND_VERSION}"/kind-linux-amd64 + # Install + sudo cp "${TMP_DIR}"/kubectl /usr/local/bin/kubectl + sudo cp "${TMP_DIR}"/kind /usr/local/bin/kind + sudo chmod +x /usr/local/bin/kubectl /usr/local/bin/kind +} + +create_multinode_cluster() { + echo "Creating multi node cluster" + # output_dir + mkdir -p _artifacts + # create cluster + cat < _artifacts/kubeconfig.conf +} + +install_network_policy_apis() { + echo "Installing network policy APIs" + /usr/local/bin/kubectl apply -f ./config/crd/standard/policy.networking.k8s.io_clusternetworkpolicies.yaml +} + +install_kube_network_policies_from_main() { + echo "Installing kube-network-policies from main" + TEMP_DIR=$(mktemp -d) + cleanup() { rm -rf "${TEMP_DIR}"; } + trap cleanup EXIT INT TERM + ( + cd "$TEMP_DIR" + # Clone the repo + git clone --depth 1 https://github.com/kubernetes-sigs/kube-network-policies.git + cd kube-network-policies/ + # Build the image with the network policy API support + REGISTRY="registry.k8s.io/networking" IMAGE_NAME="kube-network-policies" TAG="test" make image-build-npa-"${NPAPI_VERSION}" + # Preload the image in the kind cluster + /usr/local/bin/kind load docker-image registry.k8s.io/networking/kube-network-policies:test-npa-"${NPAPI_VERSION}" --name "${KIND_CLUSTER_NAME}" + # Install kube-network-policies with the image built from main + sed -i s#registry.k8s.io/networking/kube-network-policies.*#registry.k8s.io/networking/kube-network-policies:test-npa-${NPAPI_VERSION}# install-cnp.yaml + /usr/local/bin/kubectl apply -f ./install-cnp.yaml + ) +} + +get_cluster_status() { + echo "Getting cluster status" + # wait network is ready + sleep 5 + /usr/local/bin/kubectl get nodes -o wide + /usr/local/bin/kubectl get pods -A + /usr/local/bin/kubectl wait --timeout=1m --for=condition=ready pods --namespace=kube-system -l k8s-app=kube-dns + /usr/local/bin/kubectl wait --timeout=1m --for=condition=ready pods --namespace=kube-system -l app=kube-network-policies +} + +run_tests() { + echo "Running tests" + go mod download + REPO_VERSION=$(git describe --always --dirty) + go test -v ./conformance -run TestConformanceProfiles -args --conformance-profiles=ClusterNetworkPolicy --organization=kubernetes --project=kube-network-policies --url=https://github.com/kubernetes-sigs/kube-network-policies --version="${REPO_VERSION}" --contact=https://github.com/kubernetes-sigs/kube-network-policies/issues/new --additional-info=https://github.com/kubernetes-sigs/kube-network-policies +} + +export_logs() { + echo "Exporting logs" + /usr/local/bin/kind export logs --name "${KIND_CLUSTER_NAME}" -v7 ./_artifacts/logs +} + +# TODO: make this script execute multiple steps if specified as args in the +# order the steps are specified. +# +# run-conformance.sh setup_environment run_tests +# +# Will execute setup_environment, then run_tests. +# + +usage() { + echo "Usage: $0 [commands]" + echo "Commands:" + echo " enable_ipv4_and_ipv6_forwarding" + echo " setup_environment" + echo " create_multinode_cluster" + echo " install_network_policy_apis" + echo " install_kube_network_policies_from_main" + echo " get_cluster_status" + echo " run_tests" + echo " export_logs" + echo " all" +} + +all() { + enable_ipv4_and_ipv6_forwarding + setup_environment + create_multinode_cluster + install_network_policy_apis + install_kube_network_policies_from_main + get_cluster_status + run_tests + export_logs +} + +if [ "$#" -eq 0 ]; then + usage + exit 1 +fi + +case "$1" in + enable_ipv4_and_ipv6_forwarding) + enable_ipv4_and_ipv6_forwarding + ;; + setup_environment) + setup_environment + ;; + create_multinode_cluster) + create_multinode_cluster + ;; + install_network_policy_apis) + install_network_policy_apis + ;; + install_kube_network_policies_from_main) + install_kube_network_policies_from_main + ;; + get_cluster_status) + get_cluster_status + ;; + run_tests) + run_tests + ;; + export_logs) + export_logs + ;; + all) + all + ;; + *) + usage + exit 1 + ;; +esac From 4b8edf6e92e0303245a580644ec53b5f85f3b26e Mon Sep 17 00:00:00 2001 From: Bowei Du Date: Wed, 15 Oct 2025 13:27:59 -0700 Subject: [PATCH 6/7] Cleanup the conformance script --- hack/run-conformance.sh | 259 ++++++++++++++++++++++++---------------- 1 file changed, 155 insertions(+), 104 deletions(-) diff --git a/hack/run-conformance.sh b/hack/run-conformance.sh index 76fca8c4..4bab2e38 100755 --- a/hack/run-conformance.sh +++ b/hack/run-conformance.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright 2024 The Kubernetes Authors. +# Copyright 2025 The Kubernetes Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,19 +14,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This script is a helper script to run the conformance tests locally. -# It is a translation of the .github/workflows/conformance.yml file. - set -o errexit set -o nounset set -o pipefail -# -# All the following variables are inherited from the github workflow -# -# The github workflow sets the IP_FAMILY using the matrix strategy. -# For this script we default to ipv4, but can be overridden by setting the -# IP_FAMILY environment variable. +KUBECTL=$(which kubectl) +KIND=$(which kind) + +echo "[RUN] found KUBECTL=${KUBECTL}" +echo "[RUN] found KIND=${KIND}" + +# These values will be overridden by the github workflow vars. IP_FAMILY="${IP_FAMILY:-ipv4}" GO_VERSION="${GO_VERSION:-1.24}" K8S_VERSION="${K8S_VERSION:-v1.33.0}" @@ -35,18 +33,28 @@ IMAGE_NAME="${IMAGE_NAME:-registry.k8s.io/networking/kube-network-policies}" KIND_CLUSTER_NAME="${KIND_CLUSTER_NAME:-kind}" NPAPI_VERSION="${NPAPI_VERSION:-v1alpha2}" -# -# The following functions are a translation of the steps in the github workflow -# +CLEANUP_ON_EXIT="${CLEANUP_ON_EXIT:-true}" +TMP_DIR=$(mktemp -d) +echo "[RUN] Using TMP_DIR='${TMP_DIR}'" + +cleanup() { + if [[ ${CLEANUP_ON_EXIT} != "true" ]]; then + echo "[RUN] Warning: not cleaning up TMP_DIR (${TMP_DIR})" + return + fi + echo "[RUN] Removing TMP_DIR ${TMP_DIR})" + rm -rf "${TMP_DIR}" +} +trap cleanup EXIT INT TERM + enable_ipv4_and_ipv6_forwarding() { - echo "Enabling ipv4 and ipv6 forwarding" + echo "[RUN] Enabling ipv4 and ipv6 forwarding" sudo sysctl -w net.ipv6.conf.all.forwarding=1 sudo sysctl -w net.ipv4.ip_forward=1 } setup_environment() { - echo "Setting up environment (download dependencies)" - TMP_DIR=$(mktemp -d) + echo "[RUN] Setting up environment (download dependencies)" # kubectl curl -L https://dl.k8s.io/"${K8S_VERSION}"/bin/linux/amd64/kubectl -o "${TMP_DIR}"/kubectl # kind @@ -55,101 +63,129 @@ setup_environment() { sudo cp "${TMP_DIR}"/kubectl /usr/local/bin/kubectl sudo cp "${TMP_DIR}"/kind /usr/local/bin/kind sudo chmod +x /usr/local/bin/kubectl /usr/local/bin/kind + + KUBECTL="/usr/local/bin/kubectl" + KIND="/usr/local/bin/kind" + + echo "[RUN] using KUBECTL=${KUBECTL}" + echo "[RUN] using KIND=${KIND}" } create_multinode_cluster() { - echo "Creating multi node cluster" + echo "[RUN] Creating multi node cluster" # output_dir mkdir -p _artifacts # create cluster - cat < _artifacts/kubeconfig.conf + ${KIND} get kubeconfig --name "${KIND_CLUSTER_NAME}" > _artifacts/kubeconfig.conf } install_network_policy_apis() { - echo "Installing network policy APIs" - /usr/local/bin/kubectl apply -f ./config/crd/standard/policy.networking.k8s.io_clusternetworkpolicies.yaml + echo "[RUN] Installing network policy APIs" + ${KUBECTL} apply -f ./config/crd/standard/policy.networking.k8s.io_clusternetworkpolicies.yaml } install_kube_network_policies_from_main() { - echo "Installing kube-network-policies from main" - TEMP_DIR=$(mktemp -d) - cleanup() { rm -rf "${TEMP_DIR}"; } - trap cleanup EXIT INT TERM - ( - cd "$TEMP_DIR" + echo "[RUN] Installing kube-network-policies from main" + ( # Subshell to preserve cwd. + cd "$TMP_DIR" # Clone the repo git clone --depth 1 https://github.com/kubernetes-sigs/kube-network-policies.git cd kube-network-policies/ # Build the image with the network policy API support - REGISTRY="registry.k8s.io/networking" IMAGE_NAME="kube-network-policies" TAG="test" make image-build-npa-"${NPAPI_VERSION}" + REGISTRY="registry.k8s.io/networking" IMAGE_NAME="kube-network-policies" TAG="test" \ + make image-build-npa-"${NPAPI_VERSION}" # Preload the image in the kind cluster - /usr/local/bin/kind load docker-image registry.k8s.io/networking/kube-network-policies:test-npa-"${NPAPI_VERSION}" --name "${KIND_CLUSTER_NAME}" + ${KIND} \ + load docker-image registry.k8s.io/networking/kube-network-policies:test-npa-"${NPAPI_VERSION}" \ + --name "${KIND_CLUSTER_NAME}" # Install kube-network-policies with the image built from main - sed -i s#registry.k8s.io/networking/kube-network-policies.*#registry.k8s.io/networking/kube-network-policies:test-npa-${NPAPI_VERSION}# install-cnp.yaml - /usr/local/bin/kubectl apply -f ./install-cnp.yaml + sed -i "s#registry.k8s.io/networking/kube-network-policies.*#registry.k8s.io/networking/kube-network-policies:test-npa-${NPAPI_VERSION}# install-cnp.yaml" + ${KUBECTL} apply -f ./install-cnp.yaml ) } get_cluster_status() { - echo "Getting cluster status" - # wait network is ready + echo "[RUN] Getting cluster status" + # wait for the network to be ready sleep 5 - /usr/local/bin/kubectl get nodes -o wide - /usr/local/bin/kubectl get pods -A - /usr/local/bin/kubectl wait --timeout=1m --for=condition=ready pods --namespace=kube-system -l k8s-app=kube-dns - /usr/local/bin/kubectl wait --timeout=1m --for=condition=ready pods --namespace=kube-system -l app=kube-network-policies + ${KUBECTL} get nodes -o wide + ${KUBECTL} get pods -A + ${KUBECTL} wait \ + --timeout=1m \ + --for=condition=ready pods \ + --namespace=kube-system \ + -l k8s-app=kube-dns + ${KUBECTL} wait \ + --timeout=1m \ + --for=condition=ready pods \ + --namespace=kube-system \ + -l app=kube-network-policies } run_tests() { - echo "Running tests" + echo "[RUN] Running tests" go mod download REPO_VERSION=$(git describe --always --dirty) - go test -v ./conformance -run TestConformanceProfiles -args --conformance-profiles=ClusterNetworkPolicy --organization=kubernetes --project=kube-network-policies --url=https://github.com/kubernetes-sigs/kube-network-policies --version="${REPO_VERSION}" --contact=https://github.com/kubernetes-sigs/kube-network-policies/issues/new --additional-info=https://github.com/kubernetes-sigs/kube-network-policies + go test -v ./conformance \ + -run TestConformanceProfiles \ + -args \ + --conformance-profiles=ClusterNetworkPolicy \ + --organization=kubernetes \ + --project=kube-network-policies \ + --url=https://github.com/kubernetes-sigs/kube-network-policies \ + --version="${REPO_VERSION}" \ + --contact=https://github.com/kubernetes-sigs/kube-network-policies/issues/new \ + --additional-info=https://github.com/kubernetes-sigs/kube-network-policies } export_logs() { - echo "Exporting logs" - /usr/local/bin/kind export logs --name "${KIND_CLUSTER_NAME}" -v7 ./_artifacts/logs + echo "[RUN] Exporting logs" + ${KIND} export logs --name "${KIND_CLUSTER_NAME}" -v7 ./_artifacts/logs } -# TODO: make this script execute multiple steps if specified as args in the -# order the steps are specified. -# -# run-conformance.sh setup_environment run_tests -# -# Will execute setup_environment, then run_tests. -# - usage() { - echo "Usage: $0 [commands]" - echo "Commands:" - echo " enable_ipv4_and_ipv6_forwarding" - echo " setup_environment" - echo " create_multinode_cluster" - echo " install_network_policy_apis" - echo " install_kube_network_policies_from_main" - echo " get_cluster_status" - echo " run_tests" - echo " export_logs" - echo " all" + cat <&2 "Invalid command: $arg" + usage + exit 1 + ;; + esac +done From 2cd78247e116804137f37191f26f4dfe3543a743 Mon Sep 17 00:00:00 2001 From: Bowei Du Date: Wed, 15 Oct 2025 17:04:10 -0700 Subject: [PATCH 7/7] run-conformance --- hack/run-conformance.sh | 167 +++++++++++++++++++++++----------------- 1 file changed, 98 insertions(+), 69 deletions(-) diff --git a/hack/run-conformance.sh b/hack/run-conformance.sh index 4bab2e38..9671e6f5 100755 --- a/hack/run-conformance.sh +++ b/hack/run-conformance.sh @@ -18,13 +18,58 @@ set -o errexit set -o nounset set -o pipefail -KUBECTL=$(which kubectl) -KIND=$(which kind) +usage() { + cat < _artifacts/kubeconfig.conf + local kindnetd_image="docker.io/kindest/kindnetd:v20230809-80a64d96" + ${KUBECTL} -n kube-system set image ds kindnet kindnet-cni="${kindnetd_image}" + + # dump the kubeconfig + ${KIND} get kubeconfig --name "${KIND_CLUSTER_NAME}" > "${ARTIFACTS_DIR}/kubeconfig.conf" } -install_network_policy_apis() { +install_apis() { echo "[RUN] Installing network policy APIs" ${KUBECTL} apply -f ./config/crd/standard/policy.networking.k8s.io_clusternetworkpolicies.yaml } -install_kube_network_policies_from_main() { +install_np_impl() { echo "[RUN] Installing kube-network-policies from main" ( # Subshell to preserve cwd. cd "$TMP_DIR" @@ -159,58 +224,22 @@ run_tests() { export_logs() { echo "[RUN] Exporting logs" - ${KIND} export logs --name "${KIND_CLUSTER_NAME}" -v7 ./_artifacts/logs -} - -usage() { - cat <