New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New output #1320
New output #1320
Conversation
Add a CLI command that launches an image scan. Does not scan images yet. Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Signed-off-by: Amir Malka <amirm@armosec.io>
…can-workload Signed-off-by: Amir Malka <amirm@armosec.io>
Signed-off-by: Amir Malka <amirm@armosec.io>
This commit adds a CLI command and an associated package that scan images for vulnerabilities. Signed-off-by: Vlad Klokun <vklokun@protonmail.ch> feat(imagescan): fail on exceeding the severity threshold Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
…kload Signed-off-by: Amir Malka <amirm@armosec.io>
This commit adds the dependencies necessary for image scanning. Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
…kload Signed-off-by: Amir Malka <amirm@armosec.io>
Signed-off-by: Amir Malka <amirm@armosec.io>
…into feat-image-scan-svc
PR Analysis
PR Feedback
How to use
|
/improve |
Preparing review... |
cmd/scan/scan.go
Outdated
@@ -90,6 +91,8 @@ func GetScanCommand(ks meta.IKubescape) *cobra.Command { | |||
scanCmd.PersistentFlags().BoolVarP(&scanInfo.Submit, "submit", "", false, "Submit the scan results to Kubescape SaaS where you can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more. By default the results are not submitted") | |||
scanCmd.PersistentFlags().BoolVarP(&scanInfo.OmitRawResources, "omit-raw-resources", "", false, "Omit raw resources from the output. By default the raw resources are included in the output") | |||
scanCmd.PersistentFlags().BoolVarP(&scanInfo.PrintAttackTree, "print-attack-tree", "", false, "Print attack tree") | |||
scanCmd.PersistentFlags().BoolVarP(&scanInfo.ScanImages, "scan-images", "", false, "Scan resources images") | |||
scanCmd.PersistentFlags().BoolVarP(&scanInfo.IsSecurityView, "security-view", "", false, "Show security view") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use --view
instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how would this work when using security view with resource view?
return err | ||
} | ||
logger.L().Success("Image scan completed successfully") | ||
|
||
scanInfo.SetScanType(cautils.ScanTypeImage) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move to pre-run
var workloads []workloadinterface.IMetadata | ||
var err error | ||
|
||
if scanInfo.ChartPath != "" && scanInfo.FilePath != "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use an interface instead
@@ -98,6 +107,80 @@ func (fileHandler *FileResourceHandler) GetResources(ctx context.Context, sessio | |||
return k8sResources, allResources, ksResources, excludedRulesMap, nil | |||
} | |||
|
|||
func getWorkloadFromHelmChart(ctx context.Context, helmPath, workloadPath string) (map[string]reporthandling.Source, []workloadinterface.IMetadata, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add unit tests
|
||
} | ||
|
||
func getWorkloadSourceHelmChart(repoRoot string, source string, gitRepo *cautils.LocalGitRepository, helmChart cautils.Chart) reporthandling.Source { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add unit tests
var workloadSource reporthandling.Source | ||
if clonedRepo != "" { | ||
workloadSource = reporthandling.Source{ | ||
Path: "", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Path: "", | |
Path: clonedRepo, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove if/else
pp.mainPrinter = prettyprinter.NewImagePrinter(pp.writer, pp.verboseMode) | ||
case cautils.ScanTypeWorkload: | ||
pp.mainPrinter = prettyprinter.NewWorkloadPrinter(pp.writer) | ||
default: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add FW type
Signed-off-by: David Wertenteil <dwertent@armosec.io>
Update github actions
installHelmText = fmt.Sprintf("Install helm for continuos monitoring: %s", linkToHelm) | ||
CICDSetupText = fmt.Sprintf("Add Kubescape to CICD: %s", linkToCICDSetup) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
installHelmText = fmt.Sprintf("Install helm for continuos monitoring: %s", linkToHelm) | |
CICDSetupText = fmt.Sprintf("Add Kubescape to CICD: %s", linkToCICDSetup) | |
installHelmText = fmt.Sprintf("Install Kubescape in your cluster for continuous monitoring: %s", linkToHelm) | |
CICDSetupText = fmt.Sprintf("Add Kubescape to your CI/CD pipeline: %s", linkToCICDSetup) |
Scan results:
|
Preparing review... |
2 similar comments
Preparing review... |
Preparing review... |
Pitying fools... |
doc, err := models.NewDocument(presenterConfig.Packages, presenterConfig.Context, presenterConfig.Matches, presenterConfig.IgnoredMatches, presenterConfig.MetadataProvider, nil, presenterConfig.DBStatus) | ||
if err != nil { | ||
logger.L().Error(fmt.Sprintf("failed to create document for image: %v", imageScanData[i].Image), helpers.Error(err)) | ||
continue | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: It's recommended to handle errors properly. In the function convertToImageScanSummary
, when an error occurs while creating a new document, the error is logged and the loop continues. This could lead to unexpected behavior if the error is not handled properly. Consider returning the error and handling it in the calling function.
doc, err := models.NewDocument(presenterConfig.Packages, presenterConfig.Context, presenterConfig.Matches, presenterConfig.IgnoredMatches, presenterConfig.MetadataProvider, nil, presenterConfig.DBStatus) | |
if err != nil { | |
logger.L().Error(fmt.Sprintf("failed to create document for image: %v", imageScanData[i].Image), helpers.Error(err)) | |
continue | |
} | |
doc, err := models.NewDocument(presenterConfig.Packages, presenterConfig.Context, presenterConfig.Matches, presenterConfig.IgnoredMatches, presenterConfig.MetadataProvider, nil, presenterConfig.DBStatus) | |
if err != nil { | |
return nil, fmt.Errorf("failed to create document for image: %v: %w", imageScanData[i].Image, err) | |
} |
func (pp *PrettyPrinter) ActionPrint(_ context.Context, opaSessionObj *cautils.OPASessionObj, imageScanData []cautils.ImageScanData) { | ||
if opaSessionObj != nil { | ||
fmt.Fprintf(pp.writer, "\n"+getSeparator("^")+"\n") | ||
|
||
sortedControlIDs := getSortedControlsIDs(opaSessionObj.Report.SummaryDetails.Controls) // ListControls().All()) | ||
|
||
switch pp.viewType { | ||
case cautils.ControlViewType: | ||
pp.printResults(&opaSessionObj.Report.SummaryDetails.Controls, opaSessionObj.AllResources, sortedControlIDs) | ||
case cautils.ResourceViewType: | ||
if pp.verboseMode { | ||
pp.resourceTable(opaSessionObj) | ||
} | ||
} | ||
|
||
pp.printOverview(opaSessionObj, pp.verboseMode) | ||
|
||
pp.mainPrinter.PrintConfigurationsScanning(&opaSessionObj.Report.SummaryDetails, sortedControlIDs) | ||
|
||
// When writing to Stdout, we aren’t really writing to an output file, | ||
// so no need to print that we are | ||
if pp.writer.Name() != os.Stdout.Name() { | ||
printer.LogOutputFile(pp.writer.Name()) | ||
} | ||
|
||
pp.printAttackTracks(opaSessionObj) | ||
} | ||
|
||
if len(imageScanData) > 0 { | ||
pp.PrintImageScan(imageScanData) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: The function ActionPrint
is doing too many things. It's printing the report, handling image scanning, and printing attack tracks. Consider breaking it down into smaller functions to improve readability and maintainability.
func (pp *PrettyPrinter) ActionPrint(_ context.Context, opaSessionObj *cautils.OPASessionObj, imageScanData []cautils.ImageScanData) { | |
if opaSessionObj != nil { | |
fmt.Fprintf(pp.writer, "\n"+getSeparator("^")+"\n") | |
sortedControlIDs := getSortedControlsIDs(opaSessionObj.Report.SummaryDetails.Controls) // ListControls().All()) | |
switch pp.viewType { | |
case cautils.ControlViewType: | |
pp.printResults(&opaSessionObj.Report.SummaryDetails.Controls, opaSessionObj.AllResources, sortedControlIDs) | |
case cautils.ResourceViewType: | |
if pp.verboseMode { | |
pp.resourceTable(opaSessionObj) | |
} | |
} | |
pp.printOverview(opaSessionObj, pp.verboseMode) | |
pp.mainPrinter.PrintConfigurationsScanning(&opaSessionObj.Report.SummaryDetails, sortedControlIDs) | |
// When writing to Stdout, we aren’t really writing to an output file, | |
// so no need to print that we are | |
if pp.writer.Name() != os.Stdout.Name() { | |
printer.LogOutputFile(pp.writer.Name()) | |
} | |
pp.printAttackTracks(opaSessionObj) | |
} | |
if len(imageScanData) > 0 { | |
pp.PrintImageScan(imageScanData) | |
} | |
} | |
func (pp *PrettyPrinter) ActionPrint(_ context.Context, opaSessionObj *cautils.OPASessionObj, imageScanData []cautils.ImageScanData) { | |
if opaSessionObj != nil { | |
pp.printReport(opaSessionObj) | |
} | |
if len(imageScanData) > 0 { | |
pp.PrintImageScan(imageScanData) | |
} | |
} | |
func (pp *PrettyPrinter) printReport(opaSessionObj *cautils.OPASessionObj) { | |
fmt.Fprintf(pp.writer, "\n"+getSeparator("^")+"\n") | |
sortedControlIDs := getSortedControlsIDs(opaSessionObj.Report.SummaryDetails.Controls) | |
switch pp.viewType { | |
case cautils.ControlViewType: | |
pp.printResults(&opaSessionObj.Report.SummaryDetails.Controls, opaSessionObj.AllResources, sortedControlIDs) | |
case cautils.ResourceViewType: | |
if pp.verboseMode { | |
pp.resourceTable(opaSessionObj) | |
} | |
} | |
pp.printOverview(opaSessionObj, pp.verboseMode) | |
pp.mainPrinter.PrintConfigurationsScanning(&opaSessionObj.Report.SummaryDetails, sortedControlIDs) | |
if pp.writer.Name() != os.Stdout.Name() { | |
printer.LogOutputFile(pp.writer.Name()) | |
} | |
pp.printAttackTracks(opaSessionObj) | |
} |
Scan results:
|
Overview
scan image
output: pretty printer, json and sarifscan workload
command and outputscan
commandAdditional Information
scan
command will be showing a security view when combined with the--view=security
flag. This view will show a specific set of controls, and how to continue investigating the resources / control documentation. It will also show the compliance score for the NSA and MITRE frameworks. On top of that, the top 5 most dangerous workloads will be shown in a new sectionkubescape scan workload <kind>/<name> --namespace=<namespace>
. There are two available flags:--file-path
for scanning using a file, and--chart-path
for scanning using a helm-chart. The second flag must be combined with the first.scan image
andscan workload
command will be showing security view.--scan-images
flag to scanning all images on a cluster/repository/file/helm-chartTODO:
How to Test
As of the time of opening this PR, you will need to add
--env=dev
every time you use--view=security
flagExamples/Screenshots
kubescape scan --view=security --env=dev
kubescape scan workload Deployment/argocd-redis --namespace argocd --env=dev
kubescape scan image redis:7.0.11-alpine
kubescape scan image redis:7.0.11-alpine -v
kubescape scan /Users/danielgrunberger/charts/stable --security-view --env=dev