From 9c9ca7fe86dcc3bcd00f88013e349f5500179ee5 Mon Sep 17 00:00:00 2001 From: Fabien Boucher Date: Wed, 10 Apr 2024 14:23:41 +0000 Subject: [PATCH] cli/dev - Add getImagesSecurityIssues command to discover images w/ sec issues The idea is to have a developer command to quickly get a reports of images with Critical or High security issues level reported by quay.io/Clair. If any we could just trigger a rebuild of the image. Change-Id: Ia29de47312e15d7234ce56820af3024ded66caaa --- CHANGELOG.md | 4 ++ cli/cmd/dev/dev.go | 85 +++++++++++++++++++++++++++++++++ controllers/libs/base/images.go | 18 ++++++- doc/reference/cli/index.md | 11 +++++ 4 files changed, 117 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6eab9dca..8517abbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. ## [in development] ### Added + +- Dev CLI - Add command "go run ./main.go dev getImagesSecurityIssue" to ease getting a small report of HIGH + and CRITICAL Security issues reported by quay.io on container images used by the sf-operator. + ### Changed - Zookeeper version bumped to 3.8.4 diff --git a/cli/cmd/dev/dev.go b/cli/cmd/dev/dev.go index bcc3c02a..64da16f0 100644 --- a/cli/cmd/dev/dev.go +++ b/cli/cmd/dev/dev.go @@ -19,7 +19,10 @@ package dev import ( "context" + "encoding/json" "errors" + "fmt" + "net/http" "os" "path/filepath" "strings" @@ -28,6 +31,7 @@ import ( ms "github.com/softwarefactory-project/sf-operator/cli/cmd/dev/microshift" cliutils "github.com/softwarefactory-project/sf-operator/cli/cmd/utils" "github.com/softwarefactory-project/sf-operator/controllers" + "github.com/softwarefactory-project/sf-operator/controllers/libs/base" "k8s.io/client-go/rest" "github.com/spf13/cobra" @@ -293,6 +297,79 @@ func devCloneAsAdmin(kmd *cobra.Command, args []string) { gerrit.CloneAsAdmin(&env, fqdn, repoName, dest, verify) } +func getImagesSecurityIssues(kmd *cobra.Command, args []string) { + + const quaySFBaseURL = "https://quay.io/api/v1/repository/software-factory/" + + type Vuln struct { + Severity string + Link string + Name string + } + + type Feature struct { + Name string + Vulnerabilities []Vuln + } + + type Layer struct { + Features []Feature + } + + type Data struct { + Layer Layer + } + + type Scan struct { + Status string + Data Data + } + + type Tag struct { + ManifestDigest string `json:"manifest_digest"` + } + + type Image struct { + Name string + Tags map[string]Tag + } + + getImageDigest := func(image base.Image) string { + + url := quaySFBaseURL + image.Name + resp, _ := http.Get(url) + target := Image{} + json.NewDecoder(resp.Body).Decode(&target) + + return target.Tags[image.Version].ManifestDigest + + } + + getImageReport := func(image base.Image) { + + digest := getImageDigest(image) + manifest := image.Name + "/manifest/" + digest + url := quaySFBaseURL + manifest + "/security" + resp, _ := http.Get(url) + target := Scan{} + json.NewDecoder(resp.Body).Decode(&target) + + println("\nScan result for: " + image.Name) + for _, feature := range target.Data.Layer.Features { + for _, vuln := range feature.Vulnerabilities { + if vuln.Severity == "High" || vuln.Severity == "Critical" { + fmt.Printf("- %s [%s] %s\n", feature.Name, vuln.Severity, vuln.Name) + } + } + } + } + + for _, image := range base.GetSelfManagedImages() { + getImageReport(image) + } + +} + func MkDevCmd() *cobra.Command { var ( @@ -337,6 +414,11 @@ func MkDevCmd() *cobra.Command { ValidArgs: devRunTestsAllowedArgs, Run: devRunTests, } + getImagesSecurityIssuesCmd = &cobra.Command{ + Use: "getImagesSecurityIssues", + Long: "Return the list of security issues reported by Quay.io (only High and Critical)", + Run: getImagesSecurityIssues, + } ) // args wipeCmd.Flags().BoolVar(&deleteData, "rm-data", false, "Delete also persistent data. This will result in data loss, like review history.") @@ -362,5 +444,8 @@ func MkDevCmd() *cobra.Command { devCmd.AddCommand(wipeCmd) devCmd.AddCommand(cloneAsAdminCmd) devCmd.AddCommand(runTestsCmd) + + devCmd.AddCommand(getImagesSecurityIssuesCmd) + return devCmd } diff --git a/controllers/libs/base/images.go b/controllers/libs/base/images.go index e8fa9a2a..7a343b4a 100644 --- a/controllers/libs/base/images.go +++ b/controllers/libs/base/images.go @@ -24,11 +24,16 @@ type Image struct { Source string `yaml:"source,omitempty"` } -func getImage(name string) string { +func loadImages() ContainerImages { var images ContainerImages if err := yaml.UnmarshalStrict([]byte(imagesYAML), &images); err != nil { panic(err) } + return images +} + +func getImage(name string) string { + images := loadImages() for _, image := range images.Images { if image.Name == name { return image.Container + ":" + image.Version @@ -38,6 +43,17 @@ func getImage(name string) string { panic("Unknown container image: " + name) } +func GetSelfManagedImages() []Image { + ret := []Image{} + images := loadImages() + for _, image := range images.Images { + if image.Source != "" { + ret = append(ret, image) + } + } + return ret +} + func ZuulExecutorImage() string { return getImage("zuul-executor") } diff --git a/doc/reference/cli/index.md b/doc/reference/cli/index.md index 68e7d625..bb6d417e 100644 --- a/doc/reference/cli/index.md +++ b/doc/reference/cli/index.md @@ -16,6 +16,7 @@ deployments, beyond what can be defined in a custom resource manifest. - [create standalone-sf](#create-standalone-sf) - [run-tests](#run-tests) - [wipe gerrit](#wipe-gerrit) + - [getImagesSecurityIssues](#getimagessecurityissues) 1. [Init](#init) 1. [Nodepool](#nodepool) - [configure providers-secrets](#configure-providers-secrets) @@ -270,6 +271,16 @@ Flags: |----------|------|-------|----|----| | --rm-data | boolean | Also delete persistent data (repositories, reviews) | yes | False | +#### getImagesSecurityIssues + +To get a report of Security Issues reported by quay.io for container images used by the +sf-operator run: `dev getImageSecurityIssue`. This command helps to decide if we need to +rebuild container images to benefit last security fixes from the base OS. + +```sh +sf-operator dev getImagesSecurityIssues +``` + ### Init The `init` subcommand can be used to initialize a CLI configuration file, or a sample manifest for deploying Software Factory.