From aa038aae9c48e74c12e5b50266570e024d30bb77 Mon Sep 17 00:00:00 2001 From: Anurag Rajawat Date: Wed, 14 Feb 2024 14:54:40 +0530 Subject: [PATCH] fix(adapters): Make adapters to update their policies info in NP status Signed-off-by: Anurag Rajawat --- go.mod | 6 +- go.sum | 4 -- pkg/adapter/nimbus-kubearmor/go.sum | 2 - .../nimbus-kubearmor/manager/manager.go | 17 +++++- pkg/adapter/nimbus-netpol/go.mod | 1 - pkg/adapter/nimbus-netpol/go.sum | 3 +- .../nimbus-netpol/manager/netpols_manager.go | 41 +++++++++++++- pkg/adapter/util/nimbuspolicy_util.go | 55 ++++++++++++++++++- 8 files changed, 111 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 32a5513a..fe8ecdd3 100644 --- a/go.mod +++ b/go.mod @@ -11,11 +11,9 @@ require ( ) require ( - github.com/5GSEC/nimbus/pkg/adapter/nimbus-kubearmor v0.0.0-20240208144202-ef6c819f09b3 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/evanphx/json-patch v5.7.0+incompatible // indirect github.com/go-logr/logr v1.4.1 // indirect - github.com/kubearmor/KubeArmor/pkg/KubeArmorController v0.0.0-20240125171707-8e6641511fe3 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect @@ -49,7 +47,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.18.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.46.0 // indirect @@ -71,7 +69,7 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.29.1 // indirect + k8s.io/api v0.29.1 k8s.io/apiextensions-apiserver v0.29.1 // indirect k8s.io/component-base v0.29.1 // indirect k8s.io/klog/v2 v2.120.1 // indirect diff --git a/go.sum b/go.sum index 964f02e3..2bc9d759 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -github.com/5GSEC/nimbus/pkg/adapter/nimbus-kubearmor v0.0.0-20240208144202-ef6c819f09b3 h1:dcJ9kZy7Kn/uh36QxLdTLn0L0UtG744uFAJHwCDUDdU= -github.com/5GSEC/nimbus/pkg/adapter/nimbus-kubearmor v0.0.0-20240208144202-ef6c819f09b3/go.mod h1:TTZsB7iLwzcTzW9CjkqIUpvx8ShiQM7bSNDH7mYnV8w= github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -68,8 +66,6 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kubearmor/KubeArmor/pkg/KubeArmorController v0.0.0-20240125171707-8e6641511fe3 h1:xDg2EAk7rV3psrUkwC7JqY6pzOutWwh4VuUEybypcrA= -github.com/kubearmor/KubeArmor/pkg/KubeArmorController v0.0.0-20240125171707-8e6641511fe3/go.mod h1:Z7ZPkMwtVcjSaDigSekvooXRxapWsLAVVmX3ltL673k= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= diff --git a/pkg/adapter/nimbus-kubearmor/go.sum b/pkg/adapter/nimbus-kubearmor/go.sum index 8e5bfd38..27d5382d 100644 --- a/pkg/adapter/nimbus-kubearmor/go.sum +++ b/pkg/adapter/nimbus-kubearmor/go.sum @@ -1,5 +1,3 @@ -github.com/5GSEC/nimbus v0.0.0-20240129090659-01178b5c28c7 h1:adBGcrCAKeU7PLiz6m2c+3c8uuL5UPkHN5O6FHJQm7I= -github.com/5GSEC/nimbus v0.0.0-20240129090659-01178b5c28c7/go.mod h1:VXo/w78XDmQEunuZYIsDyGDthCKealQR13X9OkY25D0= github.com/5GSEC/nimbus v0.0.0-20240208070656-624660f34768 h1:v2fY3lWXydstfekQSHs9n0TpNnTteC7Iws3ojwGtFJk= github.com/5GSEC/nimbus v0.0.0-20240208070656-624660f34768/go.mod h1:yw79m9f1+f3tBSZCMQKbNVKL39Q71FyGyoa8nClo1Hs= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= diff --git a/pkg/adapter/nimbus-kubearmor/manager/manager.go b/pkg/adapter/nimbus-kubearmor/manager/manager.go index d6ce175a..f26f5b8b 100644 --- a/pkg/adapter/nimbus-kubearmor/manager/manager.go +++ b/pkg/adapter/nimbus-kubearmor/manager/manager.go @@ -29,7 +29,6 @@ import ( var ( scheme = runtime.NewScheme() - np intentv1.NimbusPolicy k8sClient client.Client ) @@ -81,6 +80,7 @@ func Run(ctx context.Context) { func reconcileKsp(ctx context.Context, kspName, namespace string, deleted bool) { logger := log.FromContext(ctx) npName := adapterutil.ExtractNpName(kspName) + var np intentv1.NimbusPolicy err := k8sClient.Get(ctx, types.NamespacedName{Name: npName, Namespace: namespace}, &np) if err != nil { if !errors.IsNotFound(err) { @@ -98,13 +98,14 @@ func reconcileKsp(ctx context.Context, kspName, namespace string, deleted bool) func createOrUpdateKsp(ctx context.Context, npName, npNamespace string) { logger := log.FromContext(ctx) + var np intentv1.NimbusPolicy if err := k8sClient.Get(ctx, types.NamespacedName{Name: npName, Namespace: npNamespace}, &np); err != nil { logger.Error(err, "failed to get NimbusPolicy", "NimbusPolicy.Name", npName, "NimbusPolicy.Namespace", npNamespace) return } if adapterutil.IsOrphan(np.GetOwnerReferences(), "SecurityIntentBinding") { - logger.V(4).Info("Ignoring orphan NimbusPolicy", "NimbusPolicy.Name", np.GetName(), "NimbusPolicy.Namespace", np.GetNamespace()) + logger.V(4).Info("Ignoring orphan NimbusPolicy", "NimbusPolicy.Name", npName, "NimbusPolicy.Namespace", npNamespace) return } @@ -140,6 +141,18 @@ func createOrUpdateKsp(ctx context.Context, npName, npNamespace string) { } logger.Info("KubeArmorPolicy configured", "KubeArmorPolicy.Name", existingKsp.Name, "KubeArmorPolicy.Namespace", existingKsp.Namespace) } + + // Due to adapters' dependency on nimbus module, the docker image build is + // failing. The relevant code is commented out below (lines 151-153). We shall + // uncomment this code in a subsequent PR. + + // Every adapter is responsible for updating the status field of the + // corresponding NimbusPolicy with the number and names of successfully created + // policies. This provides feedback to users about the translation and deployment + // of their security intent. + //if err = adapterutil.UpdateNpStatus(ctx, k8sClient, "KubeArmorPolicy/"+ksp.Name, np.Name, np.Namespace); err != nil { + // logger.Error(err, "failed to update KubeArmorPolicies status in NimbusPolicy") + //} } } diff --git a/pkg/adapter/nimbus-netpol/go.mod b/pkg/adapter/nimbus-netpol/go.mod index 1b82b8ba..59f5c915 100644 --- a/pkg/adapter/nimbus-netpol/go.mod +++ b/pkg/adapter/nimbus-netpol/go.mod @@ -16,7 +16,6 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/emicklei/go-restful/v3 v3.11.2 // indirect - github.com/evanphx/json-patch v5.7.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/zapr v1.3.0 // indirect diff --git a/pkg/adapter/nimbus-netpol/go.sum b/pkg/adapter/nimbus-netpol/go.sum index 40de45ce..43718566 100644 --- a/pkg/adapter/nimbus-netpol/go.sum +++ b/pkg/adapter/nimbus-netpol/go.sum @@ -1,5 +1,3 @@ -github.com/5GSEC/nimbus v0.0.0-20240129090659-01178b5c28c7 h1:adBGcrCAKeU7PLiz6m2c+3c8uuL5UPkHN5O6FHJQm7I= -github.com/5GSEC/nimbus v0.0.0-20240129090659-01178b5c28c7/go.mod h1:VXo/w78XDmQEunuZYIsDyGDthCKealQR13X9OkY25D0= github.com/5GSEC/nimbus v0.0.0-20240208070656-624660f34768 h1:v2fY3lWXydstfekQSHs9n0TpNnTteC7Iws3ojwGtFJk= github.com/5GSEC/nimbus v0.0.0-20240208070656-624660f34768/go.mod h1:yw79m9f1+f3tBSZCMQKbNVKL39Q71FyGyoa8nClo1Hs= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -154,6 +152,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/adapter/nimbus-netpol/manager/netpols_manager.go b/pkg/adapter/nimbus-netpol/manager/netpols_manager.go index 86a75a35..91ac4a7d 100644 --- a/pkg/adapter/nimbus-netpol/manager/netpols_manager.go +++ b/pkg/adapter/nimbus-netpol/manager/netpols_manager.go @@ -7,6 +7,7 @@ import ( "context" "fmt" + "github.com/go-logr/logr" netv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" @@ -28,7 +29,6 @@ import ( var ( scheme = runtime.NewScheme() - np intentv1.NimbusPolicy k8sClient client.Client ) @@ -80,6 +80,7 @@ func Run(ctx context.Context) { func reconcileNetPol(ctx context.Context, netpolName, namespace string, deleted bool) { logger := log.FromContext(ctx) npName := adapterutil.ExtractNpName(netpolName) + var np intentv1.NimbusPolicy err := k8sClient.Get(ctx, types.NamespacedName{Name: npName, Namespace: namespace}, &np) if err != nil { if !errors.IsNotFound(err) { @@ -97,6 +98,7 @@ func reconcileNetPol(ctx context.Context, netpolName, namespace string, deleted func createOrUpdateNetworkPolicy(ctx context.Context, npName, npNamespace string) { logger := log.FromContext(ctx) + var np intentv1.NimbusPolicy if err := k8sClient.Get(ctx, types.NamespacedName{Name: npName, Namespace: npNamespace}, &np); err != nil { logger.Error(err, "failed to get NimbusPolicy", "NimbusPolicy.Name", npName[0], "NimbusPolicy.Namespace", npName[1]) return @@ -108,6 +110,7 @@ func createOrUpdateNetworkPolicy(ctx context.Context, npName, npNamespace string } netPols := processor.BuildNetPolsFrom(logger, np) + deleteUnnecessaryNetpols(ctx, netPols, npNamespace, logger) // Iterate using a separate index variable to avoid aliasing for idx := range netPols { netpol := netPols[idx] @@ -138,6 +141,18 @@ func createOrUpdateNetworkPolicy(ctx context.Context, npName, npNamespace string } logger.Info("NetworkPolicy configured", "NetworkPolicy.Name", netpol.Name, "NetworkPolicy.Namespace", netpol.Namespace) } + + // Due to adapters' dependency on nimbus module, the docker image build is + // failing. The relevant code is commented out below (lines 151-153). We shall + // uncomment this code in a subsequent PR. + + // Every adapter is responsible for updating the status field of the + // corresponding NimbusPolicy with the number and names of successfully created + // policies. This provides feedback to users about the translation and deployment + // of their security intent. + //if err = adapterutil.UpdateNpStatus(ctx, k8sClient, "NetworkPolicy/"+netpol.Name, np.Name, np.Namespace); err != nil { + // logger.Error(err, "failed to update NetworkPolicies status in NimbusPolicy") + //} } } @@ -161,3 +176,27 @@ func deleteNetworkPolicy(ctx context.Context, npName, npNamespace string) { ) } } + +func deleteUnnecessaryNetpols(ctx context.Context, netPols []netv1.NetworkPolicy, namespace string, logger logr.Logger) { + var existingNetpols netv1.NetworkPolicyList + if err := k8sClient.List(ctx, &existingNetpols, client.InNamespace(namespace)); err != nil { + logger.Error(err, "failed to list NetworkPolicies for cleanup") + return + } + + netpolsToDeleteName := make(map[string]bool) + for _, netpol := range netPols { + netpolsToDeleteName[netpol.Name] = true + } + + for idx := range existingNetpols.Items { + existingNetpol := existingNetpols.Items[idx] + if _, needed := netpolsToDeleteName[existingNetpol.Name]; !needed { + if err := k8sClient.Delete(ctx, &existingNetpol); err != nil { + logger.Error(err, "failed to delete unnecessary NetworkPolicy", "NetworkPolicy.Name", existingNetpol.Name, "NetworkPolicy.Namespace", existingNetpol.Namespace) + } else { + logger.Info("Deleted unnecessary NetworkPolicy", "NetworkPolicy.Name", existingNetpol.Name, "NetworkPolicy.Namespace", existingNetpol.Namespace) + } + } + } +} diff --git a/pkg/adapter/util/nimbuspolicy_util.go b/pkg/adapter/util/nimbuspolicy_util.go index 3889c0b1..2579971a 100644 --- a/pkg/adapter/util/nimbuspolicy_util.go +++ b/pkg/adapter/util/nimbuspolicy_util.go @@ -4,10 +4,61 @@ package util import ( + "context" "strings" + + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" + + intentv1 "github.com/5GSEC/nimbus/api/v1" ) -func ExtractNpName(kspName string) string { - words := strings.Split(kspName, "-") +// ExtractNpName extracts the actual NimbusPolicy name from a formatted policy +// name. +func ExtractNpName(policyName string) string { + words := strings.Split(policyName, "-") return strings.Join(words[:len(words)-1], "-") } + +// UpdateNpStatus updates the provided NimbusPolicy status with the number and +// names of its descendant policies that were created. +func UpdateNpStatus(ctx context.Context, k8sClient client.Client, currPolicyFullName, npName, namespace string) error { + // Since multiple adapters may attempt to update the NimbusPolicy status + // concurrently, potentially leading to conflicts. To ensure data consistency, + // retry on write failures. On conflict, the update is retried with an + // exponential backoff strategy. This provides resilience against potential + // issues while preventing indefinite retries in case of persistent conflicts. + if retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { + latestNp := &intentv1.NimbusPolicy{} + if err := k8sClient.Get(ctx, types.NamespacedName{Name: npName, Namespace: namespace}, latestNp); err != nil { + return nil + } + + updateCountAndPoliciesName(latestNp, currPolicyFullName) + if err := k8sClient.Status().Update(ctx, latestNp); err != nil { + return err + } + + return nil + }); retryErr != nil { + return retryErr + } + return nil +} + +func updateCountAndPoliciesName(latestNp *intentv1.NimbusPolicy, currPolicyFullName string) { + if !contains(latestNp.Status.Policies, currPolicyFullName) { + latestNp.Status.NumberOfAdapterPolicies++ + latestNp.Status.Policies = append(latestNp.Status.Policies, currPolicyFullName) + } +} + +func contains(existingPolicies []string, policy string) bool { + for _, existingPolicy := range existingPolicies { + if existingPolicy == policy { + return true + } + } + return false +}