diff --git a/deepfence_agent/plugins/SecretScanner b/deepfence_agent/plugins/SecretScanner index 34a3d679a7..1c949b17b3 160000 --- a/deepfence_agent/plugins/SecretScanner +++ b/deepfence_agent/plugins/SecretScanner @@ -1 +1 @@ -Subproject commit 34a3d679a7d78f3747dd7328487994895026f3ce +Subproject commit 1c949b17b3e2e40d0dadbb4faf83000092314528 diff --git a/deepfence_agent/plugins/cloud-scanner b/deepfence_agent/plugins/cloud-scanner index 89ebb301ee..c25aedcfdb 160000 --- a/deepfence_agent/plugins/cloud-scanner +++ b/deepfence_agent/plugins/cloud-scanner @@ -1 +1 @@ -Subproject commit 89ebb301ee47b5c4407359460437f395bff67b06 +Subproject commit c25aedcfdbc09a9deae9f40cdea9367a6b6ca658 diff --git a/deepfence_agent/plugins/package-scanner b/deepfence_agent/plugins/package-scanner index 8a52ca4950..0de7189a74 160000 --- a/deepfence_agent/plugins/package-scanner +++ b/deepfence_agent/plugins/package-scanner @@ -1 +1 @@ -Subproject commit 8a52ca4950d0d8670c872af2985c5a53f7530f19 +Subproject commit 0de7189a7425b30dce4961e4ba6745932dbcbf4d diff --git a/deepfence_agent/plugins/yara-rules b/deepfence_agent/plugins/yara-rules index 5f09216537..8217b51893 160000 --- a/deepfence_agent/plugins/yara-rules +++ b/deepfence_agent/plugins/yara-rules @@ -1 +1 @@ -Subproject commit 5f09216537d46a27019420c06b8c8181f26cb347 +Subproject commit 8217b518934b556ee7f56e6e5fc3e05be8c8d9fa diff --git a/deepfence_server/handler/scan_reports.go b/deepfence_server/handler/scan_reports.go index 071c4cb4d5..84cf52ecca 100644 --- a/deepfence_server/handler/scan_reports.go +++ b/deepfence_server/handler/scan_reports.go @@ -260,6 +260,32 @@ func (h *Handler) StartVulnerabilityScanHandler(w http.ResponseWriter, r *http.R return } + scanTrigger := model.ScanTriggerCommon{} + for _, v := range reqs.ScanTriggerCommon.NodeIDs { + if v.NodeType == "container" { + imageID, err := GetImageFromContainerID(r.Context(), v.NodeID) + if err != nil { + log.Error().Err(err).Msg("Cannot start image scan for container") + continue + } + scanTrigger.NodeIDs = append(scanTrigger.NodeIDs, model.NodeIdentifier{ + NodeID: imageID, + NodeType: "image", + }) + } + } + + _, _, err = StartMultiScan(r.Context(), true, utils.NEO4JVulnerabilityScan, scanTrigger, actionBuilder) + if err != nil { + if err.Error() == "Result contains no more records" { + h.respondError(&noNodesMatchedInNeo4jError, w) + return + } + log.Error().Msgf("%v", err) + h.respondError(err, w) + return + } + h.AuditUserActivity(r, EventVulnerabilityScan, ActionStart, reqs, true) err = httpext.JSON(w, http.StatusAccepted, model.ScanTriggerResp{ScanIds: scanIDs, BulkScanID: bulkID}) @@ -400,6 +426,32 @@ func (h *Handler) StartSecretScanHandler(w http.ResponseWriter, r *http.Request) return } + scanTrigger := model.ScanTriggerCommon{} + for _, v := range reqs.ScanTriggerCommon.NodeIDs { + if v.NodeType == "container" { + imageID, err := GetImageFromContainerID(r.Context(), v.NodeID) + if err != nil { + log.Error().Err(err).Msg("Cannot start image scan for container") + continue + } + scanTrigger.NodeIDs = append(scanTrigger.NodeIDs, model.NodeIdentifier{ + NodeID: imageID, + NodeType: "image", + }) + } + } + + _, _, err = StartMultiScan(r.Context(), true, utils.NEO4JSecretScan, scanTrigger, actionBuilder) + if err != nil { + if err.Error() == "Result contains no more records" { + h.respondError(&noNodesMatchedInNeo4jError, w) + return + } + log.Error().Msgf("%v", err) + h.respondError(err, w) + return + } + h.AuditUserActivity(r, EventSecretScan, ActionStart, reqs, true) err = httpext.JSON(w, http.StatusAccepted, model.ScanTriggerResp{ScanIds: scanIDs, BulkScanID: bulkID}) @@ -520,6 +572,32 @@ func (h *Handler) StartMalwareScanHandler(w http.ResponseWriter, r *http.Request return } + scanTrigger := model.ScanTriggerCommon{} + for _, v := range reqs.ScanTriggerCommon.NodeIDs { + if v.NodeType == "container" { + imageID, err := GetImageFromContainerID(r.Context(), v.NodeID) + if err != nil { + log.Error().Err(err).Msg("Cannot start image scan for container") + continue + } + scanTrigger.NodeIDs = append(scanTrigger.NodeIDs, model.NodeIdentifier{ + NodeID: imageID, + NodeType: "image", + }) + } + } + + _, _, err = StartMultiScan(r.Context(), true, utils.NEO4JMalwareScan, scanTrigger, actionBuilder) + if err != nil { + if err.Error() == "Result contains no more records" { + h.respondError(&noNodesMatchedInNeo4jError, w) + return + } + log.Error().Msgf("%v", err) + h.respondError(err, w) + return + } + h.AuditUserActivity(r, EventMalwareScan, ActionStart, reqs, true) err = httpext.JSON(w, http.StatusAccepted, model.ScanTriggerResp{ScanIds: scanIDs, BulkScanID: bulkID}) @@ -2520,3 +2598,44 @@ func (h *Handler) rulesActionHandler(w http.ResponseWriter, r *http.Request, act } w.WriteHeader(http.StatusNoContent) } + +func GetImageFromContainerID(ctx context.Context, nodeID string) (string, error) { + + ctx, span := telemetry.NewSpan(ctx, "scan-reports", "get-image-from-container-id") + defer span.End() + + var name string + + driver, err := directory.Neo4jClient(ctx) + if err != nil { + return name, err + } + + session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) + defer session.Close(ctx) + + tx, err := session.BeginTransaction(ctx, neo4j.WithTxTimeout(30*time.Second)) + if err != nil { + return name, err + } + defer tx.Close(ctx) + + res, err := tx.Run(ctx, ` + MATCH (n:Container{node_id:$node_id}) + RETURN n.docker_image_id`, + map[string]interface{}{"node_id": nodeID}) + if err != nil { + return name, err + } + + rec, err := res.Single(ctx) + if err != nil { + return name, err + } + + if vi, ok := rec.Get("n.docker_image_id"); ok && vi != nil { + name = vi.(string) + } + + return name, nil +} diff --git a/deepfence_worker/cronjobs/neo4j.go b/deepfence_worker/cronjobs/neo4j.go index ce8479950a..d3c3968876 100644 --- a/deepfence_worker/cronjobs/neo4j.go +++ b/deepfence_worker/cronjobs/neo4j.go @@ -846,6 +846,39 @@ func LinkNodes(ctx context.Context, task *asynq.Task) error { return err } + for _, scanType := range []utils.Neo4jScanType{ + utils.NEO4JVulnerabilityScan, + utils.NEO4JSecretScan, + utils.NEO4JMalwareScan } { + scanNode := string(scanType) + statusField := ingestersUtil.ScanStatusField[scanType] + latestField := ingestersUtil.LatestScanIDField[scanType] + countField := ingestersUtil.ScanCountField[scanType] + if _, err = session.Run(ctx, ` + MATCH (n:Container) + WHERE NOT EXISTS((n)<-[:SCANNED]-(:`+scanNode+`)) + MATCH (i:ContainerImage{node_id:n.docker_image_id}) + MATCH (i) -[:SCANNED]- (s:`+scanNode+`) + WITH max(s.updated_at) as latest, s, n + MATCH (s) -[r:DETECTED]- (v) + MERGE (news:`+scanNode+`{node_id:n.node_id+"-"+toString(TIMESTAMP())}) + MERGE (news)-[:DETECTED{masked:r.masked}]-> (v) + MERGE (n) <-[:SCANNED]- (news) + WITH n, news, s, count(v) as cnt + SET news.status = s.status, + news.updated_at = TIMESTAMP(), + news.created_at = s.created_at, + news.is_priority = s.is_priority, + news.retries = s.retries, + news.status_message = s.status_message, + n.`+statusField+` = s.status, + n.`+latestField+` = news.node_id, + n.`+countField+` = cnt`, + map[string]interface{}{}, txConfig); err != nil { + return err + } + } + log.Debug().Msgf("Link Nodes task took: %v", time.Since(start)) return nil diff --git a/golang_deepfence_sdk b/golang_deepfence_sdk index 4943c14781..226fd1e1e6 160000 --- a/golang_deepfence_sdk +++ b/golang_deepfence_sdk @@ -1 +1 @@ -Subproject commit 4943c14781c54befc03e4011650a369de6926137 +Subproject commit 226fd1e1e6bb7b9f4e179d6f738bb7cd9c55dd72