Skip to content

Commit

Permalink
feat: cyclonedx kbom support
Browse files Browse the repository at this point in the history
Signed-off-by: chenk <hen.keinan@gmail.com>
  • Loading branch information
chen-keinan committed Jun 5, 2023
1 parent d4acaf5 commit 38c2280
Show file tree
Hide file tree
Showing 6 changed files with 439 additions and 99 deletions.
2 changes: 1 addition & 1 deletion docs/docs/references/configuration/cli/trivy_kubernetes.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ trivy kubernetes [flags] { cluster | all | specific resources like kubectl. eg:
--exclude-nodes strings indicate the node labels that the node-collector job should exclude from scanning (example: kubernetes.io/arch:arm64,team:dev)
--exit-code int specify exit code when any security issues are found
--file-patterns strings specify config file patterns
-f, --format string format (table, json, template, sarif, cyclonedx, spdx, spdx-json, github, cosign-vuln) (default "table")
-f, --format string format (table, json, cyclonedx) (default "table")
--helm-set strings specify Helm values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--helm-set-file strings specify Helm values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)
--helm-set-string strings specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
Expand Down
10 changes: 0 additions & 10 deletions pkg/k8s/report/report_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package report

import (
"regexp"
"strings"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -575,11 +573,3 @@ func Test_separateMisconfigReports(t *testing.T) {
})
}
}

const ansi = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"

var ansiRegexp = regexp.MustCompile(ansi)

func stripAnsi(str string) string {
return strings.TrimSpace(ansiRegexp.ReplaceAllString(str, ""))
}
27 changes: 5 additions & 22 deletions pkg/k8s/scanner/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ func (s *Scanner) Scan(ctx context.Context, artifactsData []*artifacts.Artifact)
return report.Report{}, err
}
return report.Report{
SchemaVersion: 0,
RootComponent: rootComponent,
}, nil
} else {
Expand Down Expand Up @@ -217,8 +218,7 @@ func clusterInfoToReportResources(allArtifact []*artifacts.Artifact, clusterName
if err != nil {
return &core.Component{}, err
}
podComponents := flatComponents(podComp, nil)
coreComponents = append(coreComponents, podComponents...)
coreComponents = append(coreComponents, podComp)
case nodeInfo:
var nf bom.NodeInfo
err := ms.Decode(artifact.RawResource, &nf)
Expand Down Expand Up @@ -273,12 +273,12 @@ func clusterInfoToReportResources(allArtifact []*artifacts.Artifact, clusterName
"architecture": nf.Architecture,
}
m := cyclonedx.NewMarshaler("1.2")
nodeComponents, err := m.MarshalReport(nodeReport)
nodeComponent, err := m.MarshalReport(nodeReport)
if err != nil {
return nil, err
}
comp := flatComponents(nodeComponents, properties)
coreComponents = append(coreComponents, comp...)
nodeComponent.Properties = properties
coreComponents = append(coreComponents, nodeComponent)
default:
return nil, fmt.Errorf("resource kind %s is not supported", artifact.Kind)
}
Expand Down Expand Up @@ -319,20 +319,3 @@ func runtimeNameVersion(name string) (string, string) {
}
return "", ""
}

func flatComponents(component *core.Component, properties map[string]string) []*core.Component {
components := make([]*core.Component, 0)
components = append(components, &core.Component{
Type: component.Type,
Name: component.Name,
Version: component.Version,
PackageURL: component.PackageURL,
Licenses: component.Licenses,
Hashes: component.Hashes,
Supplier: component.Supplier,
Properties: properties,
Vulnerabilities: component.Vulnerabilities,
})
components = append(components, component.Components...)
return components
}
155 changes: 96 additions & 59 deletions pkg/k8s/scanner/scanner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ package scanner

import (
"context"
"encoding/json"
"fmt"
"testing"

cdx "github.com/CycloneDX/cyclonedx-go"
"github.com/aquasecurity/trivy-kubernetes/pkg/artifacts"
cmd "github.com/aquasecurity/trivy/pkg/commands/artifact"
"github.com/aquasecurity/trivy/pkg/digest"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/purl"
"github.com/package-url/packageurl-go"

"github.com/aquasecurity/trivy/pkg/flag"
"github.com/aquasecurity/trivy/pkg/k8s/report"
k8s "github.com/aquasecurity/trivy/pkg/k8s/report"
"github.com/aquasecurity/trivy/pkg/types"

"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx/core"

"github.com/stretchr/testify/assert"
)

