Skip to content
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

Vulnerability Scanning Implementation for container images #1489

Open
wants to merge 16 commits into
base: main
Choose a base branch
from

Conversation

karanibm6
Copy link
Contributor

@karanibm6 karanibm6 commented Feb 7, 2024

Changes

Implementation of this SHIP : https://github.com/shipwright-io/community/blob/main/ships/0033-build-output-vulnerability-scanning.md#build-output-vulnerability-scanning

  • Add vulnerability scanning options in build and buildrun types in v1alpha1 and v1beta1
  • Add vulnerable image for unit testing of vulnerability scanning feature
  • Implement vulnerability scanning for container images using trivy and lists vulnerabilities in buildrun output
  • Add e2e tests to verify options for vulnerability scanning

Fixes #1394

Submitter Checklist

  • Includes tests if functionality changed/was added
  • Includes docs if changes are user-facing
  • Set a kind label on this PR
  • Release notes block has been filled in, or marked NONE

See the contributor guide
for details on coding conventions, github and prow interactions, and the code review process.

Release Notes

Vulnerability Scanning Implementation

@openshift-ci openshift-ci bot added the do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. label Feb 7, 2024
Copy link
Contributor

openshift-ci bot commented Feb 7, 2024

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign adambkaplan for approval. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@pull-request-size pull-request-size bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Feb 7, 2024
@karanibm6
Copy link
Contributor Author

/kind feature

@openshift-ci openshift-ci bot added the kind/feature Categorizes issue or PR as related to a new feature. label Feb 7, 2024
@karanibm6 karanibm6 force-pushed the add-vulnerability-scanning branch 8 times, most recently from c5ea814 to a8fd62f Compare February 7, 2024 20:18
@qu1queee qu1queee requested review from qu1queee and removed request for otaviof February 8, 2024 08:29
cmd/image-processing/main_test.go Outdated Show resolved Hide resolved
hack/install-trivy.sh Outdated Show resolved Hide resolved
pkg/apis/build/v1alpha1/build_types.go Outdated Show resolved Hide resolved
pkg/apis/build/v1alpha1/build_types.go Outdated Show resolved Hide resolved
pkg/apis/build/v1alpha1/build_types.go Outdated Show resolved Hide resolved
cmd/image-processing/main.go Outdated Show resolved Hide resolved
cmd/image-processing/main.go Outdated Show resolved Hide resolved
cmd/image-processing/main_test.go Outdated Show resolved Hide resolved
)

const (
VulnerabilityCountLimit = 50 // Number of vulnerabilities to be added to buildrun output.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Would be nice to have it configurable for downstream projects to adapt to their needs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HeavyWombat Shall I add it as another field for vulnerabilityScanOptions ? or Can I set it as an environment variable in some config or in the image-processing container ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial feeling would be an environment variable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be in config.go which reads from environment variables.

pkg/image/vulnerability_scan.go Outdated Show resolved Hide resolved
pkg/image/vulnerability_scan_test.go Outdated Show resolved Hide resolved
pkg/image/vulnerability_scan_test.go Outdated Show resolved Hide resolved
pkg/image/vulnerability_scan_test.go Outdated Show resolved Hide resolved
pkg/image/vulnerability_scan_test.go Outdated Show resolved Hide resolved
pkg/image/vulnerability_scan_test.go Outdated Show resolved Hide resolved
@karanibm6 karanibm6 force-pushed the add-vulnerability-scanning branch 3 times, most recently from eaddddc to 476489d Compare February 17, 2024 12:28
@openshift-ci openshift-ci bot added release-note Label for when a PR has specified a release note and removed do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. labels Feb 17, 2024
@HeavyWombat HeavyWombat self-requested a review February 20, 2024 09:30
Copy link
Contributor

@HeavyWombat HeavyWombat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, thanks for the PR. I am generally speaking fine with it, but have a couple of detail questions.

pkg/apis/build/v1alpha1/build_types.go Outdated Show resolved Hide resolved
)

const (
VulnerabilityCountLimit = 50 // Number of vulnerabilities to be added to buildrun output.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial feeling would be an environment variable.

pkg/image/vulnerability_scan.go Outdated Show resolved Hide resolved
pkg/image/vulnerability_scan.go Outdated Show resolved Hide resolved
test/data/images/vuln-single-image/vuln-image.tar Outdated Show resolved Hide resolved
test/e2e/v1alpha1/e2e_vulnerability_scanning_test.go Outdated Show resolved Hide resolved
cmd/image-processing/main.go Outdated Show resolved Hide resolved
Copy link
Member

@SaschaSchwarze0 SaschaSchwarze0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work.

)

