Skip to content

Commit

Permalink
sbom-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
an1l4 committed Mar 1, 2024
1 parent 0180b1b commit c76e68e
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 62 deletions.
124 changes: 91 additions & 33 deletions agent/kubviz/plugins/trivy/trivy_sbom.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,21 @@ import (
"log"
"os"
"os/exec"
"strings"

"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx"
"github.com/google/uuid"
"github.com/intelops/kubviz/agent/kubviz/plugins/outdated"
"github.com/intelops/kubviz/constants"
"github.com/intelops/kubviz/model"
"github.com/intelops/kubviz/pkg/opentelemetry"
"github.com/nats-io/nats.go"
"github.com/pkg/errors"
"go.opentelemetry.io/otel"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)

func PublishTrivySbomReport(report cyclonedx.BOM, js nats.JetStreamContext) error {
func PublishTrivySbomReport(report map[string]interface{}, js nats.JetStreamContext) error {

// opentelemetry
opentelconfig, err := opentelemetry.GetConfigurations()
Expand All @@ -34,32 +36,23 @@ func PublishTrivySbomReport(report cyclonedx.BOM, js nats.JetStreamContext) erro
defer span.End()
}

for _, packageinfo := range report.Packages {
for _, pkg := range packageinfo.Packages {

metrics := model.SbomData{
ID: uuid.New().String(),
ClusterName: ClusterName,
ComponentName: report.CycloneDX.Metadata.Component.Name,
PackageName: pkg.Name,
PackageUrl: report.CycloneDX.Metadata.Component.PackageURL,
BomRef: report.CycloneDX.Metadata.Component.BOMRef,
SerialNumber: report.CycloneDX.SerialNumber,
CycloneDxVersion: report.CycloneDX.Version,
BomFormat: report.CycloneDX.BOMFormat,
}
metricsJson, err := json.Marshal(metrics)
if err != nil {
log.Println("error occurred while marshalling sbom metrics in agent", err.Error())
return err
}
_, err = js.Publish(constants.TRIVY_SBOM_SUBJECT, metricsJson)
if err != nil {
return err
}
log.Printf("Trivy sbom report with Id %v has been published\n", metrics.ID)
}
metrics := model.Sbom{
ID: uuid.New().String(),
ClusterName: ClusterName,
Report: report,
}
metricsJson, err := json.Marshal(metrics)
if err != nil {
log.Println("error occurred while marshalling sbom metrics in agent", err.Error())
return err
}
_, err = js.Publish(constants.TRIVY_SBOM_SUBJECT, metricsJson)
if err != nil {
return err
}
log.Printf("Trivy sbom report with Id %v has been published\n", metrics.ID)
log.Printf("Trivy sbom report with Id %v has been published\n", metrics)

return nil
}

Expand Down Expand Up @@ -98,13 +91,12 @@ func RunTrivySbomScan(config *rest.Config, js nats.JetStreamContext) error {
defer span.End()
}

images, err := outdated.ListImages(config)

images, err := ListImagesForSbom(config)
if err != nil {
log.Printf("failed to list images: %v", err)
}
for _, image := range images {

for _, image := range images {
sbomcmd := fmt.Sprintf("trivy image --format cyclonedx %s --cache-dir %s", image.PullableImage, trivySbomCacheDir)
out, err := executeCommandSbom(sbomcmd)

Expand All @@ -122,13 +114,79 @@ func RunTrivySbomScan(config *rest.Config, js nats.JetStreamContext) error {
continue // Move on to the next image
}

var report cyclonedx.BOM
var report map[string]interface{}
err = json.Unmarshal(out, &report)
if err != nil {
log.Printf("Error unmarshaling JSON data for image sbom %s: %v", image.PullableImage, err)
continue // Move on to the next image in case of an error
}
PublishTrivySbomReport(report, js)
err = PublishTrivySbomReport(report, js)
if err != nil {
log.Printf("Error publishing Trivy SBOM report for image %s: %v", image.PullableImage, err)
continue
}
}
return nil
}

func ListImagesForSbom(config *rest.Config) ([]model.RunningImage, error) {
var err error
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, errors.Wrap(err, "failed to create clientset")
}
ctx := context.Background()
namespaces, err := clientset.CoreV1().Namespaces().List(ctx, metav1.ListOptions{})
if err != nil {
return nil, errors.Wrap(err, "failed to list namespaces")
}

runningImages := []model.RunningImage{}
for _, namespace := range namespaces.Items {
pods, err := clientset.CoreV1().Pods(namespace.Name).List(ctx, metav1.ListOptions{})
if err != nil {
return nil, errors.Wrap(err, "failed to list pods")
}

for _, pod := range pods.Items {
for _, initContainerStatus := range pod.Status.InitContainerStatuses {
pullable := initContainerStatus.ImageID
pullable = strings.TrimPrefix(pullable, "docker-pullable://")
runningImage := model.RunningImage{
Pod: pod.Name,
Namespace: pod.Namespace,
InitContainer: &initContainerStatus.Name,
Image: initContainerStatus.Image,
PullableImage: pullable,
}
runningImages = append(runningImages, runningImage)
}

for _, containerStatus := range pod.Status.ContainerStatuses {
pullable := containerStatus.ImageID
pullable = strings.TrimPrefix(pullable, "docker-pullable://")

runningImage := model.RunningImage{
Pod: pod.Name,
Namespace: pod.Namespace,
Container: &containerStatus.Name,
Image: containerStatus.Image,
PullableImage: pullable,
}
runningImages = append(runningImages, runningImage)
}
}
}

// Remove exact duplicates
cleanedImages := []model.RunningImage{}
seenImages := make(map[string]bool)
for _, runningImage := range runningImages {
if !seenImages[runningImage.PullableImage] {
cleanedImages = append(cleanedImages, runningImage)
seenImages[runningImage.PullableImage] = true
}
}

return cleanedImages, nil
}
57 changes: 48 additions & 9 deletions client/pkg/clickhouse/db_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type DBInterface interface {
InsertGitEvent(string)
InsertKubeScoreMetrics(model.KubeScoreRecommendations)
InsertTrivyImageMetrics(metrics model.TrivyImage)
InsertTrivySbomMetrics(metrics model.SbomData)
InsertTrivySbomMetrics(metrics model.Sbom)
InsertTrivyMetrics(metrics model.Trivy)
RetriveKetallEvent() ([]model.Resource, error)
RetriveOutdatedEvent() ([]model.CheckResultfinal, error)
Expand Down Expand Up @@ -922,7 +922,7 @@ func (c *DBClient) InsertTrivyImageMetrics(metrics model.TrivyImage) {

}
}
func (c *DBClient) InsertTrivySbomMetrics(metrics model.SbomData) {
func (c *DBClient) InsertTrivySbomMetrics(metrics model.Sbom) {
//opentelemetry
opentelconfig, err := opentelemetry.GetConfigurations()
if err != nil {
Expand All @@ -944,16 +944,55 @@ func (c *DBClient) InsertTrivySbomMetrics(metrics model.SbomData) {
log.Fatalf("error preparing statement: %v", err)
}

data := metrics.Report
bomComponents, ok := data["components"].([]interface{})
if !ok {
log.Println("error: components not found or not in expected format")
}
var componentName, bomRef, serialNumber, bomFormat, purl, componentType string
var version int32
// Iterate over the components to find the desired name
for _, component := range bomComponents {
componentMap, ok := component.(map[string]interface{})
if !ok {
log.Println("error: component not in expected format")
continue
}
if name, ok := componentMap["name"].(string); ok {
componentName = name
break
}
}
metadata, ok := data["metadata"].(map[string]interface{})
if !ok {
log.Println("error: metadata not found or not in expected format")
return
}

component, ok := metadata["component"].(map[string]interface{})
if !ok {
log.Println("error: component not found or not in expected format")
return
}

bomRef, _ = component["bom-ref"].(string)
purl, _ = component["purl"].(string)
componentType, _ = component["type"].(string)

serialNumber, _ = data["serialNumber"].(string)
version, _ = data["version"].(int32)
bomFormat, _ = data["bomFormat"].(string)

if _, err := stmt.Exec(
metrics.ID,
metrics.ClusterName,
metrics.ComponentName,
metrics.PackageName,
metrics.PackageUrl,
metrics.BomRef,
metrics.SerialNumber,
int32(metrics.CycloneDxVersion),
metrics.BomFormat,
componentName,
componentType,
purl,
bomRef,
serialNumber,
int32(version),
bomFormat,
); err != nil {
log.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion client/pkg/clients/kubviz_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func (n *NATSContext) SubscribeAllKubvizNats(conn clickhouse.DBInterface) {
Consumer: cfg.TrivySbomConsumer,
Handler: func(msg *nats.Msg) {
msg.Ack()
var metrics model.SbomData
var metrics model.Sbom
err := json.Unmarshal(msg.Data, &metrics)
if err != nil {
log.Println("failed to unmarshal from nats", err)
Expand Down
21 changes: 2 additions & 19 deletions model/trivy_sbom.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,7 @@
package model

import (
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx"
)

type Sbom struct {
ID string
Report cyclonedx.BOM
}

type SbomData struct {
ID string
ID string
ClusterName string
ComponentName string
PackageName string
PackageUrl string
BomRef string
SerialNumber string
CycloneDxVersion int
BomFormat string
Report map[string]interface{}
}


0 comments on commit c76e68e

Please sign in to comment.