Skip to content

Commit

Permalink
Add network policy controller and metalnetlet firewall rule enforceme…
Browse files Browse the repository at this point in the history
…nt with tests

Co-authored-by: Rohit Kumar <[email protected]>
  • Loading branch information
sujeet01 and Rohit-0505 committed Apr 23, 2024
1 parent a5dff1d commit 363d219
Show file tree
Hide file tree
Showing 37 changed files with 3,149 additions and 342 deletions.
21 changes: 0 additions & 21 deletions api/core/v1alpha1/common_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
package v1alpha1

import (
"net/netip"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)
Expand Down Expand Up @@ -52,22 +50,3 @@ type LocalUIDReference struct {
// UID is the UID of the referenced entity.
UID types.UID `json:"uid"`
}

// IPPrefix represents a network prefix.
// +nullable
type IPPrefix struct {
netip.Prefix `json:"-"`
}

func (in *IPPrefix) DeepCopyInto(out *IPPrefix) {
*out = *in
}

// IPAdd is an IP address.
type IPAdd struct {
netip.Addr `json:"-"`
}

func (in *IPAdd) DeepCopyInto(out *IPAdd) {
*out = *in
}
15 changes: 7 additions & 8 deletions api/core/v1alpha1/networkpolicy_types.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors
// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors
// SPDX-License-Identifier: Apache-2.0

