Skip to content

Commit

Permalink
Add EndPort to Network Policy - Alpha (#97058)
Browse files Browse the repository at this point in the history
* Fix merge conflict in kube_features

* Add alpha support for EndPort in Network Policy

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Add alpha support for EndPort in Network Policy

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Add alpha support for EndPort in Network Policy

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Correct some nits

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Add alpha support for EndPort in Network Policy

* Add alpha support for EndPort in Network Policy

* Add alpha support for EndPort in Network Policy

* Add alpha support for EndPort in Network Policy
  • Loading branch information
rikatz authored Feb 2, 2021
1 parent 7e6ef0e commit b7c82bb
Show file tree
Hide file tree
Showing 27 changed files with 1,181 additions and 427 deletions.
7 changes: 6 additions & 1 deletion api/openapi-spec/swagger.json

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

2 changes: 2 additions & 0 deletions pkg/apis/extensions/v1beta1/zz_generated.conversion.go

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

15 changes: 13 additions & 2 deletions pkg/apis/networking/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,21 @@ type NetworkPolicyPort struct {
// +optional
Protocol *api.Protocol

// The port on the given protocol. This can either be a numerical or named port on
// a pod. If this field is not provided, this matches all port names and numbers.
// The port on the given protocol. This can either be a numerical or named
// port on a pod. If this field is not provided, this matches all port names and
// numbers.
// If present, only traffic on the specified protocol AND port will be matched.
// +optional
Port *intstr.IntOrString

// If set, indicates that the range of ports from port to endPort, inclusive,
// should be allowed by the policy. This field cannot be defined if the port field
// is not defined or if the port field is defined as a named (string) port.
// The endPort must be equal or greater than port.
// This feature is in Alpha state and should be enabled using the Feature Gate
// "NetworkPolicyEndPort".
// +optional
EndPort *int32
}

// IPBlock describes a particular CIDR (Ex. "192.168.1.1/24","2001:db9::/64") that is allowed
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/networking/v1/zz_generated.conversion.go

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

10 changes: 10 additions & 0 deletions pkg/apis/networking/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,21 @@ func ValidateNetworkPolicyPort(port *networking.NetworkPolicyPort, portPath *fie
for _, msg := range validation.IsValidPortNum(int(port.Port.IntVal)) {
allErrs = append(allErrs, field.Invalid(portPath.Child("port"), port.Port.IntVal, msg))
}
if port.EndPort != nil && *port.EndPort < port.Port.IntVal {
allErrs = append(allErrs, field.Invalid(portPath.Child("endPort"), port.Port.IntVal, "must be greater than or equal to `port`"))
}
} else {
if port.EndPort != nil {
allErrs = append(allErrs, field.Invalid(portPath.Child("endPort"), *port.EndPort, "may not be specified when `port` is non-numeric"))
}
for _, msg := range validation.IsValidPortName(port.Port.StrVal) {
allErrs = append(allErrs, field.Invalid(portPath.Child("port"), port.Port.StrVal, msg))
}
}
} else {
if port.EndPort != nil {
allErrs = append(allErrs, field.Invalid(portPath.Child("endPort"), *port.EndPort, "may not be specified when `port` is not specified"))
}
}

return allErrs
Expand Down
222 changes: 221 additions & 1 deletion pkg/apis/networking/validation/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func TestValidateNetworkPolicy(t *testing.T) {
protocolUDP := api.ProtocolUDP
protocolICMP := api.Protocol("ICMP")
protocolSCTP := api.ProtocolSCTP

endPort := int32(32768)
successCases := []networking.NetworkPolicy{
{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
Expand Down Expand Up @@ -377,6 +377,78 @@ func TestValidateNetworkPolicy(t *testing.T) {
PolicyTypes: []networking.PolicyType{networking.PolicyTypeIngress, networking.PolicyTypeEgress},
},
},
{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
Spec: networking.NetworkPolicySpec{
PodSelector: metav1.LabelSelector{
MatchLabels: map[string]string{"a": "b"},
},
Egress: []networking.NetworkPolicyEgressRule{
{
Ports: []networking.NetworkPolicyPort{
{
Protocol: nil,
Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 32000},
EndPort: &endPort,
},
{
Protocol: &protocolUDP,
Port: &intstr.IntOrString{Type: intstr.String, StrVal: "dns"},
},
},
},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
Spec: networking.NetworkPolicySpec{
PodSelector: metav1.LabelSelector{
MatchLabels: map[string]string{"a": "b"},
},
Egress: []networking.NetworkPolicyEgressRule{
{
To: []networking.NetworkPolicyPeer{
{
NamespaceSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{"c": "d"},
},
},
},
Ports: []networking.NetworkPolicyPort{
{
Protocol: nil,
Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 30000},
EndPort: &endPort,
},
{
Protocol: nil,
Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 32000},
EndPort: &endPort,
},
},
},
},
Ingress: []networking.NetworkPolicyIngressRule{
{
From: []networking.NetworkPolicyPeer{
{
PodSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{"e": "f"},
},
},
},
Ports: []networking.NetworkPolicyPort{
{
Protocol: &protocolTCP,
Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 32768},
EndPort: &endPort,
},
},
},
},
},
},
}

