From e7e846d01d037d6739cf39b6b605e48a79098c1e Mon Sep 17 00:00:00 2001 From: Matthias Bertschy Date: Wed, 8 Nov 2023 17:30:11 +0100 Subject: [PATCH 1/4] update applicationprofile type Signed-off-by: Matthias Bertschy --- go.mod | 2 +- go.sum | 4 +- .../v1/applicationprofile_manager.go | 64 ++++++++++++++++--- .../v1/applicationprofile_manager_test.go | 8 +-- pkg/k8sclient/k8sclient_mock.go | 4 ++ pkg/storage/storage_mock.go | 5 +- pkg/utils/utils.go | 40 ++++++++++++ 7 files changed, 109 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index f84e3124..bd393af9 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/kubescape/backend v0.0.13 github.com/kubescape/go-logger v0.0.21 github.com/kubescape/k8s-interface v0.0.148 - github.com/kubescape/storage v0.0.33 + github.com/kubescape/storage v0.0.38 github.com/panjf2000/ants/v2 v2.8.1 github.com/spf13/viper v1.16.0 github.com/stretchr/testify v1.8.4 diff --git a/go.sum b/go.sum index ab54715d..0aed0320 100644 --- a/go.sum +++ b/go.sum @@ -300,8 +300,8 @@ github.com/kubescape/go-logger v0.0.21 h1:4ZRIEw3UGUH6BG/cH3yiqFipzQSfGAoCrxlsZu github.com/kubescape/go-logger v0.0.21/go.mod h1:x3HBpZo3cMT/WIdy18BxvVVd5D0e/PWFVk/HiwBNu3g= github.com/kubescape/k8s-interface v0.0.148 h1:vtXDUjvCow5wMdDvb5c/Td9SpafeRqsV/LnOd0NVVsE= github.com/kubescape/k8s-interface v0.0.148/go.mod h1:5sz+5Cjvo98lTbTVDiDA4MmlXxeHSVMW/wR0V3hV4K8= -github.com/kubescape/storage v0.0.33 h1:CAD2A6cO1mekX6ecOGYrHfY5HMOZWm3uzoxSTafqxgs= -github.com/kubescape/storage v0.0.33/go.mod h1:ObCIVOnVyWwRwU0iuKTzOnrJQScqPgkw0FgvSINwosY= +github.com/kubescape/storage v0.0.38 h1:LR+QTqjeYw4kM1repIltDLDQGqHgKmG196lQyHP+xUw= +github.com/kubescape/storage v0.0.38/go.mod h1:ObCIVOnVyWwRwU0iuKTzOnrJQScqPgkw0FgvSINwosY= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= diff --git a/pkg/applicationprofilemanager/v1/applicationprofile_manager.go b/pkg/applicationprofilemanager/v1/applicationprofile_manager.go index 3a3dac33..8a6d1789 100644 --- a/pkg/applicationprofilemanager/v1/applicationprofile_manager.go +++ b/pkg/applicationprofilemanager/v1/applicationprofile_manager.go @@ -8,6 +8,7 @@ import ( "node-agent/pkg/k8sclient" "node-agent/pkg/storage" "node-agent/pkg/utils" + "sort" "time" mapset "github.com/deckarep/golang-set/v2" @@ -69,6 +70,38 @@ func (am *ApplicationProfileManager) ensureInstanceID(ctx context.Context, conta watchedContainer.InstanceID = instanceIDs[i] } } + // find container type and index + // containers + if watchedContainer.ContainerType == utils.Unknown { + containers, err := pod.GetContainers() + if err != nil { + logger.L().Ctx(ctx).Error("ApplicationProfileManager - failed to get containers", helpers.Error(err)) + return + } + for i, c := range containers { + if c.Name == container.K8s.ContainerName { + watchedContainer.ContainerIndex = i + watchedContainer.ContainerType = utils.Container + break + } + } + } + // initContainers + if watchedContainer.ContainerType == utils.Unknown { + initContainers, err := pod.GetInitContainers() + if err != nil { + logger.L().Ctx(ctx).Error("ApplicationProfileManager - failed to get init containers", helpers.Error(err)) + return + } + for i, c := range initContainers { + if c.Name == container.K8s.ContainerName { + watchedContainer.ContainerIndex = i + watchedContainer.ContainerType = utils.InitContainer + break + } + } + } + // FIXME ephemeralContainers are not supported yet } func (am *ApplicationProfileManager) deleteResources(watchedContainer *utils.WatchedContainerData) { @@ -154,15 +187,16 @@ func (am *ApplicationProfileManager) saveProfile(ctx context.Context, watchedCon opens := am.openSets.Get(watchedContainer.K8sContainerID) // existing profile existingProfile, _ := am.storageClient.GetApplicationProfile(slug, namespace) + existingProfileContainer := utils.GetApplicationProfileContainer(existingProfile, watchedContainer.ContainerType, watchedContainer.ContainerIndex) if existingProfile != nil { - capabilities.Append(existingProfile.Spec.Capabilities...) - for _, exec := range existingProfile.Spec.Execs { + capabilities.Append(existingProfileContainer.Capabilities...) + for _, exec := range existingProfileContainer.Execs { if _, exist := execs[exec.Path]; !exist { execs[exec.Path] = mapset.NewSet[string]() } execs[exec.Path].Append(exec.Args...) } - for _, open := range existingProfile.Spec.Opens { + for _, open := range existingProfileContainer.Opens { if _, exist := opens[open.Path]; !exist { opens[open.Path] = mapset.NewSet[string]() } @@ -183,27 +217,37 @@ func (am *ApplicationProfileManager) saveProfile(ctx context.Context, watchedCon Labels: utils.GetLabels(watchedContainer), }, } + newProfileContainer := v1beta1.ApplicationProfileContainer{} // add capabilities - newProfile.Spec.Capabilities = capabilities.ToSlice() + newProfileContainer.Capabilities = capabilities.ToSlice() + sort.Strings(newProfileContainer.Capabilities) // add execs - newProfile.Spec.Execs = make([]v1beta1.ExecCalls, 0) + newProfileContainer.Execs = make([]v1beta1.ExecCalls, 0) for path, exec := range execs { - newProfile.Spec.Execs = append(newProfile.Spec.Execs, v1beta1.ExecCalls{ + args := exec.ToSlice() + sort.Strings(args) + newProfileContainer.Execs = append(newProfileContainer.Execs, v1beta1.ExecCalls{ Path: path, - Args: exec.ToSlice(), + Args: args, }) } // add opens - newProfile.Spec.Opens = make([]v1beta1.OpenCalls, 0) + newProfileContainer.Opens = make([]v1beta1.OpenCalls, 0) for path, open := range opens { - newProfile.Spec.Opens = append(newProfile.Spec.Opens, v1beta1.OpenCalls{ + flags := open.ToSlice() + sort.Strings(flags) + newProfileContainer.Opens = append(newProfileContainer.Opens, v1beta1.OpenCalls{ Path: path, - Flags: open.ToSlice(), + Flags: flags, }) } + // insert application profile container + utils.InsertApplicationProfileContainer(newProfile, watchedContainer.ContainerType, watchedContainer.ContainerIndex, newProfileContainer) + // save application profile if err := am.storageClient.CreateApplicationProfile(newProfile, namespace); err != nil { logger.L().Ctx(ctx).Error("ApplicationProfileManager - failed to save application profile", helpers.Error(err)) } + logger.L().Debug("ApplicationProfileManager - saved application profile", helpers.String("slug", slug), helpers.String("container ID", watchedContainer.ContainerID), helpers.String("k8s workload", watchedContainer.K8sContainerID), helpers.Interface("profile", newProfile)) // profile summary summary := &v1beta1.ApplicationProfileSummary{ ObjectMeta: newProfile.ObjectMeta, diff --git a/pkg/applicationprofilemanager/v1/applicationprofile_manager_test.go b/pkg/applicationprofilemanager/v1/applicationprofile_manager_test.go index 2c926e84..11421c1b 100644 --- a/pkg/applicationprofilemanager/v1/applicationprofile_manager_test.go +++ b/pkg/applicationprofilemanager/v1/applicationprofile_manager_test.go @@ -69,9 +69,9 @@ func TestApplicationProfileManager(t *testing.T) { sort.Strings(storageClient.ApplicationActivities[0].Spec.Syscalls) assert.Equal(t, []string{"dup", "listen", "open"}, storageClient.ApplicationActivities[0].Spec.Syscalls) assert.Equal(t, 2, len(storageClient.ApplicationProfiles)) - sort.Strings(storageClient.ApplicationProfiles[0].Spec.Capabilities) - assert.Equal(t, []string{"NET_BIND_SERVICE", "NET_BROADCAST"}, storageClient.ApplicationProfiles[0].Spec.Capabilities) - assert.Equal(t, []v1beta1.ExecCalls{{Path: "/bin/bash", Args: []string{"-c", "ls"}, Envs: []string(nil)}}, storageClient.ApplicationProfiles[0].Spec.Execs) - assert.Equal(t, []v1beta1.OpenCalls{{Path: "/etc/passwd", Flags: []string{"O_RDONLY"}}}, storageClient.ApplicationProfiles[0].Spec.Opens) + sort.Strings(storageClient.ApplicationProfiles[0].Spec.Containers[0].Capabilities) + assert.Equal(t, []string{"NET_BIND_SERVICE", "NET_BROADCAST"}, storageClient.ApplicationProfiles[0].Spec.Containers[1].Capabilities) + assert.Equal(t, []v1beta1.ExecCalls{{Path: "/bin/bash", Args: []string{"-c", "ls"}, Envs: []string(nil)}}, storageClient.ApplicationProfiles[0].Spec.Containers[1].Execs) + assert.Equal(t, []v1beta1.OpenCalls{{Path: "/etc/passwd", Flags: []string{"O_RDONLY"}}}, storageClient.ApplicationProfiles[0].Spec.Containers[1].Opens) assert.Equal(t, 2, len(storageClient.ApplicationProfileSummaries)) } diff --git a/pkg/k8sclient/k8sclient_mock.go b/pkg/k8sclient/k8sclient_mock.go index 4c61877c..931e58f9 100644 --- a/pkg/k8sclient/k8sclient_mock.go +++ b/pkg/k8sclient/k8sclient_mock.go @@ -21,6 +21,10 @@ func (k K8sClientMock) GetWorkload(namespace, _, name string) (k8sinterface.IWor }, "spec": map[string]interface{}{ "containers": []interface{}{ + map[string]interface{}{ + "name": "log", + "image": "fluentbit", + }, map[string]interface{}{ "name": "cont", "image": "nginx", diff --git a/pkg/storage/storage_mock.go b/pkg/storage/storage_mock.go index 2e0c4ecc..bb8cb7c7 100644 --- a/pkg/storage/storage_mock.go +++ b/pkg/storage/storage_mock.go @@ -37,7 +37,10 @@ func (sc *StorageHttpClientMock) GetApplicationActivity(_, _ string) (*spdxv1bet func (sc *StorageHttpClientMock) GetApplicationProfile(_, _ string) (*spdxv1beta1.ApplicationProfile, error) { return &spdxv1beta1.ApplicationProfile{ Spec: spdxv1beta1.ApplicationProfileSpec{ - Capabilities: []string{"NET_BROADCAST"}, + Containers: []spdxv1beta1.ApplicationProfileContainer{ + {Capabilities: []string{"SYS_ADMIN"}}, + {Capabilities: []string{"NET_BROADCAST"}}, + }, }, }, nil } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 55260f52..3c89fe9a 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -28,8 +28,19 @@ type PackageSourceInfoData struct { PackageSPDXIdentifier []v1beta1.ElementID } +type ContainerType int + +const ( + Unknown = iota + Container + InitContainer + EphemeralContainer +) + type WatchedContainerData struct { ContainerID string + ContainerIndex int + ContainerType ContainerType FilteredSpdxData *v1beta1.SBOMSPDXv2p3Filtered ImageID string ImageTag string @@ -124,3 +135,32 @@ func GetLabels(watchedContainer *WatchedContainerData) map[string]string { } return labels } + +func GetApplicationProfileContainer(profile *v1beta1.ApplicationProfile, containerType ContainerType, containerIndex int) v1beta1.ApplicationProfileContainer { + switch containerType { + case Container: + if len(profile.Spec.Containers) > containerIndex { + return profile.Spec.Containers[containerIndex] + } + case InitContainer: + if len(profile.Spec.InitContainers) > containerIndex { + return profile.Spec.InitContainers[containerIndex] + } + } + return v1beta1.ApplicationProfileContainer{} +} + +func InsertApplicationProfileContainer(profile *v1beta1.ApplicationProfile, containerType ContainerType, containerIndex int, profileContainer v1beta1.ApplicationProfileContainer) { + switch containerType { + case Container: + if len(profile.Spec.Containers) <= containerIndex { + profile.Spec.Containers = append(profile.Spec.Containers, make([]v1beta1.ApplicationProfileContainer, containerIndex-len(profile.Spec.Containers)+1)...) + } + profile.Spec.Containers[containerIndex] = profileContainer + case InitContainer: + if len(profile.Spec.InitContainers) <= containerIndex { + profile.Spec.InitContainers = append(profile.Spec.InitContainers, make([]v1beta1.ApplicationProfileContainer, containerIndex-len(profile.Spec.InitContainers)+1)...) + } + profile.Spec.InitContainers[containerIndex] = profileContainer + } +} From 5df5b57ad7cc33b2af065c069add60efaaea3504 Mon Sep 17 00:00:00 2001 From: Matthias Bertschy Date: Tue, 14 Nov 2023 08:21:46 +0100 Subject: [PATCH 2/4] add WLID to application profile objects Signed-off-by: Matthias Bertschy --- main.go | 2 +- .../v1/applicationprofile_manager.go | 23 ++++++++++++++++++- .../v1/applicationprofile_manager_test.go | 2 +- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index 22e549c4..84773a46 100644 --- a/main.go +++ b/main.go @@ -81,7 +81,7 @@ func main() { // Create the application profile manager var applicationProfileManager applicationprofilemanager.ApplicationProfileManagerClient if cfg.EnableApplicationProfile { - applicationProfileManager, err = applicationprofilemanagerv1.CreateApplicationProfileManager(ctx, cfg, k8sClient, storageClient) + applicationProfileManager, err = applicationprofilemanagerv1.CreateApplicationProfileManager(ctx, cfg, clusterData.ClusterName, k8sClient, storageClient) if err != nil { logger.L().Ctx(ctx).Fatal("error creating the application profile manager", helpers.Error(err)) } diff --git a/pkg/applicationprofilemanager/v1/applicationprofile_manager.go b/pkg/applicationprofilemanager/v1/applicationprofile_manager.go index 8a6d1789..3746a3e3 100644 --- a/pkg/applicationprofilemanager/v1/applicationprofile_manager.go +++ b/pkg/applicationprofilemanager/v1/applicationprofile_manager.go @@ -11,6 +11,7 @@ import ( "sort" "time" + "github.com/armosec/utils-k8s-go/wlid" mapset "github.com/deckarep/golang-set/v2" "github.com/goradd/maps" containercollection "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection" @@ -27,6 +28,7 @@ import ( type ApplicationProfileManager struct { cfg config.Config + clusterName string ctx context.Context capabilitiesSets maps.SafeMap[string, mapset.Set[string]] // key is k8sContainerID execSets maps.SafeMap[string, map[string]mapset.Set[string]] // key is k8sContainerID @@ -39,9 +41,10 @@ type ApplicationProfileManager struct { var _ applicationprofilemanager.ApplicationProfileManagerClient = (*ApplicationProfileManager)(nil) -func CreateApplicationProfileManager(ctx context.Context, cfg config.Config, k8sClient k8sclient.K8sClientInterface, storageClient storage.StorageClient) (*ApplicationProfileManager, error) { +func CreateApplicationProfileManager(ctx context.Context, cfg config.Config, clusterName string, k8sClient k8sclient.K8sClientInterface, storageClient storage.StorageClient) (*ApplicationProfileManager, error) { return &ApplicationProfileManager{ cfg: cfg, + clusterName: clusterName, ctx: ctx, k8sClient: k8sClient, storageClient: storageClient, @@ -58,6 +61,24 @@ func (am *ApplicationProfileManager) ensureInstanceID(ctx context.Context, conta return } pod := wl.(*workloadinterface.Workload) + // find parentWlid + kind, name, err := am.k8sClient.CalculateWorkloadParentRecursive(pod) + if err != nil { + logger.L().Ctx(ctx).Error("ApplicationProfileManager - failed to calculate workload parent", helpers.Error(err)) + return + } + parentWorkload, err := am.k8sClient.GetWorkload(pod.GetNamespace(), kind, name) + if err != nil { + logger.L().Ctx(ctx).Error("ApplicationProfileManager - failed to get parent workload", helpers.Error(err)) + return + } + w := parentWorkload.(*workloadinterface.Workload) + watchedContainer.Wlid = w.GenerateWlid(am.clusterName) + err = wlid.IsWlidValid(watchedContainer.Wlid) + if err != nil { + logger.L().Ctx(ctx).Error("ApplicationProfileManager - failed to validate WLID", helpers.Error(err)) + return + } // find instanceID instanceIDs, err := instanceidhandler.GenerateInstanceID(pod) if err != nil { diff --git a/pkg/applicationprofilemanager/v1/applicationprofile_manager_test.go b/pkg/applicationprofilemanager/v1/applicationprofile_manager_test.go index 11421c1b..c3121143 100644 --- a/pkg/applicationprofilemanager/v1/applicationprofile_manager_test.go +++ b/pkg/applicationprofilemanager/v1/applicationprofile_manager_test.go @@ -24,7 +24,7 @@ func TestApplicationProfileManager(t *testing.T) { ctx := context.TODO() k8sClient := &k8sclient.K8sClientMock{} storageClient := &storage.StorageHttpClientMock{} - am, err := CreateApplicationProfileManager(ctx, cfg, k8sClient, storageClient) + am, err := CreateApplicationProfileManager(ctx, cfg, "cluster", k8sClient, storageClient) assert.NoError(t, err) // report container started container := &containercollection.Container{ From d9c6b09e93951c1d1b69ba840ff516a805f7bef3 Mon Sep 17 00:00:00 2001 From: Matthias Bertschy Date: Tue, 14 Nov 2023 13:54:47 +0100 Subject: [PATCH 3/4] add container name, remove wrong annotations/labels Signed-off-by: Matthias Bertschy --- .../v1/applicationprofile_manager.go | 22 ++++++++----------- pkg/sbomhandler/v1/sbomhandler.go | 2 +- pkg/utils/utils.go | 4 +++- pkg/utils/utils_test.go | 19 +++++++++++++++- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/pkg/applicationprofilemanager/v1/applicationprofile_manager.go b/pkg/applicationprofilemanager/v1/applicationprofile_manager.go index 3746a3e3..c3575109 100644 --- a/pkg/applicationprofilemanager/v1/applicationprofile_manager.go +++ b/pkg/applicationprofilemanager/v1/applicationprofile_manager.go @@ -181,13 +181,10 @@ func (am *ApplicationProfileManager) saveProfile(ctx context.Context, watchedCon ObjectMeta: metav1.ObjectMeta{ Name: slug, Annotations: map[string]string{ - instanceidhandler.WlidMetadataKey: watchedContainer.Wlid, - instanceidhandler.InstanceIDMetadataKey: watchedContainer.InstanceID.GetStringFormatted(), - instanceidhandler.ContainerNameMetadataKey: watchedContainer.InstanceID.GetContainerName(), - instanceidhandler.ImageIDMetadataKey: watchedContainer.ImageID, - instanceidhandler.StatusMetadataKey: "", + instanceidhandler.WlidMetadataKey: watchedContainer.Wlid, + instanceidhandler.StatusMetadataKey: "", }, - Labels: utils.GetLabels(watchedContainer), + Labels: utils.GetLabels(watchedContainer, true), }, } // add syscalls @@ -229,16 +226,15 @@ func (am *ApplicationProfileManager) saveProfile(ctx context.Context, watchedCon ObjectMeta: metav1.ObjectMeta{ Name: slug, Annotations: map[string]string{ - instanceidhandler.WlidMetadataKey: watchedContainer.Wlid, - instanceidhandler.InstanceIDMetadataKey: watchedContainer.InstanceID.GetStringFormatted(), - instanceidhandler.ContainerNameMetadataKey: watchedContainer.InstanceID.GetContainerName(), - instanceidhandler.ImageIDMetadataKey: watchedContainer.ImageID, - instanceidhandler.StatusMetadataKey: "", + instanceidhandler.WlidMetadataKey: watchedContainer.Wlid, + instanceidhandler.StatusMetadataKey: "", }, - Labels: utils.GetLabels(watchedContainer), + Labels: utils.GetLabels(watchedContainer, true), }, } - newProfileContainer := v1beta1.ApplicationProfileContainer{} + newProfileContainer := v1beta1.ApplicationProfileContainer{ + Name: watchedContainer.InstanceID.GetContainerName(), + } // add capabilities newProfileContainer.Capabilities = capabilities.ToSlice() sort.Strings(newProfileContainer.Capabilities) diff --git a/pkg/sbomhandler/v1/sbomhandler.go b/pkg/sbomhandler/v1/sbomhandler.go index 04ed6548..9a7d1078 100644 --- a/pkg/sbomhandler/v1/sbomhandler.go +++ b/pkg/sbomhandler/v1/sbomhandler.go @@ -76,7 +76,7 @@ func (sc *SBOMHandler) FilterSBOM(watchedContainer *utils.WatchedContainerData, instanceidhandler.ImageIDMetadataKey: watchedContainer.ImageID, instanceidhandler.StatusMetadataKey: "", }, - Labels: utils.GetLabels(watchedContainer), + Labels: utils.GetLabels(watchedContainer, false), }, } } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 3c89fe9a..59b167a6 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -112,11 +112,13 @@ func Atoi(s string) int { return i } -func GetLabels(watchedContainer *WatchedContainerData) map[string]string { +func GetLabels(watchedContainer *WatchedContainerData, stripContainer bool) map[string]string { labels := watchedContainer.InstanceID.GetLabels() for i := range labels { if labels[i] == "" { delete(labels, i) + } else if stripContainer && i == instanceidhandler2.ContainerNameMetadataKey { + delete(labels, i) } else { if i == instanceidhandler2.KindMetadataKey { labels[i] = wlid.GetKindFromWlid(watchedContainer.Wlid) diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go index dbb8d47c..512e24c6 100644 --- a/pkg/utils/utils_test.go +++ b/pkg/utils/utils_test.go @@ -173,6 +173,7 @@ func TestAtoi(t *testing.T) { func Test_GetLabels(t *testing.T) { type args struct { watchedContainer *WatchedContainerData + stripContainer bool } instanceID, _ := instanceidhandler.GenerateInstanceIDFromString("apiVersion-v1/namespace-aaa/kind-deployment/name-redis/containerName-redis") tests := []struct { @@ -196,10 +197,26 @@ func Test_GetLabels(t *testing.T) { "kubescape.io/workload-namespace": "aaa", }, }, + { + name: "TestGetLabels", + args: args{ + watchedContainer: &WatchedContainerData{ + InstanceID: instanceID, + Wlid: "wlid://cluster-name/namespace-aaa/deployment-redis", + }, + stripContainer: true, + }, + want: map[string]string{ + "kubescape.io/workload-api-version": "v1", + "kubescape.io/workload-kind": "Deployment", + "kubescape.io/workload-name": "redis", + "kubescape.io/workload-namespace": "aaa", + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := GetLabels(tt.args.watchedContainer) + got := GetLabels(tt.args.watchedContainer, tt.args.stripContainer) assert.Equal(t, tt.want, got) }) } From 9a965163c297f4fb43a287a54cd2c15e3a19638e Mon Sep 17 00:00:00 2001 From: Matthias Bertschy Date: Tue, 14 Nov 2023 15:04:21 +0100 Subject: [PATCH 4/4] only save new profile/activity when sets are updated Signed-off-by: Matthias Bertschy --- .../v1/applicationprofile_manager.go | 172 ++++++++++-------- pkg/utils/utils.go | 17 +- 2 files changed, 107 insertions(+), 82 deletions(-) diff --git a/pkg/applicationprofilemanager/v1/applicationprofile_manager.go b/pkg/applicationprofilemanager/v1/applicationprofile_manager.go index c3575109..58f84517 100644 --- a/pkg/applicationprofilemanager/v1/applicationprofile_manager.go +++ b/pkg/applicationprofilemanager/v1/applicationprofile_manager.go @@ -169,44 +169,50 @@ func (am *ApplicationProfileManager) saveProfile(ctx context.Context, watchedCon return } - // activity sets + // check if we have new activities to save + var addedActivities int syscalls := mapset.NewSet[string]() // existing activity - existingActivity, _ := am.storageClient.GetApplicationActivity(slug, namespace) - if existingActivity != nil { + existingActivity, _ := am.storageClient.GetApplicationActivity(namespace, slug) + if existingActivity != nil && existingActivity.Spec.Syscalls != nil { syscalls.Append(existingActivity.Spec.Syscalls...) } - // new activity - newActivity := &v1beta1.ApplicationActivity{ - ObjectMeta: metav1.ObjectMeta{ - Name: slug, - Annotations: map[string]string{ - instanceidhandler.WlidMetadataKey: watchedContainer.Wlid, - instanceidhandler.StatusMetadataKey: "", - }, - Labels: utils.GetLabels(watchedContainer, true), - }, - } - // add syscalls - newSyscalls, err := am.syscallPeekFunc(watchedContainer.NsMntId) - if err == nil { - syscalls.Append(newSyscalls...) - } else { + // get syscalls from IG + observedSyscalls, err := am.syscallPeekFunc(watchedContainer.NsMntId) + if err != nil { logger.L().Ctx(ctx).Error("ApplicationProfileManager - failed to get syscalls", helpers.Error(err)) } - newActivity.Spec.Syscalls = syscalls.ToSlice() - if err := am.storageClient.CreateApplicationActivity(newActivity, namespace); err != nil { - logger.L().Ctx(ctx).Error("ApplicationProfileManager - failed to save application activity", helpers.Error(err)) + addedActivities += syscalls.Append(observedSyscalls...) + // new activity + if addedActivities > 0 { + newActivity := &v1beta1.ApplicationActivity{ + ObjectMeta: metav1.ObjectMeta{ + Name: slug, + Annotations: map[string]string{ + instanceidhandler.WlidMetadataKey: watchedContainer.Wlid, + instanceidhandler.StatusMetadataKey: "", + }, + Labels: utils.GetLabels(watchedContainer, true), + }, + } + // add syscalls + newActivity.Spec.Syscalls = syscalls.ToSlice() + // save application activity + if err := am.storageClient.CreateApplicationActivity(newActivity, namespace); err != nil { + logger.L().Ctx(ctx).Error("ApplicationProfileManager - failed to save application activity", helpers.Error(err)) + } + logger.L().Debug("ApplicationProfileManager - saved application activity", helpers.String("slug", slug), helpers.String("container ID", watchedContainer.ContainerID), helpers.String("k8s workload", watchedContainer.K8sContainerID)) } // profile sets - capabilities := am.capabilitiesSets.Get(watchedContainer.K8sContainerID) - execs := am.execSets.Get(watchedContainer.K8sContainerID) - opens := am.openSets.Get(watchedContainer.K8sContainerID) + var addedProfiles int + capabilities := mapset.NewSet[string]() + execs := make(map[string]mapset.Set[string]) + opens := make(map[string]mapset.Set[string]) // existing profile - existingProfile, _ := am.storageClient.GetApplicationProfile(slug, namespace) + existingProfile, _ := am.storageClient.GetApplicationProfile(namespace, slug) existingProfileContainer := utils.GetApplicationProfileContainer(existingProfile, watchedContainer.ContainerType, watchedContainer.ContainerIndex) - if existingProfile != nil { + if existingProfileContainer != nil { capabilities.Append(existingProfileContainer.Capabilities...) for _, exec := range existingProfileContainer.Execs { if _, exist := execs[exec.Path]; !exist { @@ -221,56 +227,72 @@ func (am *ApplicationProfileManager) saveProfile(ctx context.Context, watchedCon opens[open.Path].Append(open.Flags...) } } - // new profile - newProfile := &v1beta1.ApplicationProfile{ - ObjectMeta: metav1.ObjectMeta{ - Name: slug, - Annotations: map[string]string{ - instanceidhandler.WlidMetadataKey: watchedContainer.Wlid, - instanceidhandler.StatusMetadataKey: "", - }, - Labels: utils.GetLabels(watchedContainer, true), - }, - } - newProfileContainer := v1beta1.ApplicationProfileContainer{ - Name: watchedContainer.InstanceID.GetContainerName(), - } - // add capabilities - newProfileContainer.Capabilities = capabilities.ToSlice() - sort.Strings(newProfileContainer.Capabilities) - // add execs - newProfileContainer.Execs = make([]v1beta1.ExecCalls, 0) - for path, exec := range execs { - args := exec.ToSlice() - sort.Strings(args) - newProfileContainer.Execs = append(newProfileContainer.Execs, v1beta1.ExecCalls{ - Path: path, - Args: args, - }) - } - // add opens - newProfileContainer.Opens = make([]v1beta1.OpenCalls, 0) - for path, open := range opens { - flags := open.ToSlice() - sort.Strings(flags) - newProfileContainer.Opens = append(newProfileContainer.Opens, v1beta1.OpenCalls{ - Path: path, - Flags: flags, - }) - } - // insert application profile container - utils.InsertApplicationProfileContainer(newProfile, watchedContainer.ContainerType, watchedContainer.ContainerIndex, newProfileContainer) - // save application profile - if err := am.storageClient.CreateApplicationProfile(newProfile, namespace); err != nil { - logger.L().Ctx(ctx).Error("ApplicationProfileManager - failed to save application profile", helpers.Error(err)) + // get capabilities, execs and opens from IG + addedProfiles += capabilities.Append(am.capabilitiesSets.Get(watchedContainer.K8sContainerID).ToSlice()...) + for path, exec := range am.execSets.Get(watchedContainer.K8sContainerID) { + if _, exist := execs[path]; !exist { + execs[path] = mapset.NewSet[string]() + } + addedProfiles += execs[path].Append(exec.ToSlice()...) } - logger.L().Debug("ApplicationProfileManager - saved application profile", helpers.String("slug", slug), helpers.String("container ID", watchedContainer.ContainerID), helpers.String("k8s workload", watchedContainer.K8sContainerID), helpers.Interface("profile", newProfile)) - // profile summary - summary := &v1beta1.ApplicationProfileSummary{ - ObjectMeta: newProfile.ObjectMeta, + for path, open := range am.openSets.Get(watchedContainer.K8sContainerID) { + if _, exist := opens[path]; !exist { + opens[path] = mapset.NewSet[string]() + } + addedProfiles += opens[path].Append(open.ToSlice()...) } - if err := am.storageClient.CreateApplicationProfileSummary(summary, namespace); err != nil { - logger.L().Ctx(ctx).Error("ApplicationProfileManager - failed to save application profile summary", helpers.Error(err)) + // new profile + if addedProfiles > 0 { + newProfile := &v1beta1.ApplicationProfile{ + ObjectMeta: metav1.ObjectMeta{ + Name: slug, + Annotations: map[string]string{ + instanceidhandler.WlidMetadataKey: watchedContainer.Wlid, + instanceidhandler.StatusMetadataKey: "", + }, + Labels: utils.GetLabels(watchedContainer, true), + }, + } + newProfileContainer := &v1beta1.ApplicationProfileContainer{ + Name: watchedContainer.InstanceID.GetContainerName(), + } + // add capabilities + newProfileContainer.Capabilities = capabilities.ToSlice() + sort.Strings(newProfileContainer.Capabilities) + // add execs + newProfileContainer.Execs = make([]v1beta1.ExecCalls, 0) + for path, exec := range execs { + args := exec.ToSlice() + sort.Strings(args) + newProfileContainer.Execs = append(newProfileContainer.Execs, v1beta1.ExecCalls{ + Path: path, + Args: args, + }) + } + // add opens + newProfileContainer.Opens = make([]v1beta1.OpenCalls, 0) + for path, open := range opens { + flags := open.ToSlice() + sort.Strings(flags) + newProfileContainer.Opens = append(newProfileContainer.Opens, v1beta1.OpenCalls{ + Path: path, + Flags: flags, + }) + } + // insert application profile container + utils.InsertApplicationProfileContainer(newProfile, watchedContainer.ContainerType, watchedContainer.ContainerIndex, newProfileContainer) + // save application profile + if err := am.storageClient.CreateApplicationProfile(newProfile, namespace); err != nil { + logger.L().Ctx(ctx).Error("ApplicationProfileManager - failed to save application profile", helpers.Error(err)) + } + logger.L().Debug("ApplicationProfileManager - saved application profile", helpers.String("slug", slug), helpers.String("container ID", watchedContainer.ContainerID), helpers.String("k8s workload", watchedContainer.K8sContainerID)) + // profile summary + summary := &v1beta1.ApplicationProfileSummary{ + ObjectMeta: newProfile.ObjectMeta, + } + if err := am.storageClient.CreateApplicationProfileSummary(summary, namespace); err != nil { + logger.L().Ctx(ctx).Error("ApplicationProfileManager - failed to save application profile summary", helpers.Error(err)) + } } } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 59b167a6..3a8c79b6 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -138,31 +138,34 @@ func GetLabels(watchedContainer *WatchedContainerData, stripContainer bool) map[ return labels } -func GetApplicationProfileContainer(profile *v1beta1.ApplicationProfile, containerType ContainerType, containerIndex int) v1beta1.ApplicationProfileContainer { +func GetApplicationProfileContainer(profile *v1beta1.ApplicationProfile, containerType ContainerType, containerIndex int) *v1beta1.ApplicationProfileContainer { + if profile == nil { + return nil + } switch containerType { case Container: if len(profile.Spec.Containers) > containerIndex { - return profile.Spec.Containers[containerIndex] + return &profile.Spec.Containers[containerIndex] } case InitContainer: if len(profile.Spec.InitContainers) > containerIndex { - return profile.Spec.InitContainers[containerIndex] + return &profile.Spec.InitContainers[containerIndex] } } - return v1beta1.ApplicationProfileContainer{} + return nil } -func InsertApplicationProfileContainer(profile *v1beta1.ApplicationProfile, containerType ContainerType, containerIndex int, profileContainer v1beta1.ApplicationProfileContainer) { +func InsertApplicationProfileContainer(profile *v1beta1.ApplicationProfile, containerType ContainerType, containerIndex int, profileContainer *v1beta1.ApplicationProfileContainer) { switch containerType { case Container: if len(profile.Spec.Containers) <= containerIndex { profile.Spec.Containers = append(profile.Spec.Containers, make([]v1beta1.ApplicationProfileContainer, containerIndex-len(profile.Spec.Containers)+1)...) } - profile.Spec.Containers[containerIndex] = profileContainer + profile.Spec.Containers[containerIndex] = *profileContainer case InitContainer: if len(profile.Spec.InitContainers) <= containerIndex { profile.Spec.InitContainers = append(profile.Spec.InitContainers, make([]v1beta1.ApplicationProfileContainer, containerIndex-len(profile.Spec.InitContainers)+1)...) } - profile.Spec.InitContainers[containerIndex] = profileContainer + profile.Spec.InitContainers[containerIndex] = *profileContainer } }