package v1alpha1
Expand All @@ -9,7 +9,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// NetworkPolicySpec defines the desired state of NetworkPolicy.
type NetworkPolicySpec struct {
// NetworkRef is the network to regulate using this policy.
NetworkRef corev1.LocalObjectReference `json:"networkRef"`
Expand Down Expand Up @@ -66,14 +65,14 @@ type NetworkPolicyPeer struct {

// NetworkPolicyIngressRule describes a rule to regulate ingress traffic with.
type NetworkPolicyIngressRule struct {
// Ports specifies the list of ports which should be made accessible for
// this rule. Each item in this list is combined using a logical OR. Empty matches all ports.
// As soon as a single item is present, only these ports are allowed.
Ports []NetworkPolicyPort `json:"ports,omitempty"`
// From specifies the list of sources which should be able to send traffic to the
// selected network interfaces. Fields are combined using a logical OR. Empty matches all sources.
// As soon as a single item is present, only these peers are allowed.
From []NetworkPolicyPeer `json:"from,omitempty"`
// Ports specifies the list of ports which should be made accessible for
// this rule. Each item in this list is combined using a logical OR. Empty matches all ports.
// As soon as a single item is present, only these ports are allowed.
Ports []NetworkPolicyPort `json:"ports,omitempty"`
}

// NetworkPolicyEgressRule describes a rule to regulate egress traffic with.
Expand All @@ -98,10 +97,10 @@ const (
PolicyTypeEgress PolicyType = "Egress"
)

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +genclient

// NetworkPolicy is the Schema for the networkpolicies API
// NetworkPolicy is the Schema for the networkpolicies API.
type NetworkPolicy struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
11 changes: 6 additions & 5 deletions api/core/v1alpha1/networkpolicyrule_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package v1alpha1

import (
"github.com/ironcore-dev/ironcore-net/apimachinery/api/net"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
Expand All @@ -19,10 +20,10 @@ type NetworkPolicyRule struct {

// NetworkRef is the network the load balancer is assigned to.
NetworkRef LocalUIDReference `json:"networkRef"`

// Targets are the targets of the network policy.
Targets []TargetNetworkInterface `json:"targets"`

Targets []TargetNetworkInterface `json:"targets,omitempty"`
// Priority is an optional field that specifies the order in which the policy is applied.
Priority *int32 `json:"priority,omitempty"`
// IngressRules are the ingress rules.
IngressRules []Rule `json:"ingressRule,omitempty"`
// EgressRules are the egress rules.
Expand All @@ -32,7 +33,7 @@ type NetworkPolicyRule struct {
// TargetNetworkInterface is the target of the network policy.
type TargetNetworkInterface struct {
// IP is the IP address of the target network interface.
IP IPAdd `json:"ip"`
IP net.IP `json:"ip"`
// TargetRef is the target providing the destination.
TargetRef *NetworkPolicyTargetRef `json:"targetRef,omitempty"`
}
Expand All @@ -58,7 +59,7 @@ type ObjectIP struct {
// If unset but Prefix is set, this can be inferred.
IPFamily corev1.IPFamily `json:"ipFamily,omitempty"`
// Prefix is the prefix of the IP.
Prefix *IPPrefix `json:"prefix,omitempty"`
Prefix net.IPPrefix `json:"prefix,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
Expand Down
42 changes: 12 additions & 30 deletions api/core/v1alpha1/zz_generated.deepcopy.go

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

32 changes: 32 additions & 0 deletions apinetlet/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,38 @@

package client

import (
"context"

apinetv1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

const (
NetworkInterfaceProviderIDField = ".status.providerID"
NetworkPolicyNetworkNameField = "networkpolicy-network-name"
)

func SetupNetworkPolicyNetworkNameFieldIndexer(ctx context.Context, indexer client.FieldIndexer) error {
return indexer.IndexField(ctx, &apinetv1alpha1.NetworkPolicy{}, NetworkPolicyNetworkNameField, func(obj client.Object) []string {
networkPolicy := obj.(*apinetv1alpha1.NetworkPolicy)
return []string{networkPolicy.Spec.NetworkRef.Name}
})
}

type Object[O any] interface {
client.Object
*O
}

func ReconcileRequestsFromObjectStructSlice[O Object[OStruct], S ~[]OStruct, OStruct any](objs S) []reconcile.Request {
res := make([]reconcile.Request, len(objs))
for i := range objs {
obj := O(&objs[i])
res[i] = reconcile.Request{
NamespacedName: client.ObjectKeyFromObject(obj),
}
}
return res
}
14 changes: 14 additions & 0 deletions apinetlet/controllers/controllers_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import (

"github.com/ironcore-dev/controller-utils/buildutils"
"github.com/ironcore-dev/controller-utils/modutils"
apinetletclient "github.com/ironcore-dev/ironcore-net/apinetlet/client"
apinetclient "github.com/ironcore-dev/ironcore-net/internal/client"

apinetv1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1"
"github.com/ironcore-dev/ironcore-net/client-go/ironcorenet"
ipamv1alpha1 "github.com/ironcore-dev/ironcore/api/ipam/v1alpha1"
Expand Down Expand Up @@ -138,6 +141,9 @@ func SetupTest(apiNetNamespace *corev1.Namespace) *corev1.Namespace {
})
Expect(err).ToNot(HaveOccurred())

Expect(apinetletclient.SetupNetworkPolicyNetworkNameFieldIndexer(ctx, k8sManager.GetFieldIndexer())).To(Succeed())
Expect(apinetclient.SetupNetworkInterfaceNetworkNameFieldIndexer(ctx, k8sManager.GetFieldIndexer())).To(Succeed())

apiNetInterface := ironcorenet.NewForConfigOrDie(cfg)

// register reconciler here
Expand Down Expand Up @@ -174,12 +180,20 @@ func SetupTest(apiNetNamespace *corev1.Namespace) *corev1.Namespace {
APINetNamespace: apiNetNamespace.Name,
}).SetupWithManager(k8sManager, k8sManager.GetCache())).To(Succeed())

Expect((&NetworkPolicyReconciler{
Client: k8sManager.GetClient(),
APINetClient: k8sManager.GetClient(),
APINetInterface: apiNetInterface,
APINetNamespace: apiNetNamespace.Name,
}).SetupWithManager(k8sManager, k8sManager.GetCache())).To(Succeed())

mgrCtx, cancel := context.WithCancel(context.Background())
DeferCleanup(cancel)
go func() {
defer GinkgoRecover()
Expect(k8sManager.Start(mgrCtx)).To(Succeed(), "failed to start manager")
}()

})

return apiNetNamespace
Expand Down
86 changes: 86 additions & 0 deletions apinetlet/controllers/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ import (
apinetv1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1"
"github.com/ironcore-dev/ironcore-net/apimachinery/api/net"
apinetv1alpha1ac "github.com/ironcore-dev/ironcore-net/client-go/applyconfigurations/core/v1alpha1"
apinetmetav1ac "github.com/ironcore-dev/ironcore-net/client-go/applyconfigurations/meta/v1"

commonv1alpha1 "github.com/ironcore-dev/ironcore/api/common/v1alpha1"
corev1alpha1 "github.com/ironcore-dev/ironcore/api/core/v1alpha1"
networkingv1alpha1 "github.com/ironcore-dev/ironcore/api/networking/v1alpha1"
utilslices "github.com/ironcore-dev/ironcore/utils/slices"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func ipToAPINetIP(ip commonv1alpha1.IP) net.IP {
Expand Down Expand Up @@ -69,3 +73,85 @@ func apiNetNetworkInterfaceStateToNetworkInterfaceState(state apinetv1alpha1.Net
return networkingv1alpha1.NetworkInterfaceStatePending
}
}

func networkPolicyTypesToAPINetNetworkPolicyTypes(policyTypes []networkingv1alpha1.PolicyType) ([]apinetv1alpha1.PolicyType, error) {
var apiNetPolicyTypes []apinetv1alpha1.PolicyType
for _, policyType := range policyTypes {
switch policyType {
case networkingv1alpha1.PolicyTypeIngress:
apiNetPolicyTypes = append(apiNetPolicyTypes, apinetv1alpha1.PolicyTypeIngress)
case networkingv1alpha1.PolicyTypeEgress:
apiNetPolicyTypes = append(apiNetPolicyTypes, apinetv1alpha1.PolicyTypeEgress)
default:
return nil, fmt.Errorf("invalid policy type: %s", policyType)
}
}
return apiNetPolicyTypes, nil
}

func translatePeers(peers []networkingv1alpha1.NetworkPolicyPeer) []apinetv1alpha1ac.NetworkPolicyPeerApplyConfiguration {
var apiNetPeers []apinetv1alpha1ac.NetworkPolicyPeerApplyConfiguration
for _, peer := range peers {
apiNetPeer := apinetv1alpha1ac.NetworkPolicyPeer().
WithObjectSelector(translateObjectSelector(peer.ObjectSelector)).
WithIPBlock(translateIPBlock(peer.IPBlock))
apiNetPeers = append(apiNetPeers, *apiNetPeer)
}
return apiNetPeers
}

func translateIPBlock(ipBlock *networkingv1alpha1.IPBlock) *apinetv1alpha1ac.IPBlockApplyConfiguration {
if ipBlock == nil {
return nil
}

var except []net.IPPrefix
for _, prefix := range ipBlock.Except {
except = append(except, net.IPPrefix(prefix))
}

return apinetv1alpha1ac.IPBlock().
WithCIDR(net.IPPrefix(ipBlock.CIDR)).
WithExcept(except...)
}

func translateObjectSelector(objSel *corev1alpha1.ObjectSelector) *apinetv1alpha1ac.ObjectSelectorApplyConfiguration {
if objSel == nil {
return nil
}

return apinetv1alpha1ac.ObjectSelector().
WithKind(objSel.Kind).
WithMatchLabels(objSel.MatchLabels).
WithMatchExpressions(translateLabelSelectorRequirements(objSel.MatchExpressions)...)
}

func translateLabelSelectorRequirements(reqs []metav1.LabelSelectorRequirement) []*apinetmetav1ac.LabelSelectorRequirementApplyConfiguration {
var translated []*apinetmetav1ac.LabelSelectorRequirementApplyConfiguration
for _, req := range reqs {
translated = append(translated, apinetmetav1ac.LabelSelectorRequirement().
WithKey(req.Key).
WithOperator(req.Operator).
WithValues(req.Values...))
}
return translated
}

func translateLabelSelector(labelSelector metav1.LabelSelector) *apinetmetav1ac.LabelSelectorApplyConfiguration {
return apinetmetav1ac.LabelSelector().
WithMatchLabels(labelSelector.MatchLabels).
WithMatchExpressions(translateLabelSelectorRequirements(labelSelector.MatchExpressions)...)
}

func translatePorts(ports []networkingv1alpha1.NetworkPolicyPort) []apinetv1alpha1ac.NetworkPolicyPortApplyConfiguration {
var apiNetPorts []apinetv1alpha1ac.NetworkPolicyPortApplyConfiguration
for _, port := range ports {
apiNetPort := apinetv1alpha1ac.NetworkPolicyPortApplyConfiguration{
Protocol: port.Protocol,
Port: &port.Port,
EndPort: port.EndPort,
}
apiNetPorts = append(apiNetPorts, apiNetPort)
}
return apiNetPorts
}
Loading

0 comments on commit 363d219

Please sign in to comment.