// Success cases are expected to pass validation.
Expand Down Expand Up @@ -798,6 +870,154 @@ func TestValidateNetworkPolicy(t *testing.T) {
PolicyTypes: []networking.PolicyType{"foo", "bar", "baz"},
},
},
"multiple ports defined, one port range is invalid": {
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
Spec: networking.NetworkPolicySpec{
PodSelector: metav1.LabelSelector{
MatchLabels: map[string]string{"a": "b"},
},
Egress: []networking.NetworkPolicyEgressRule{
{
To: []networking.NetworkPolicyPeer{
{
NamespaceSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{"c": "d"},
},
},
},
Ports: []networking.NetworkPolicyPort{
{
Protocol: &protocolUDP,
Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 35000},
EndPort: &endPort,
},
{
Protocol: nil,
Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 32000},
EndPort: &endPort,
},
},
},
},
},
},
"endPort defined with named/string port": {
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
Spec: networking.NetworkPolicySpec{
PodSelector: metav1.LabelSelector{
MatchLabels: map[string]string{"a": "b"},
},
Egress: []networking.NetworkPolicyEgressRule{
{
To: []networking.NetworkPolicyPeer{
{
NamespaceSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{"c": "d"},
},
},
},
Ports: []networking.NetworkPolicyPort{
{
Protocol: &protocolUDP,
Port: &intstr.IntOrString{Type: intstr.String, StrVal: "dns"},
EndPort: &endPort,
},
{
Protocol: nil,
Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 32000},
EndPort: &endPort,
},
},
},
},
},
},
"endPort defined without port defined": {
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
Spec: networking.NetworkPolicySpec{
PodSelector: metav1.LabelSelector{
MatchLabels: map[string]string{"a": "b"},
},
Egress: []networking.NetworkPolicyEgressRule{
{
To: []networking.NetworkPolicyPeer{
{
NamespaceSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{"c": "d"},
},
},
},
Ports: []networking.NetworkPolicyPort{
{
Protocol: &protocolTCP,
EndPort: &endPort,
},
},
},
},
},
},
"port is greater than endPort": {
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
Spec: networking.NetworkPolicySpec{
PodSelector: metav1.LabelSelector{
MatchLabels: map[string]string{"a": "b"},
},
Egress: []networking.NetworkPolicyEgressRule{
{
To: []networking.NetworkPolicyPeer{
{
NamespaceSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{"c": "d"},
},
},
},
Ports: []networking.NetworkPolicyPort{
{
Protocol: &protocolSCTP,
Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 33000},
EndPort: &endPort,
},
},
},
},
},
},
"multiple invalid port ranges defined": {
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
Spec: networking.NetworkPolicySpec{
PodSelector: metav1.LabelSelector{
MatchLabels: map[string]string{"a": "b"},
},
Egress: []networking.NetworkPolicyEgressRule{
{
To: []networking.NetworkPolicyPeer{
{
NamespaceSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{"c": "d"},
},
},
},
Ports: []networking.NetworkPolicyPort{
{
Protocol: &protocolUDP,
Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 35000},
EndPort: &endPort,
},
{
Protocol: &protocolTCP,
EndPort: &endPort,
},
{
Protocol: &protocolTCP,
Port: &intstr.IntOrString{Type: intstr.String, StrVal: "https"},
EndPort: &endPort,
},
},
},
},
},
},
}

// Error cases are not expected to pass validation.
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/networking/zz_generated.deepcopy.go

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

7 changes: 7 additions & 0 deletions pkg/features/kube_features.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,12 @@ const (
// Enables SCTP as new protocol for Service ports, NetworkPolicy, and ContainerPort in Pod/Containers definition
SCTPSupport featuregate.Feature = "SCTPSupport"

// owner: @rikatz
// alpha: v1.21
//
// Enables the endPort field in NetworkPolicy to enable a Port Range behavior in Network Policies.
NetworkPolicyEndPort featuregate.Feature = "NetworkPolicyEndPort"

// owner: @xing-yang
// alpha: v1.12
// beta: v1.17
Expand Down Expand Up @@ -729,6 +735,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
RuntimeClass: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.23
NodeLease: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
SCTPSupport: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.22
NetworkPolicyEndPort: {Default: false, PreRelease: featuregate.Alpha},
VolumeSnapshotDataSource: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.21
ProcMountType: {Default: false, PreRelease: featuregate.Alpha},
TTLAfterFinished: {Default: false, PreRelease: featuregate.Alpha},
Expand Down
Loading

0 comments on commit b7c82bb

Please sign in to comment.