Expand All @@ -23,7 +24,7 @@ func TestK8sClusterInfoReport(t *testing.T) {
name string
clusterName string
artifacts []*artifacts.Artifact
want report.Report
want *core.Component
}{
{
name: "test custer info with resources",
Expand Down Expand Up @@ -63,66 +64,106 @@ func TestK8sClusterInfoReport(t *testing.T) {
},
},
},
want: report.Report{
ClusterName: "test-cluster",
Resources: []k8s.Resource{
want: &core.Component{
Type: cdx.ComponentTypeContainer,
Name: "test-cluster",
Components: []*core.Component{
{
Kind: "PodInfo",
Type: cdx.ComponentTypeApplication,
Name: "kube-apiserver-kind-control-plane",
Report: types.Report{
ArtifactType: "k8s_pod",
ArtifactName: "kube-apiserver-kind-control-plane",
Metadata: types.Metadata{
RepoDigests: []string{},
},
Results: types.Results{
{
Target: "containers",
Type: "oci",
Class: types.ClassK8sComponents,
Packages: ftypes.Packages{
{
ID: "k8s.gcr.io/kube-apiserver:1.21.1",
Name: "k8s.gcr.io/kube-apiserver",
Version: "1.21.1",
Digest: digest.NewDigestFromString("sha256", "18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f"),
Properties: map[string]string{
"SchemaVersion": "0",
},
Components: []*core.Component{
{
Type: cdx.ComponentTypeContainer,
Name: "k8s.gcr.io/kube-apiserver",
Version: "sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f",
PackageURL: &purl.PackageURL{
packageurl.PackageURL{
Type: "oci",
Name: "kube-apiserver",
Version: "sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f",
Qualifiers: packageurl.Qualifiers{
{
Key: "repository_url",
Value: "k8s.gcr.io/kube-apiserver",
},
{
Key: "arch",
},
},
},
"",
},
Hashes: []digest.Digest{"sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f"},
Properties: map[string]string{
"PkgID": "k8s.gcr.io/kube-apiserver:1.21.1",
"PkgType": "oci",
},
},
},
},
{
Namespace: "",
Kind: "NodeInfo",
Name: "kind-control-plane",
Report: types.Report{
ArtifactType: "vm",
ArtifactName: "kind-control-plane",
Metadata: types.Metadata{
OS: &ftypes.OS{
Family: "ubuntu",
Name: "21.04",
Type: cdx.ComponentTypeContainer,
Name: "kind-control-plane",
Properties: map[string]string{
"architecture": "arm64",
"host_name": "kind-control-plane",
"kernel_version": "6.2.13-300.fc38.aarch64",
"node_role": "master",
"operating_system": "linux",
},
Components: []*core.Component{
{
Type: cdx.ComponentTypeOS,
Name: "ubuntu",
Version: "21.04",
Properties: map[string]string{
"Class": "os-pkgs",
"Type": "ubuntu",
},
},
Results: types.Results{
{
Target: "os-packages",
Class: types.ClassOSPkg,
Type: "ubuntu",
{
Type: cdx.ComponentTypeApplication,
Name: "node-core-components",
Properties: map[string]string{
"Class": "lang-pkgs",
"Type": "golang",
},
{
Target: "node-core-components",
Class: types.ClassLangPkg,
Type: "golang",
Packages: ftypes.Packages{
{
Name: "kubelet",
Version: "1.21.1",
Components: []*core.Component{
{
Type: cdx.ComponentTypeLibrary,
Name: "kubelet",
Version: "1.21.1",
Properties: map[string]string{
"PkgType": "golang",
},
PackageURL: &purl.PackageURL{
packageurl.PackageURL{
Type: "golang",
Name: "kubelet",
Version: "1.21.1",
Qualifiers: packageurl.Qualifiers{},
},
"",
},
},
{
Type: cdx.ComponentTypeLibrary,
Name: "containerd",
Version: "1.5.2",
Properties: map[string]string{
"PkgType": "golang",
},
{
Name: "containerd",
Version: "1.5.2",
PackageURL: &purl.PackageURL{
packageurl.PackageURL{
Type: "golang",
Name: "containerd",
Version: "1.5.2",
Qualifiers: packageurl.Qualifiers{},
},
"",
},
},
},
Expand All @@ -140,11 +181,7 @@ func TestK8sClusterInfoReport(t *testing.T) {
assert.NoError(t, err)
scanner := NewScanner(tt.clusterName, runner, flagOpts)
got, err := scanner.Scan(ctx, tt.artifacts)
assert.NoError(t, err)
b, err := json.Marshal(got)
assert.NoError(t, err)
fmt.Println(string(b))
// assert.Equal(t, tt.want, got)
assert.Equal(t, tt.want, got.RootComponent)
})
}
}
2 changes: 2 additions & 0 deletions pkg/sbom/cyclonedx/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ func (e *Marshaler) rootComponent(r types.Report) (*core.Component, error) {

case ftypes.ArtifactVM:
root.Type = cdx.ComponentTypeContainer
case ftypes.KubernetesPod:
root.Type = cdx.ComponentTypeApplication
case ftypes.ArtifactFilesystem, ftypes.ArtifactRemoteRepository:
root.Type = cdx.ComponentTypeApplication
}
Expand Down
Loading

0 comments on commit 38c2280

Please sign in to comment.