const (
VulnerabilityCountLimit = 50 // Number of vulnerabilities to be added to buildrun output.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be in config.go which reads from environment variables.

pkg/image/vulnerability_scan.go Outdated Show resolved Hide resolved
Comment on lines 472 to 475
return reconcile.Result{}, resources.UpdateConditionWithFalseStatus(ctx, r.client, buildRun, fmt.Sprintf("Vulnerabilities have been found in the output image. For detailed information, see kubectl --namespace %s logs %s --container step-image-processing",
buildRun.Namespace,
lastTaskRun.Status.PodName,
), "VulnerabilitiesFound")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the message, should we say "check the BuildRun status, or see kubectl ..." ?

Can we put VulnerabilitiesFound into a constant ? Would be nearby here:

BuildRunStatePodEvicted = "PodEvicted"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -145,6 +145,12 @@ type GitSourceResult struct {
BranchName string `json:"branchName,omitempty"`
}

// Vulnerability defines a vulnerability by its ID and severity
type Vulnerability struct {
VulnerabilityID string `json:"vulnerabilityID,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The section is called vulnerabilities, then no nead to call it vulnerabilityID insight of it.

Suggested change
VulnerabilityID string `json:"vulnerabilityID,omitempty"`
ID string `json:"id,omitempty"`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did that because it was easy to map it with the result from Trivy scan. I will create a different struct for trivy result.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

test/data/images/vuln-single-image/vuln-image.tar Outdated Show resolved Hide resolved
test/e2e/v1alpha1/e2e_vulnerability_scanning_test.go Outdated Show resolved Hide resolved

// Ensure the BuildRun has been created
err := testBuild.CreateBR(testBuildRun)
Expect(err).ToNot(HaveOccurred(), "Failed to create BuildRun")
if _, err := testBuild.GetBR(testBuildRun.Name); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand that check. Why do we need to check if the BuildRun exists ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because in my tests, I have already created the buildrun, otherwise I had to create a new function for running buildruns.
This condition is also present in validateBuildRunToSucceed function.

@karanibm6 karanibm6 force-pushed the add-vulnerability-scanning branch 3 times, most recently from 03ae3cd to fea1096 Compare April 17, 2024 17:26
Copy link
Contributor

@HeavyWombat HeavyWombat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, thanks for the PR. I only found some small things we should change, but it looks mostly very good to me already.

test "github.com/shipwright-io/build/test/v1beta1_samples"
)

var _ = Describe("Integration tests Build and BuildRuns", func() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var _ = Describe("Integration tests Build and BuildRuns", func() {
var _ = Describe("Vulnerability scan tests", func() {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it is in the integration package, I would say we do not need to repeat that in the name of the tests here.

Comment on lines 73 to 77
func (c *clusterBuildStrategyPrototype) TestMe(f func(clusterBuildStrategy *buildv1beta1.ClusterBuildStrategy)) {
cbs, err := c.Create()
Expect(err).ToNot(HaveOccurred())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Assuming the Expect in this helper function are not causing issues a lot, I would say that it qualifies as a Ginkgo helper function and we should declare it as such.

Suggested change
func (c *clusterBuildStrategyPrototype) TestMe(f func(clusterBuildStrategy *buildv1beta1.ClusterBuildStrategy)) {
cbs, err := c.Create()
Expect(err).ToNot(HaveOccurred())
func (c *clusterBuildStrategyPrototype) TestMe(f func(clusterBuildStrategy *buildv1beta1.ClusterBuildStrategy)) {
GinkgoHelper()
cbs, err := c.Create()
Expect(err).ToNot(HaveOccurred())


. "github.com/onsi/gomega"

meta "k8s.io/apimachinery/pkg/apis/meta/v1"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Super)Nit: Can we rename it metav1? I think this is the more widely used import name.

}
})

It("should fail for invvalid severities", func() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
It("should fail for invvalid severities", func() {
It("should fail for invalid severities", func() {

})

resources.UpdateBuildRunUsingTaskResults(ctx, br, tr.Status.Results, taskRunRequest)

Expect(br.Status.Output.Digest).To(Equal(imageDigest))
Expect(br.Status.Output.Size).To(Equal(int64(230)))
Expect(len(br.Status.Output.Vulnerabilities)).To(Equal(2))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I recently learned there is a Ginkgo/Gomega idiomatic way to write that (didn't check the syntax again, but I think it is like this):

Suggested change
Expect(len(br.Status.Output.Vulnerabilities)).To(Equal(2))
Expect(br.Status.Output.Vulnerabilities).To(HaveLen(2))

@qu1queee qu1queee added this to the release-v0.14.0 milestone May 2, 2024
@karanibm6 karanibm6 force-pushed the add-vulnerability-scanning branch from 6ddd690 to 313ea2d Compare May 5, 2024 15:19
"--vuln-count-limit", "10",
)).ToNot(HaveOccurred())
output := filecontent(filename)
Expect(strings.Contains(output, "CVE-2019-8457")).To(BeTrue())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will produce a better output in case substring is not found:

Suggested change
Expect(strings.Contains(output, "CVE-2019-8457")).To(BeTrue())
Expect(output).To(ContainSubstring("CVE-2019-8457"))

"--vuln-settings", vulnSettings.String(),
"--result-file-image-vulnerabilities", filename,
)).ToNot(HaveOccurred())
Expect(strings.Contains(filecontent(filename), "CVE-2019-8457")).To(BeTrue())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Expect(strings.Contains(filecontent(filename), "CVE-2019-8457")).To(BeTrue())
output := filecontent(filename)
Expect(output).To(ContainSubstring("CVE-2019-8457"))

"--vuln-settings", vulnSettings.String(),
"--result-file-image-vulnerabilities", filename,
)).To(HaveOccurred())
Expect(strings.Contains(filecontent(filename), "CVE-2019-8457")).To(BeTrue())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Expect(strings.Contains(filecontent(filename), "CVE-2019-8457")).To(BeTrue())
output := filecontent(filename)
Expect(output).To(ContainSubstring("CVE-2019-8457"))

})
})

It("should run vulnerability scanning on a image if it is already pushed by the strategy", func() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
It("should run vulnerability scanning on a image if it is already pushed by the strategy", func() {
It("should run vulnerability scanning on an image that is already pushed by the strategy", func() {

"--vuln-settings", vulnSettings.String(),
"--result-file-image-vulnerabilities", filename,
)).ToNot(HaveOccurred())
Expect(strings.Contains(filecontent(filename), "CVE-2019-12900")).To(BeTrue())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Expect(strings.Contains(filecontent(filename), "CVE-2019-12900")).To(BeTrue())
output := filecontent(filename)
Expect(output).To(ContainSubstring("CVE-2019-12900"))

@@ -103,6 +106,7 @@ type Config struct {
Controllers Controllers
KubeAPIOptions KubeAPIOptions
GitRewriteRule bool
VulnerabilityCountLimit string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a number. The error returned by SetConfigFromEnv will cause the controller to panic and that's the desired behavior for invalid values.

cmd := exec.CommandContext(ctx, "trivy", trivyArgs...)

// Print the command to be executed
log.Println(cmd.String())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would print the password, correct? If so, is a no-go.


if failedContainer.Name == "step-image-processing" && exitCode == 22 {
reason = buildv1beta1.BuildRunStateVulnerabilitiesFound
message = fmt.Sprintf("Vulnerabilities have been found in the image which can be seen in the buildrun status. For detailed information,see kubectl --namespace %s logs %s --container=%s",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will there be reasonable output in the container logs?

Copy link
Contributor Author

@karanibm6 karanibm6 May 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, just the vulnerabilities list. In case trivy command fails, it will print an error, but in that case exit code won't be 22.

Comment on lines 232 to 233
// Generate a pod with the status to be evicted
failedTaskRunEvictedPod := corev1.Pod{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls adjust

severityStr := *b.Build.Spec.Output.VulnerabilityScan.Ignore.Severity
if !isValidSeverity(severityStr) {
b.Build.Status.Reason = build.BuildReasonPtr(build.VulnerabilityScanSeverityNotValid)
b.Build.Status.Message = pointer.String("output vulnerability scan severity is invalid, must be a comma separated combination of these values: low | medium | high | critical")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Message is not correct.

- Add vulnerability scanning options in build and buildrun types in v1alpha1 and v1beta1
- Changes for conversion to v1beta1
@SaschaSchwarze0
Copy link
Member

Looks mostly good @karanibm6. I put a few small changes in karanibm6#37. Please check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API kind/feature Categorizes issue or PR as related to a new feature. release-note Label for when a PR has specified a release note size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

[FEATURE] Implement Build Output Vulnerability Scanning
6 participants