Skip to content

Commit

Permalink
WIP: add vulnerability scan upload sbom to minio (#733)
Browse files Browse the repository at this point in the history
  • Loading branch information
gnmahanth committed Dec 23, 2022
1 parent 2f39d45 commit 2407d41
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 255 deletions.
23 changes: 0 additions & 23 deletions deepfence_agent/tools/apache/fluentbit/td-agent-bit.conf
Original file line number Diff line number Diff line change
Expand Up @@ -81,29 +81,6 @@
#
storage.backlog.mem_limit 5M

[INPUT]
Name tail
Path ${DF_INSTALL_DIR}/var/log/fenced/vulnerability-scan/*.log
Tag vulnerability-scan
storage.type filesystem
Buffer_Chunk_Size 4K
Mem_Buf_Limit 5MB
Refresh_Interval 10
Skip_Long_Lines On
DB ${DF_INSTALL_DIR}/home/deepfence/fluentbit/vulnerability-scan.db
Parser json

[INPUT]
Name tail
Path ${DF_INSTALL_DIR}/var/log/fenced/vulnerability-scan-log/*.log
Tag vulnerability-scan-log
storage.type filesystem
Buffer_Chunk_Size 4K
Mem_Buf_Limit 5MB
Refresh_Interval 10
Skip_Long_Lines On
DB ${DF_INSTALL_DIR}/home/deepfence/fluentbit/vulnerability-scan-scan.db
Parser json

[INPUT]
Name tail
Expand Down
282 changes: 52 additions & 230 deletions deepfence_agent/tools/apache/scope/probe/host/generate_sbom.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,109 +2,48 @@ package host

import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"

"github.com/Jeffail/tunny"
ctl "github.com/deepfence/ThreatMapper/deepfence_utils/controls"
log "github.com/sirupsen/logrus"
scopeHostname "github.com/weaveworks/scope/common/hostname"
pb "github.com/weaveworks/scope/proto"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)

const (
packageScannerSocket = "/tmp/package-scanner.sock"
defaultVulnerabilityScanConcurrency = 5
packageScannerSocket = "/tmp/package-scanner.sock"
)

var (
scanPath = "dir:/fenced/mnt/host/"
grpcVulnScanWorkerPool *tunny.Pool
vulnerabilityScanFile = getDfInstallDir() + "/var/log/fenced/vulnerability-scan/vulnerability_scan.log"
vulnerabilityScanStatusFile = getDfInstallDir() + "/var/log/fenced/vulnerability-scan-log/vulnerability_scan_log.log"
scanPath = "dir:/fenced/mnt/host/"
)

type vulnScanParameters struct {
client pb.PackageScannerClient
req *pb.SBOMRequest
controlArgs map[string]string
hostName string
}

func init() {
os.MkdirAll(filepath.Dir(vulnerabilityScanFile), 0755)
os.MkdirAll(filepath.Dir(vulnerabilityScanStatusFile), 0755)
var err error
scanConcurrency, err = strconv.Atoi(os.Getenv("VULNERABILITY_SCAN_CONCURRENCY"))
if err != nil {
scanConcurrency = defaultVulnerabilityScanConcurrency
}
grpcVulnScanWorkerPool = tunny.NewFunc(scanConcurrency,
getAndPublishVulnerabilityScanResultsWrapper)
mgmtConsoleUrl = os.Getenv("MGMT_CONSOLE_URL")
consolePort := os.Getenv("MGMT_CONSOLE_PORT")
if consolePort != "" && consolePort != "443" {
mgmtConsoleUrl += ":" + consolePort
}
deepfenceKey = os.Getenv("DEEPFENCE_KEY")
if os.Getenv("DF_SERVERLESS") == "true" {
certPath = "/deepfence/etc/filebeat/filebeat.crt"
scanDir = "/"
} else {
scanDir = HostMountDir
scanPath = "dir:/"
}
}

func createPackageScannerClient() (pb.PackageScannerClient, error) {
maxMsgSize := 1024 * 1024 * 1 // 1 mb
conn, err := grpc.Dial("unix://"+packageScannerSocket,
conn, err := grpc.Dial(
"unix://"+packageScannerSocket,
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMsgSize)),
grpc.WithAuthority("dummy"), grpc.WithInsecure())
grpc.WithAuthority("dummy"),
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
return nil, err
}
return pb.NewPackageScannerClient(conn), nil
}

func generateSbomRequest(req ctl.StartVulnerabilityScanRequest) (*pb.SBOMRequest, error) {
var imageName = "host"
var imageId = ""
var scanId = ""
var kubernetesClusterName = ""
var containerName = ""
var containerId = ""

if imageNameArg, ok := req.BinArgs["image_name"]; ok {
imageName = imageNameArg
}
if containerNameArg, ok := req.BinArgs["container_name"]; ok {
containerName = containerNameArg
}
if kubernetesClusterNameArg, ok := req.BinArgs["kubernetes_cluster_name"]; ok {
kubernetesClusterName = kubernetesClusterNameArg
}
if imageIdArg, ok := req.BinArgs["image_id"]; ok {
imageId = imageIdArg
}
if containerIdArg, ok := req.BinArgs["container_id"]; ok {
containerId = containerIdArg
}
if imageName != "host" && imageId == "" {
return nil, errors.New("image_id is required for container/image vulnerability scan")
}
scanType := "all"
if scanTypeArg, ok := req.BinArgs["scan_type"]; ok {
scanType = scanTypeArg
}
if scanIdArg, ok := req.BinArgs["scan_id"]; ok {
scanId = scanIdArg
}
func GenerateSbomForVulnerabilityScan(imageName, imageId, scanId, containerId,
kubernetesClusterName, containerName, scanType string) error {
ctx := context.Background()

hostName := scopeHostname.Get()
var nodeType string
Expand All @@ -115,14 +54,16 @@ func generateSbomRequest(req ctl.StartVulnerabilityScanRequest) (*pb.SBOMRequest
} else {
nodeType = "container_image"
}

packageScannerClient, err := createPackageScannerClient()
if err != nil {
return err
}
var source string
if imageName == "host" {
source = scanPath
} else {
source = imageName
}

sbomRequest := &pb.SBOMRequest{
Source: source,
ScanType: scanType,
Expand All @@ -135,175 +76,56 @@ func generateSbomRequest(req ctl.StartVulnerabilityScanRequest) (*pb.SBOMRequest
RegistryId: "",
ContainerId: containerId,
}
return sbomRequest, nil
}

func StartVulnerabilityScan(req ctl.StartVulnerabilityScanRequest) error {

sbomRequest, err := generateSbomRequest(req)
if err != nil {
return err
}

packageScannerClient, err := createPackageScannerClient()
_, err = packageScannerClient.GenerateSBOM(ctx, sbomRequest)
if err != nil {
return err
}
go grpcVulnScanWorkerPool.Process(vulnScanParameters{
client: packageScannerClient,
req: sbomRequest,
controlArgs: req.BinArgs,
hostName: req.Hostname,
})
return nil
}

func getAndPublishVulnerabilityScanResultsWrapper(scanParametersInterface interface{}) interface{} {
scanParameters, ok := scanParametersInterface.(vulnScanParameters)
if !ok {
fmt.Println("Error reading input from grpc API")
return nil
}
getAndPublishVulnerabilityScanResults(scanParameters.client, scanParameters.req,
scanParameters.controlArgs, scanParameters.hostName)
return nil
}

func getAndPublishVulnerabilityScanResults(client pb.PackageScannerClient, req *pb.SBOMRequest,
controlArgs map[string]string, hostName string) {
var scanLog = make(map[string]interface{})
scanLog["node_id"] = controlArgs["node_id"]
scanLog["node_type"] = controlArgs["node_type"]
scanLog["node_name"] = hostName
scanLog["container_name"] = controlArgs["container_name"]
scanLog["kubernetes_cluster_name"] = controlArgs["kubernetes_cluster_name"]
scanLog["host_name"] = hostName
scanLog["scan_id"] = controlArgs["scan_id"]
scanLog["masked"] = "false"
scanLog["scan_status"] = "IN_PROGRESS"
scanLog["time_stamp"] = getTimestamp()
scanLog["@timestamp"] = getCurrentTime()

byteJson, err := json.Marshal(scanLog)
if err != nil {
log.Errorf("err marshalling json: %s", err)
return
}

err = writeToFile(string(byteJson), vulnerabilityScanStatusFile)
if err != nil {
log.Errorf("error in sending data to mark in progress: %s" + err.Error())
}

res, err := client.GenerateSBOM(context.Background(), req)
if err != nil {
scanLog["scan_status"] = "ERROR"
scanLog["scan_message"] = err.Error()
scanLog["time_stamp"] = getTimestamp()
scanLog["@timestamp"] = getCurrentTime()
byteJson, err = json.Marshal(scanLog)
if err != nil {
log.Errorf("error marshalling json: %s", err)
return
}
writeToFile(string(byteJson), vulnerabilityScanStatusFile)
return
}
func StartVulnerabilityScan(req ctl.StartVulnerabilityScanRequest) error {
var (
imageName = "host"
imageId = ""
scanId = ""
kubernetesClusterName = ""
containerName = ""
containerId = ""
scanType = "all"
)

sbom, err := os.ReadFile(res.GetSbomPath())
if err != nil {
scanLog["scan_status"] = "ERROR"
scanLog["scan_message"] = err.Error()
scanLog["time_stamp"] = getTimestamp()
scanLog["@timestamp"] = getCurrentTime()
byteJson, err = json.Marshal(scanLog)
if err != nil {
log.Errorf("error marshalling json: %s", err)
return
}
writeToFile(string(byteJson), vulnerabilityScanStatusFile)
return
if imageNameArg, ok := req.BinArgs["image_name"]; ok {
imageName = imageNameArg
}
defer os.Remove(res.GetSbomPath())

sbomData := make(map[string]interface{})
if err := json.Unmarshal(sbom, &sbomData); err != nil {
scanLog["scan_status"] = "ERROR"
scanLog["scan_message"] = err.Error()
scanLog["time_stamp"] = getTimestamp()
scanLog["@timestamp"] = getCurrentTime()
byteJson, err = json.Marshal(scanLog)
if err != nil {
log.Errorf("error marshalling json: %s", err)
return
}
writeScanDataToFile(string(byteJson), vulnerabilityScanStatusFile)
return
if containerNameArg, ok := req.BinArgs["container_name"]; ok {
containerName = containerNameArg
}

var scanDoc = make(map[string]interface{})
scanDoc["node_id"] = controlArgs["node_id"]
scanDoc["node_type"] = controlArgs["node_type"]
scanDoc["node_name"] = hostName
scanDoc["host_name"] = hostName
scanDoc["scan_id"] = controlArgs["scan_id"]
scanDoc["container_name"] = controlArgs["container_name"]
scanDoc["kubernetes_cluster_name"] = controlArgs["kubernetes_cluster_name"]
scanDoc["sbom"] = sbomData
byteJson, err = json.Marshal(scanDoc)
if err != nil {
scanLog["scan_status"] = "ERROR"
scanLog["scan_message"] = err.Error()
scanLog["time_stamp"] = getTimestamp()
scanLog["@timestamp"] = getCurrentTime()
byteJson, err = json.Marshal(scanLog)
if err != nil {
log.Errorf("error marshalling json: %s", err)
return
}
writeToFile(string(byteJson), vulnerabilityScanStatusFile)
return
if kubernetesClusterNameArg, ok := req.BinArgs["kubernetes_cluster_name"]; ok {
kubernetesClusterName = kubernetesClusterNameArg
}
err = writeToFile(string(byteJson), vulnerabilityScanFile)
if err != nil {
scanLog["scan_status"] = "ERROR"
scanLog["scan_message"] = err.Error()
scanLog["time_stamp"] = getTimestamp()
scanLog["@timestamp"] = getCurrentTime()
byteJson, err = json.Marshal(scanLog)
if err != nil {
log.Errorf("error marshalling json: %s", err)
return
}
writeToFile(string(byteJson), vulnerabilityScanStatusFile)
return
if imageIdArg, ok := req.BinArgs["image_id"]; ok {
imageId = imageIdArg
}

scanLog["scan_status"] = "COMPLETE"
scanLog["time_stamp"] = getTimestamp()
scanLog["@timestamp"] = getCurrentTime()
byteJson, err = json.Marshal(scanLog)
if err != nil {
log.Errorf("error marshalling json: %s", err)
return
if containerIdArg, ok := req.BinArgs["container_id"]; ok {
containerId = containerIdArg
}
err = writeToFile(string(byteJson), vulnerabilityScanStatusFile)
if err != nil {
log.Errorf("error in sending data %s", err.Error())
if imageName != "host" && imageId == "" {
return errors.New("image_id is required for container/image vulnerability scan")
}

}

func writeToFile(msg string, filename string) error {
out, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
return err
if scanTypeArg, ok := req.BinArgs["scan_type"]; ok {
scanType = scanTypeArg
}
defer out.Close()

_, err = out.WriteString(strings.Replace(msg, "\n", " ", -1) + "\n")
if err != nil {
return err
if scanIdArg, ok := req.BinArgs["scan_id"]; ok {
scanId = scanIdArg
}
log.Infof("uploading %s tar to console...", imageName)
// call package scanner plugin
go func() {
err := GenerateSbomForVulnerabilityScan(imageName, imageId, scanId,
containerId, kubernetesClusterName, containerName, scanType)
if err != nil {
log.Error(err.Error())
}
}()
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func StartSecretsScan(req ctl.StartSecretScanRequest) error {
case ctl.Image:
splits := strings.Split(req.ResourceId, ";")
if len(splits) != 2 {
return errors.New("Image id format is incorrect")
return errors.New("image id format is incorrect")
}
greq = pb.FindRequest{Input: &pb.FindRequest_Image{
Image: &pb.DockerImage{Id: splits[0], Name: splits[1]},
Expand Down
Loading

0 comments on commit 2407d41

Please sign in to comment.