diff --git a/api/unversioned/config/config.go b/api/unversioned/config/config.go index c469755bfe..8fbc09cc25 100644 --- a/api/unversioned/config/config.go +++ b/api/unversioned/config/config.go @@ -75,6 +75,7 @@ const ( oneDay = unversioned.Duration(time.Hour * 24) ) +// TODO - add defaults for gathering/scanning/removing Pinned images func Default() *unversioned.EraserConfig { return &unversioned.EraserConfig{ Manager: unversioned.ManagerConfig{ diff --git a/api/unversioned/imagejob_types.go b/api/unversioned/imagejob_types.go index 5ef6ae5001..f2b9b1644b 100644 --- a/api/unversioned/imagejob_types.go +++ b/api/unversioned/imagejob_types.go @@ -25,6 +25,7 @@ type Image struct { ImageID string `json:"image_id"` Names []string `json:"names,omitempty"` Digests []string `json:"digests,omitempty"` + Pinned bool `json:"pinned,omitempty"` } // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! diff --git a/api/v1/zz_generated.conversion.go b/api/v1/zz_generated.conversion.go index 816e166670..678844c967 100644 --- a/api/v1/zz_generated.conversion.go +++ b/api/v1/zz_generated.conversion.go @@ -138,11 +138,6 @@ func autoConvert_unversioned_Image_To_v1_Image(in *unversioned.Image, out *Image return nil } -// Convert_unversioned_Image_To_v1_Image is an autogenerated conversion function. -func Convert_unversioned_Image_To_v1_Image(in *unversioned.Image, out *Image, s conversion.Scope) error { - return autoConvert_unversioned_Image_To_v1_Image(in, out, s) -} - func autoConvert_v1_ImageJob_To_unversioned_ImageJob(in *ImageJob, out *unversioned.ImageJob, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta if err := Convert_v1_ImageJobStatus_To_unversioned_ImageJobStatus(&in.Status, &out.Status, s); err != nil { diff --git a/api/v1alpha1/zz_generated.conversion.go b/api/v1alpha1/zz_generated.conversion.go index 70c4d3e92e..be84a6fbc8 100644 --- a/api/v1alpha1/zz_generated.conversion.go +++ b/api/v1alpha1/zz_generated.conversion.go @@ -348,11 +348,6 @@ func autoConvert_unversioned_Image_To_v1alpha1_Image(in *unversioned.Image, out return nil } -// Convert_unversioned_Image_To_v1alpha1_Image is an autogenerated conversion function. -func Convert_unversioned_Image_To_v1alpha1_Image(in *unversioned.Image, out *Image, s conversion.Scope) error { - return autoConvert_unversioned_Image_To_v1alpha1_Image(in, out, s) -} - func autoConvert_v1alpha1_ImageJob_To_unversioned_ImageJob(in *ImageJob, out *unversioned.ImageJob, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta if err := Convert_v1alpha1_ImageJobStatus_To_unversioned_ImageJobStatus(&in.Status, &out.Status, s); err != nil { diff --git a/controllers/imagecollector/imagecollector_controller.go b/controllers/imagecollector/imagecollector_controller.go index dc918a1f82..d91018e8e2 100644 --- a/controllers/imagecollector/imagecollector_controller.go +++ b/controllers/imagecollector/imagecollector_controller.go @@ -308,10 +308,12 @@ func (r *Reconciler) createImageJob(ctx context.Context) (ctrl.Result, error) { fmt.Sprintf("--pprof-port=%d", profileConfig.Port), } - collArgs := []string{"--scan-disabled=" + strconv.FormatBool(scanDisabled)} + // todo implement the config for this + collArgs := []string{"--scan-disabled=" + strconv.FormatBool(scanDisabled), "--scan-pinned=" + strconv.FormatBool(scanCfg.ScanPinned)} collArgs = append(collArgs, profileArgs...) - removerArgs := []string{"--log-level=" + logger.GetLevel()} + // todo implement the config for this + removerArgs := []string{"--log-level=" + logger.GetLevel(), "--remove-pinned=" + strconv.FormatBool(eraserCfg.RemovePinned)} removerArgs = append(removerArgs, profileArgs...) pullSecrets := []corev1.LocalObjectReference{} diff --git a/go.mod b/go.mod index 1e9f86c754..10beae7d9f 100644 --- a/go.mod +++ b/go.mod @@ -151,6 +151,7 @@ replace ( k8s.io/component-helpers => k8s.io/component-helpers v0.26.11 k8s.io/controller-manager => k8s.io/controller-manager v0.26.11 k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.26.11 + k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.26.11 k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.26.11 k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.26.11 k8s.io/kube-proxy => k8s.io/kube-proxy v0.26.11 diff --git a/pkg/collector/collector.go b/pkg/collector/collector.go index 09c2c81641..80fdaf1f9c 100644 --- a/pkg/collector/collector.go +++ b/pkg/collector/collector.go @@ -23,6 +23,7 @@ var ( enableProfile = flag.Bool("enable-pprof", false, "enable pprof profiling") profilePort = flag.Int("pprof-port", 6060, "port for pprof profiling. defaulted to 6060 if unspecified") scanDisabled = flag.Bool("scan-disabled", false, "boolean for if scanner container is disabled") + scanPinned = flag.Bool("scan-pinned", false, "boolean for if scanner container should scan pinned images") // Timeout of connecting to server (default: 5m). timeout = 5 * time.Minute @@ -80,6 +81,11 @@ func main() { } log.Info("images collected", "finalImages:", finalImages) + if !(*scanPinned) { + log.Info("skipping scanning pinned images") + finalImages = util.RemovePinnedImages(finalImages) + } + data, err := json.Marshal(finalImages) if err != nil { log.Error(err, "failed to encode finalImages") diff --git a/pkg/collector/helpers.go b/pkg/collector/helpers.go index 4bb52456d9..1216c8e148 100644 --- a/pkg/collector/helpers.go +++ b/pkg/collector/helpers.go @@ -28,6 +28,7 @@ func getImages(c cri.Collector) ([]unversioned.Image, error) { newImg := unversioned.Image{ ImageID: img.Id, Names: repoTags, + Pinned: img.Pinned, } digests, errs := util.ProcessRepoDigests(img.RepoDigests) @@ -71,6 +72,7 @@ func getImages(c cri.Collector) ([]unversioned.Image, error) { ImageID: imageID, Names: img.Names, Digests: img.Digests, + Pinned: img.Pinned, } if !util.IsExcluded(excluded, currImage.ImageID, idToImageMap) { diff --git a/pkg/remover/helpers.go b/pkg/remover/helpers.go index 9d16e1d7d6..c819ef5140 100644 --- a/pkg/remover/helpers.go +++ b/pkg/remover/helpers.go @@ -8,7 +8,7 @@ import ( util "github.com/eraser-dev/eraser/pkg/utils" ) -func removeImages(c cri.Remover, targetImages []string) (int, error) { +func removeImages(c cri.Remover, removePinned bool, targetImages []string) (int, error) { removed := 0 backgroundContext, cancel := context.WithTimeout(context.Background(), timeout) @@ -30,6 +30,7 @@ func removeImages(c cri.Remover, targetImages []string) (int, error) { newImg := unversioned.Image{ ImageID: img.Id, Names: repoTags, + Pinned: img.Pinned, } digests, errs := util.ProcessRepoDigests(img.RepoDigests) @@ -75,6 +76,12 @@ func removeImages(c cri.Remover, targetImages []string) (int, error) { continue } + // TODO - figure out why is imgDigestOrTag used instead of imageID when it's called "idToImageMap" (copied usage from isExcluded). + if !removePinned && util.IsPinned(imageID, idToImageMap) { + log.Info("image is kept due to being pinned", "given", imgDigestOrTag, "imageID", imageID, "name", idToImageMap[imageID]) + continue + } + err = c.DeleteImage(backgroundContext, imageID) if err != nil { log.Error(err, "error removing image", "given", imgDigestOrTag, "imageID", imageID, "name", idToImageMap[imageID]) @@ -108,6 +115,11 @@ func removeImages(c cri.Remover, targetImages []string) (int, error) { continue } + if !removePinned && util.IsPinned(imageID, idToImageMap) { + log.Info("image is kept due to being pinned", "imageID", imageID, "name", idToImageMap[imageID]) + continue + } + if err := c.DeleteImage(backgroundContext, imageID); err != nil { success = false log.Error(err, "error removing image", "imageID", imageID, "name", idToImageMap[imageID]) diff --git a/pkg/remover/remover.go b/pkg/remover/remover.go index a4228c6b67..eee7b697d9 100644 --- a/pkg/remover/remover.go +++ b/pkg/remover/remover.go @@ -30,6 +30,7 @@ var ( imageListPtr = flag.String("imagelist", "", "name of ImageList") enableProfile = flag.Bool("enable-pprof", false, "enable pprof profiling") profilePort = flag.Int("pprof-port", 6060, "port for pprof profiling. defaulted to 6060 if unspecified") + removePinned = flag.Bool("remove-pinned", false, "skip over pinned images when removing") // Timeout of connecting to server (default: 5m). timeout = 5 * time.Minute @@ -130,7 +131,8 @@ func main() { log.Info("no images to exclude") } - removed, err := removeImages(client, imagelist) + // we pass in the removePinned flag to removeImages, because as of now we just have a list of imageIDs, and we don't know if they are pinned or not + removed, err := removeImages(client, *removePinned, imagelist) if err != nil { log.Error(err, "failed to remove images") os.Exit(generalErr) diff --git a/pkg/scanners/trivy/trivy.go b/pkg/scanners/trivy/trivy.go index 8a1ceed5ef..3862858dea 100644 --- a/pkg/scanners/trivy/trivy.go +++ b/pkg/scanners/trivy/trivy.go @@ -124,6 +124,7 @@ func main() { log.Info("Failed", "Images", failedImages) } + // send to eraser? err = provider.SendImages(vulnerableImages, failedImages) if err != nil { log.Error(err, "unable to write images") diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 01a9555ca8..9ee2964b26 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -178,6 +178,10 @@ func GetNonRunningImages(runningImages map[string]string, allImages []unversione return nonRunningImages } +func IsPinned(img string, idToImageMap map[string]unversioned.Image) bool { + return idToImageMap[img].Pinned +} + func IsExcluded(excluded map[string]struct{}, img string, idToImageMap map[string]unversioned.Image) bool { if len(excluded) == 0 { return false @@ -417,3 +421,13 @@ func ProcessRepoDigests(repoDigests []string) ([]string, []error) { return digests, errs } + +func RemovePinnedImages(images []unversioned.Image) []unversioned.Image { + filteredImages := []unversioned.Image{} + for _, image := range images { + if !image.Pinned { + filteredImages = append(filteredImages, image) + } + } + return filteredImages +}