From 392bea9523499c76f21a9971ca609559602ef449 Mon Sep 17 00:00:00 2001 From: Matthias Bertschy Date: Wed, 8 Nov 2023 17:30:11 +0100 Subject: [PATCH] update applicationprofile type Signed-off-by: Matthias Bertschy --- go.mod | 2 +- go.sum | 4 +- .../v1/applicationprofile_manager.go | 53 ++++++++++++++++--- .../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, 100 insertions(+), 16 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..f433bc08 100644 --- a/pkg/applicationprofilemanager/v1/applicationprofile_manager.go +++ b/pkg/applicationprofilemanager/v1/applicationprofile_manager.go @@ -69,6 +69,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 +186,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,24 +216,28 @@ 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() // 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{ + newProfileContainer.Execs = append(newProfileContainer.Execs, v1beta1.ExecCalls{ Path: path, Args: exec.ToSlice(), }) } // 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{ + newProfileContainer.Opens = append(newProfileContainer.Opens, v1beta1.OpenCalls{ Path: path, Flags: open.ToSlice(), }) } + // 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)) } 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 + } +}