From b42b7d49fd2c3f31631310a782505a1adaa9eefd Mon Sep 17 00:00:00 2001 From: Piotr Rygielski <114479+vikin91@users.noreply.github.com> Date: Wed, 16 Nov 2022 17:02:31 +0100 Subject: [PATCH 01/14] X-Smart-Branch-Parent: master Experiment with calls to Analyze --- .../nodescanv2/fake_nodescan_test.go | 23 ++++++++ compliance/collection/nodescanv2/nodescan.go | 58 ++++++++++++++++++- 2 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 compliance/collection/nodescanv2/fake_nodescan_test.go diff --git a/compliance/collection/nodescanv2/fake_nodescan_test.go b/compliance/collection/nodescanv2/fake_nodescan_test.go new file mode 100644 index 0000000000000..4c21514d284f9 --- /dev/null +++ b/compliance/collection/nodescanv2/fake_nodescan_test.go @@ -0,0 +1,23 @@ +package nodescanv2 + +import ( + "testing" + + "github.com/stackrox/rox/generated/storage" + "github.com/stretchr/testify/suite" +) + +func TestFakeNodeScan(t *testing.T) { + suite.Run(t, &NodeScanSuite{}) +} + +type FakeNodeScanSuite struct { + suite.Suite +} + +func (n *FakeNodeScanSuite) TestMessageFormat() { + fns, err := (&FakeNodeScanner{}).Scan("someNode") + n.Nil(err) + n.NotNil(fns) + n.IsType(&storage.NodeScanV2{}, fns) +} diff --git a/compliance/collection/nodescanv2/nodescan.go b/compliance/collection/nodescanv2/nodescan.go index 3885873680b96..8f311d2775688 100644 --- a/compliance/collection/nodescanv2/nodescan.go +++ b/compliance/collection/nodescanv2/nodescan.go @@ -1,8 +1,11 @@ package nodescanv2 import ( - "github.com/pkg/errors" + timestamp "github.com/gogo/protobuf/types" "github.com/stackrox/rox/generated/storage" + "github.com/stackrox/scanner/database" + scannerV1 "github.com/stackrox/scanner/generated/scanner/api/v1" + "github.com/stackrox/scanner/pkg/analyzer/nodes" ) // NodeScanner defines an interface for V2 NodeScanning @@ -14,7 +17,56 @@ type NodeScanner interface { type NodeScan struct { } -// Scan scans the current node and returns the results as storage.NodeInventory object +// Scan scans the current node and returns the results as storage.NodeScanV2 object func (n *NodeScan) Scan(nodeName string) (*storage.NodeInventory, error) { - return nil, errors.New("Not implemented") + componentsHost, err := nodes.Analyze(nodeName, "/host/", false) + log.Info("Finished node inventory /host scan") + if err != nil { + log.Errorf("Error scanning node /host inventory: %v", err) + } + log.Infof("Components found under /host: %v", componentsHost) + if err != nil { + return nil, err + } + + protoComponents := protoComponentsFromScanComponents(componentsHost) + m := &storage.NodeInventory{ + NodeName: nodeName, + ScanTime: timestamp.TimestampNow(), + Components: protoComponents, + } + return m, nil +} + +func protoComponentsFromScanComponents(c *nodes.Components) *scannerV1.Components { + // For now, we only care about RHEL components, but this must be extended once we support non-RHCOS + pc := scannerV1.Components{ + Namespace: c.OSNamespace.Name, + OsComponents: nil, + RhelComponents: convertRHELComponents(c.CertifiedRHELComponents), + LanguageComponents: nil, + } + return &pc +} + +func convertRHELComponents(rc *database.RHELv2Components) []*scannerV1.RHELComponent { + v1rhelc := make([]*scannerV1.RHELComponent, 0) + if rc.Packages == nil { + log.Warn("No RHEL packages found in scan result") + return nil + } + for _, rhelc := range rc.Packages { + v1rhelc = append(v1rhelc, &scannerV1.RHELComponent{ + Id: 0, + Name: rhelc.Name, + Namespace: rc.Dist, // check + Version: rhelc.Version, + Arch: rhelc.Arch, + Module: rhelc.Module, + Cpes: rc.CPEs, // do we just append all here? + Executables: rhelc.Executables, + // AddedBy: "", // do we know? + }) + } + return v1rhelc } From 939023bd6623d1d53fd8097ffb7ae26779a7e34a Mon Sep 17 00:00:00 2001 From: Matthias Meidinger Date: Wed, 30 Nov 2022 11:34:16 +0100 Subject: [PATCH 02/14] wip: Ported changes from Piotrs branch over --- compliance/collection/nodescanv2/nodescan.go | 11 +++++++++-- pkg/features/list.go | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/compliance/collection/nodescanv2/nodescan.go b/compliance/collection/nodescanv2/nodescan.go index 8f311d2775688..c16d245c6835d 100644 --- a/compliance/collection/nodescanv2/nodescan.go +++ b/compliance/collection/nodescanv2/nodescan.go @@ -29,7 +29,10 @@ func (n *NodeScan) Scan(nodeName string) (*storage.NodeInventory, error) { return nil, err } - protoComponents := protoComponentsFromScanComponents(componentsHost) + var protoComponents *scannerV1.Components + if componentsHost != nil { + protoComponents = protoComponentsFromScanComponents(componentsHost) + } m := &storage.NodeInventory{ NodeName: nodeName, ScanTime: timestamp.TimestampNow(), @@ -39,11 +42,15 @@ func (n *NodeScan) Scan(nodeName string) (*storage.NodeInventory, error) { } func protoComponentsFromScanComponents(c *nodes.Components) *scannerV1.Components { + var components []*scannerV1.RHELComponent // For now, we only care about RHEL components, but this must be extended once we support non-RHCOS + if c.CertifiedRHELComponents != nil { + components = convertRHELComponents(c.CertifiedRHELComponents) + } pc := scannerV1.Components{ Namespace: c.OSNamespace.Name, OsComponents: nil, - RhelComponents: convertRHELComponents(c.CertifiedRHELComponents), + RhelComponents: components, LanguageComponents: nil, } return &pc diff --git a/pkg/features/list.go b/pkg/features/list.go index afc73d09cd90d..a7219dd3b1694 100644 --- a/pkg/features/list.go +++ b/pkg/features/list.go @@ -46,6 +46,9 @@ var ( // RHCOSNodeScanning enables phase 1 functions of "Full host level vulnerability scanning for RHCOS nodes" (ROX-10818) RHCOSNodeScanning = registerFeature("Enable RHCOS node scanning of OS and installed packages", "ROX_RHCOS_NODE_SCANNING", false) + // UseFakeNodeInventory tells compliance to use FakeNodeScanner with hardcoded data instead of calling scanner.Analyze() + UseFakeNodeInventory = registerFeature("Enables compliance to use FakeNodeScanner with hardcoded data instead of calling scanner.Analyze()", "ROX_RHCOS_FAKE_NODE_INVENTORY", false) + // ProcessesListeningOnPort enables the NetworkFlow code to also update the processes that are listening on ports ProcessesListeningOnPort = registerFeature("Enable Processes Listening on Port", "ROX_PROCESSES_LISTENING_ON_PORT", false) From f151bdda0fce6e8bbccfd975cc16ece732068100 Mon Sep 17 00:00:00 2001 From: Matthias Meidinger Date: Wed, 7 Dec 2022 17:19:41 +0100 Subject: [PATCH 03/14] Extend compliance with new emptyDir mount for /tmp, keep RPM in compliance image, temporary switch to bleeding edge scanner PR branch --- image/rhel/Dockerfile.envsubst | 2 +- .../helm/stackrox-secured-cluster/templates/collector.yaml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/image/rhel/Dockerfile.envsubst b/image/rhel/Dockerfile.envsubst index cc6921c2a5ecf..13e7cb157ead1 100644 --- a/image/rhel/Dockerfile.envsubst +++ b/image/rhel/Dockerfile.envsubst @@ -55,7 +55,7 @@ RUN ln -s entrypoint-wrapper.sh /stackrox/admission-control && \ microdnf clean all && \ rm /tmp/snappy.rpm /tmp/postgres.rpm /tmp/postgres-libs.rpm RPM-GPG-KEY-CentOS-Official && \ # (Optional) Remove line below to keep package management utilities - rpm -e --nodeps $(rpm -qa curl '*rpm*' '*dnf*' '*libsolv*' '*hawkey*' 'yum*') && \ + rpm -e --nodeps $(rpm -qa curl '*dnf*' '*libsolv*' '*hawkey*' 'yum*') && \ rm -rf /var/cache/dnf /var/cache/yum && \ # The contents of paths mounted as emptyDir volumes in Kubernetes are saved # by the script `save-dir-contents` during the image build. The directory diff --git a/image/templates/helm/stackrox-secured-cluster/templates/collector.yaml b/image/templates/helm/stackrox-secured-cluster/templates/collector.yaml index 4997dea064696..0e485e36fad01 100644 --- a/image/templates/helm/stackrox-secured-cluster/templates/collector.yaml +++ b/image/templates/helm/stackrox-secured-cluster/templates/collector.yaml @@ -122,6 +122,8 @@ spec: - mountPath: /run/secrets/stackrox.io/certs/ name: certs readOnly: true + - mountPath: /tmp/ + name: tmp-ed volumes: - hostPath: path: /var/run/docker.sock @@ -161,3 +163,5 @@ spec: emptyDir: {} - name: etc-pki-volume emptyDir: {} + - name: tmp-ed + emptyDir: {} From 09f9a6602bbdb4b8867fcb808ed8e23f0efcce2f Mon Sep 17 00:00:00 2001 From: Matthias Meidinger Date: Thu, 8 Dec 2022 14:57:47 +0100 Subject: [PATCH 04/14] Remove TODO notice --- compliance/collection/main.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/compliance/collection/main.go b/compliance/collection/main.go index 078cd95758289..e6d16bc5274a6 100644 --- a/compliance/collection/main.go +++ b/compliance/collection/main.go @@ -276,9 +276,16 @@ func main() { defer close(sensorC) go manageSendingToSensor(ctx, cli, sensorC) - // TODO(ROX-12971): Replace with real scanner - scanner := nodescanv2.FakeNodeScanner{} - nodeInventoriesC := manageNodeScanLoop(ctx, env.NodeRescanInterval.DurationSetting(), &scanner) + var scanner nodescanv2.NodeScanner + if features.UseFakeNodeInventory.Enabled() { + log.Infof("Using FakeNodeScanner") + scanner = &nodescanv2.FakeNodeScanner{} + } else { + log.Infof("Using NodeScan") + scanner = &nodescanv2.NodeScan{} + } + nodeInventoriesC := manageNodeScanLoop(ctx, env.NodeRescanInterval.DurationSetting(), scanner) + // multiplex producers (nodeInventoriesC) into the output channel (sensorC) go func() { for { From cd61b511c251e82050b06e5a9bbfc9b40cdb0f5a Mon Sep 17 00:00:00 2001 From: Matthias Meidinger Date: Thu, 8 Dec 2022 15:54:35 +0100 Subject: [PATCH 05/14] Fix Fake Nodescan Test --- compliance/collection/nodescanv2/fake_nodescan_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compliance/collection/nodescanv2/fake_nodescan_test.go b/compliance/collection/nodescanv2/fake_nodescan_test.go index 4c21514d284f9..5be20a7b51ebd 100644 --- a/compliance/collection/nodescanv2/fake_nodescan_test.go +++ b/compliance/collection/nodescanv2/fake_nodescan_test.go @@ -19,5 +19,5 @@ func (n *FakeNodeScanSuite) TestMessageFormat() { fns, err := (&FakeNodeScanner{}).Scan("someNode") n.Nil(err) n.NotNil(fns) - n.IsType(&storage.NodeScanV2{}, fns) + n.IsType(&storage.NodeInventory{}, fns) } From 99cff759eef165b4bd8537320f1af9c7f7142794 Mon Sep 17 00:00:00 2001 From: Matthias Meidinger Date: Thu, 8 Dec 2022 16:13:07 +0100 Subject: [PATCH 06/14] Clean up rebase artifacts --- compliance/collection/nodescanv2/nodescan.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compliance/collection/nodescanv2/nodescan.go b/compliance/collection/nodescanv2/nodescan.go index c16d245c6835d..1235eff01f68a 100644 --- a/compliance/collection/nodescanv2/nodescan.go +++ b/compliance/collection/nodescanv2/nodescan.go @@ -17,7 +17,7 @@ type NodeScanner interface { type NodeScan struct { } -// Scan scans the current node and returns the results as storage.NodeScanV2 object +// Scan scans the current node and returns the results as storage.NodeInventory object func (n *NodeScan) Scan(nodeName string) (*storage.NodeInventory, error) { componentsHost, err := nodes.Analyze(nodeName, "/host/", false) log.Info("Finished node inventory /host scan") From 6047ea819f83635c6393dfc6839b65aae6dd14a1 Mon Sep 17 00:00:00 2001 From: Matthias Meidinger Date: Thu, 8 Dec 2022 18:40:50 +0100 Subject: [PATCH 07/14] Clean up code comments --- compliance/collection/nodescanv2/nodescan.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compliance/collection/nodescanv2/nodescan.go b/compliance/collection/nodescanv2/nodescan.go index 1235eff01f68a..2da6aef60a252 100644 --- a/compliance/collection/nodescanv2/nodescan.go +++ b/compliance/collection/nodescanv2/nodescan.go @@ -66,13 +66,12 @@ func convertRHELComponents(rc *database.RHELv2Components) []*scannerV1.RHELCompo v1rhelc = append(v1rhelc, &scannerV1.RHELComponent{ Id: 0, Name: rhelc.Name, - Namespace: rc.Dist, // check + Namespace: rc.Dist, Version: rhelc.Version, Arch: rhelc.Arch, Module: rhelc.Module, - Cpes: rc.CPEs, // do we just append all here? + Cpes: rc.CPEs, Executables: rhelc.Executables, - // AddedBy: "", // do we know? }) } return v1rhelc From 7d0c7fa83e98321b31e67d9a9b796da1d80a268d Mon Sep 17 00:00:00 2001 From: Matthias Meidinger Date: Tue, 13 Dec 2022 11:11:05 +0100 Subject: [PATCH 08/14] Update code to reflect semantic change from NodeScan to NodeInventory --- compliance/collection/main.go | 16 ++++++------- .../fake_nodeinventory.go} | 8 +++---- .../nodeinventory.go} | 10 ++++---- .../nodeinventory_test.go} | 10 ++++---- .../nodescanv2/fake_nodescan_test.go | 23 ------------------- 5 files changed, 22 insertions(+), 45 deletions(-) rename compliance/collection/{nodescanv2/fake_nodescan.go => nodeinventorizer/fake_nodeinventory.go} (82%) rename compliance/collection/{nodescanv2/nodescan.go => nodeinventorizer/nodeinventory.go} (89%) rename compliance/collection/{nodescanv2/nodescan_test.go => nodeinventorizer/nodeinventory_test.go} (57%) delete mode 100644 compliance/collection/nodescanv2/fake_nodescan_test.go diff --git a/compliance/collection/main.go b/compliance/collection/main.go index e6d16bc5274a6..de53f03c0a83a 100644 --- a/compliance/collection/main.go +++ b/compliance/collection/main.go @@ -10,7 +10,7 @@ import ( "github.com/cenkalti/backoff/v3" "github.com/pkg/errors" "github.com/stackrox/rox/compliance/collection/auditlog" - "github.com/stackrox/rox/compliance/collection/nodescanv2" + "github.com/stackrox/rox/compliance/collection/nodeinventorizer" "github.com/stackrox/rox/generated/internalapi/sensor" "github.com/stackrox/rox/generated/storage" "github.com/stackrox/rox/pkg/clientconn" @@ -148,7 +148,7 @@ func manageReceiveStream(ctx context.Context, cli sensor.ComplianceServiceClient } } -func manageNodeScanLoop(ctx context.Context, rescanInterval time.Duration, scanner nodescanv2.NodeScanner) <-chan *sensor.MsgFromCompliance { +func manageNodeScanLoop(ctx context.Context, rescanInterval time.Duration, scanner nodeinventorizer.NodeInventorizer) <-chan *sensor.MsgFromCompliance { sensorC := make(chan *sensor.MsgFromCompliance) nodeName := getNode() go func() { @@ -180,7 +180,7 @@ func manageNodeScanLoop(ctx context.Context, rescanInterval time.Duration, scann return sensorC } -func scanNode(nodeName string, scanner nodescanv2.NodeScanner) (*sensor.MsgFromCompliance, error) { +func scanNode(nodeName string, scanner nodeinventorizer.NodeInventorizer) (*sensor.MsgFromCompliance, error) { result, err := scanner.Scan(nodeName) if err != nil { return nil, err @@ -276,13 +276,13 @@ func main() { defer close(sensorC) go manageSendingToSensor(ctx, cli, sensorC) - var scanner nodescanv2.NodeScanner + var scanner nodeinventorizer.NodeInventorizer if features.UseFakeNodeInventory.Enabled() { - log.Infof("Using FakeNodeScanner") - scanner = &nodescanv2.FakeNodeScanner{} + log.Infof("Using FakeNodeInventorizer") + scanner = &nodeinventorizer.FakeNodeInventorizer{} } else { - log.Infof("Using NodeScan") - scanner = &nodescanv2.NodeScan{} + log.Infof("Using NodeInventoryCollector") + scanner = &nodeinventorizer.NodeInventoryCollector{} } nodeInventoriesC := manageNodeScanLoop(ctx, env.NodeRescanInterval.DurationSetting(), scanner) diff --git a/compliance/collection/nodescanv2/fake_nodescan.go b/compliance/collection/nodeinventorizer/fake_nodeinventory.go similarity index 82% rename from compliance/collection/nodescanv2/fake_nodescan.go rename to compliance/collection/nodeinventorizer/fake_nodeinventory.go index 59ac7f863080b..1ef2f1f1114d6 100644 --- a/compliance/collection/nodescanv2/fake_nodescan.go +++ b/compliance/collection/nodeinventorizer/fake_nodeinventory.go @@ -1,4 +1,4 @@ -package nodescanv2 +package nodeinventorizer import ( timestamp "github.com/gogo/protobuf/types" @@ -11,12 +11,12 @@ var ( log = logging.LoggerForModule() ) -// FakeNodeScanner can be used to send fake messages that would be emitted by NodeInventory -type FakeNodeScanner struct { +// FakeNodeInventorizer can be used to send fake messages that would be emitted by NodeInventory +type FakeNodeInventorizer struct { } // Scan returns a fake message in the same format a real NodeInventory would produce -func (f *FakeNodeScanner) Scan(nodeName string) (*storage.NodeInventory, error) { +func (f *FakeNodeInventorizer) Scan(nodeName string) (*storage.NodeInventory, error) { log.Infof("Generating fake scan result message...") msg := &storage.NodeInventory{ NodeId: "", diff --git a/compliance/collection/nodescanv2/nodescan.go b/compliance/collection/nodeinventorizer/nodeinventory.go similarity index 89% rename from compliance/collection/nodescanv2/nodescan.go rename to compliance/collection/nodeinventorizer/nodeinventory.go index 2da6aef60a252..a288cd3acc68b 100644 --- a/compliance/collection/nodescanv2/nodescan.go +++ b/compliance/collection/nodeinventorizer/nodeinventory.go @@ -1,4 +1,4 @@ -package nodescanv2 +package nodeinventorizer import ( timestamp "github.com/gogo/protobuf/types" @@ -8,17 +8,15 @@ import ( "github.com/stackrox/scanner/pkg/analyzer/nodes" ) -// NodeScanner defines an interface for V2 NodeScanning -type NodeScanner interface { +type NodeInventorizer interface { Scan(nodeName string) (*storage.NodeInventory, error) } -// NodeScan is the V2 NodeScanning implementation -type NodeScan struct { +type NodeInventoryCollector struct { } // Scan scans the current node and returns the results as storage.NodeInventory object -func (n *NodeScan) Scan(nodeName string) (*storage.NodeInventory, error) { +func (n *NodeInventoryCollector) Scan(nodeName string) (*storage.NodeInventory, error) { componentsHost, err := nodes.Analyze(nodeName, "/host/", false) log.Info("Finished node inventory /host scan") if err != nil { diff --git a/compliance/collection/nodescanv2/nodescan_test.go b/compliance/collection/nodeinventorizer/nodeinventory_test.go similarity index 57% rename from compliance/collection/nodescanv2/nodescan_test.go rename to compliance/collection/nodeinventorizer/nodeinventory_test.go index d47cd7bf9214a..f8c84f247c099 100644 --- a/compliance/collection/nodescanv2/nodescan_test.go +++ b/compliance/collection/nodeinventorizer/nodeinventory_test.go @@ -1,4 +1,4 @@ -package nodescanv2 +package nodeinventorizer import ( "testing" @@ -16,8 +16,10 @@ type NodeScanSuite struct { } func (n *NodeScanSuite) TestMessageFormat() { - fns, err := (&FakeNodeScanner{}).Scan("someNode") + inventory, err := (&NodeInventoryCollector{}).Scan("someNode") n.Nil(err) - n.NotNil(fns) - n.IsType(&storage.NodeInventory{}, fns) + n.NotNil(inventory) + n.IsType(&storage.NodeInventory{}, inventory) } + +// TODO: Test conversion functions and real Scan! diff --git a/compliance/collection/nodescanv2/fake_nodescan_test.go b/compliance/collection/nodescanv2/fake_nodescan_test.go deleted file mode 100644 index 5be20a7b51ebd..0000000000000 --- a/compliance/collection/nodescanv2/fake_nodescan_test.go +++ /dev/null @@ -1,23 +0,0 @@ -package nodescanv2 - -import ( - "testing" - - "github.com/stackrox/rox/generated/storage" - "github.com/stretchr/testify/suite" -) - -func TestFakeNodeScan(t *testing.T) { - suite.Run(t, &NodeScanSuite{}) -} - -type FakeNodeScanSuite struct { - suite.Suite -} - -func (n *FakeNodeScanSuite) TestMessageFormat() { - fns, err := (&FakeNodeScanner{}).Scan("someNode") - n.Nil(err) - n.NotNil(fns) - n.IsType(&storage.NodeInventory{}, fns) -} From 168814d6f3fac6456b9ce7d2a0953290419d23e0 Mon Sep 17 00:00:00 2001 From: Matthias Meidinger Date: Wed, 14 Dec 2022 13:38:38 +0100 Subject: [PATCH 09/14] Address review comments - Restructured code - Moved nil handling into functions - Add TODOs for tracking open points --- .../nodeinventorizer/nodeinventory.go | 35 ++++++++++--------- image/rhel/Dockerfile.envsubst | 1 + pkg/features/list.go | 1 + 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/compliance/collection/nodeinventorizer/nodeinventory.go b/compliance/collection/nodeinventorizer/nodeinventory.go index a288cd3acc68b..211ea3af1566f 100644 --- a/compliance/collection/nodeinventorizer/nodeinventory.go +++ b/compliance/collection/nodeinventorizer/nodeinventory.go @@ -8,10 +8,12 @@ import ( "github.com/stackrox/scanner/pkg/analyzer/nodes" ) +// NodeInventorizer is the interface that defines the interface a scanner must implement type NodeInventorizer interface { Scan(nodeName string) (*storage.NodeInventory, error) } +// NodeInventoryCollector is the implementation of NodeInventorizer type NodeInventoryCollector struct { } @@ -21,16 +23,12 @@ func (n *NodeInventoryCollector) Scan(nodeName string) (*storage.NodeInventory, log.Info("Finished node inventory /host scan") if err != nil { log.Errorf("Error scanning node /host inventory: %v", err) - } - log.Infof("Components found under /host: %v", componentsHost) - if err != nil { return nil, err } + log.Infof("Components found under /host: %v", componentsHost) + + protoComponents := protoComponentsFromScanComponents(componentsHost) - var protoComponents *scannerV1.Components - if componentsHost != nil { - protoComponents = protoComponentsFromScanComponents(componentsHost) - } m := &storage.NodeInventory{ NodeName: nodeName, ScanTime: timestamp.TimestampNow(), @@ -40,29 +38,32 @@ func (n *NodeInventoryCollector) Scan(nodeName string) (*storage.NodeInventory, } func protoComponentsFromScanComponents(c *nodes.Components) *scannerV1.Components { - var components []*scannerV1.RHELComponent - // For now, we only care about RHEL components, but this must be extended once we support non-RHCOS - if c.CertifiedRHELComponents != nil { - components = convertRHELComponents(c.CertifiedRHELComponents) + + if c == nil { + return nil } - pc := scannerV1.Components{ + + // For now, we only care about RHEL components, but this must be extended once we support non-RHCOS + rhelComponents := convertRHELComponents(c.CertifiedRHELComponents) + + protoComponents := &scannerV1.Components{ Namespace: c.OSNamespace.Name, OsComponents: nil, - RhelComponents: components, + RhelComponents: rhelComponents, LanguageComponents: nil, } - return &pc + return protoComponents } func convertRHELComponents(rc *database.RHELv2Components) []*scannerV1.RHELComponent { - v1rhelc := make([]*scannerV1.RHELComponent, 0) - if rc.Packages == nil { + if rc == nil || rc.Packages == nil { log.Warn("No RHEL packages found in scan result") return nil } + v1rhelc := make([]*scannerV1.RHELComponent, len(rc.Packages)) for _, rhelc := range rc.Packages { v1rhelc = append(v1rhelc, &scannerV1.RHELComponent{ - Id: 0, + // TODO(ROX-13936): Find out if ID field is needed here Name: rhelc.Name, Namespace: rc.Dist, Version: rhelc.Version, diff --git a/image/rhel/Dockerfile.envsubst b/image/rhel/Dockerfile.envsubst index 13e7cb157ead1..639e9fa592d2f 100644 --- a/image/rhel/Dockerfile.envsubst +++ b/image/rhel/Dockerfile.envsubst @@ -55,6 +55,7 @@ RUN ln -s entrypoint-wrapper.sh /stackrox/admission-control && \ microdnf clean all && \ rm /tmp/snappy.rpm /tmp/postgres.rpm /tmp/postgres-libs.rpm RPM-GPG-KEY-CentOS-Official && \ # (Optional) Remove line below to keep package management utilities + # TODO(ROX-13934): Potentially add *RPM* to this list again rpm -e --nodeps $(rpm -qa curl '*dnf*' '*libsolv*' '*hawkey*' 'yum*') && \ rm -rf /var/cache/dnf /var/cache/yum && \ # The contents of paths mounted as emptyDir volumes in Kubernetes are saved diff --git a/pkg/features/list.go b/pkg/features/list.go index a7219dd3b1694..b96a6121bb24a 100644 --- a/pkg/features/list.go +++ b/pkg/features/list.go @@ -47,6 +47,7 @@ var ( RHCOSNodeScanning = registerFeature("Enable RHCOS node scanning of OS and installed packages", "ROX_RHCOS_NODE_SCANNING", false) // UseFakeNodeInventory tells compliance to use FakeNodeScanner with hardcoded data instead of calling scanner.Analyze() + // TODO(ROX-13935): Remove this FF and the accompanying code UseFakeNodeInventory = registerFeature("Enables compliance to use FakeNodeScanner with hardcoded data instead of calling scanner.Analyze()", "ROX_RHCOS_FAKE_NODE_INVENTORY", false) // ProcessesListeningOnPort enables the NetworkFlow code to also update the processes that are listening on ports From 707eab2f63a83d0a0379469d6579af7a9b403070 Mon Sep 17 00:00:00 2001 From: Matthias Meidinger Date: Thu, 15 Dec 2022 12:52:02 +0100 Subject: [PATCH 10/14] Init component array with 0 again to mitigate panics --- compliance/collection/nodeinventorizer/nodeinventory.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compliance/collection/nodeinventorizer/nodeinventory.go b/compliance/collection/nodeinventorizer/nodeinventory.go index 211ea3af1566f..8c882cfbef4fd 100644 --- a/compliance/collection/nodeinventorizer/nodeinventory.go +++ b/compliance/collection/nodeinventorizer/nodeinventory.go @@ -60,7 +60,7 @@ func convertRHELComponents(rc *database.RHELv2Components) []*scannerV1.RHELCompo log.Warn("No RHEL packages found in scan result") return nil } - v1rhelc := make([]*scannerV1.RHELComponent, len(rc.Packages)) + v1rhelc := make([]*scannerV1.RHELComponent, 0) for _, rhelc := range rc.Packages { v1rhelc = append(v1rhelc, &scannerV1.RHELComponent{ // TODO(ROX-13936): Find out if ID field is needed here From 963d4f23ad1d6957f4bdee6589b7629e09e091a3 Mon Sep 17 00:00:00 2001 From: Matthias Meidinger Date: Mon, 19 Dec 2022 14:06:56 +0100 Subject: [PATCH 11/14] Implement feedback - Add changelog for RPM - Rename tmp volume in Helm chart - Rework logging for nodeinventory.go --- CHANGELOG.md | 1 + compliance/collection/nodeinventorizer/nodeinventory.go | 9 ++++++--- .../stackrox-secured-cluster/templates/collector.yaml | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2af32dcd6ab2..0cfe2b7aa115f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Please avoid adding duplicate information across this changelog and JIRA/doc inp ### Deprecated Features ### Technical Changes +- ROX-12967: Introduce `rpm` to the main image to parse installed packages on RHCOS nodes ## [3.73.1] diff --git a/compliance/collection/nodeinventorizer/nodeinventory.go b/compliance/collection/nodeinventorizer/nodeinventory.go index 8c882cfbef4fd..51af40ce60609 100644 --- a/compliance/collection/nodeinventorizer/nodeinventory.go +++ b/compliance/collection/nodeinventorizer/nodeinventory.go @@ -13,19 +13,22 @@ type NodeInventorizer interface { Scan(nodeName string) (*storage.NodeInventory, error) } -// NodeInventoryCollector is the implementation of NodeInventorizer +// NodeInventoryCollector is an implementation of NodeInventorizer type NodeInventoryCollector struct { } // Scan scans the current node and returns the results as storage.NodeInventory object func (n *NodeInventoryCollector) Scan(nodeName string) (*storage.NodeInventory, error) { + log.Info("Started node inventory") + // uncertifiedRHEL is set to false, as scans are only supported on RHCOS for now, + // which only exists in certified versions componentsHost, err := nodes.Analyze(nodeName, "/host/", false) - log.Info("Finished node inventory /host scan") + log.Info("Finished node inventory") if err != nil { log.Errorf("Error scanning node /host inventory: %v", err) return nil, err } - log.Infof("Components found under /host: %v", componentsHost) + log.Debugf("Components found under /host: %v", componentsHost) protoComponents := protoComponentsFromScanComponents(componentsHost) diff --git a/image/templates/helm/stackrox-secured-cluster/templates/collector.yaml b/image/templates/helm/stackrox-secured-cluster/templates/collector.yaml index 0e485e36fad01..dca3cf3635996 100644 --- a/image/templates/helm/stackrox-secured-cluster/templates/collector.yaml +++ b/image/templates/helm/stackrox-secured-cluster/templates/collector.yaml @@ -123,7 +123,7 @@ spec: name: certs readOnly: true - mountPath: /tmp/ - name: tmp-ed + name: tmp-volume volumes: - hostPath: path: /var/run/docker.sock @@ -163,5 +163,5 @@ spec: emptyDir: {} - name: etc-pki-volume emptyDir: {} - - name: tmp-ed + - name: tmp-volume emptyDir: {} From 39da7339cde2e3ec046a1f16cf911f404b2dad63 Mon Sep 17 00:00:00 2001 From: Matthias Meidinger Date: Tue, 20 Dec 2022 12:05:49 +0100 Subject: [PATCH 12/14] Remove now defunct nodeinventory test --- .../nodeinventorizer/nodeinventory_test.go | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 compliance/collection/nodeinventorizer/nodeinventory_test.go diff --git a/compliance/collection/nodeinventorizer/nodeinventory_test.go b/compliance/collection/nodeinventorizer/nodeinventory_test.go deleted file mode 100644 index f8c84f247c099..0000000000000 --- a/compliance/collection/nodeinventorizer/nodeinventory_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package nodeinventorizer - -import ( - "testing" - - "github.com/stackrox/rox/generated/storage" - "github.com/stretchr/testify/suite" -) - -func TestNodeScan(t *testing.T) { - suite.Run(t, &NodeScanSuite{}) -} - -type NodeScanSuite struct { - suite.Suite -} - -func (n *NodeScanSuite) TestMessageFormat() { - inventory, err := (&NodeInventoryCollector{}).Scan("someNode") - n.Nil(err) - n.NotNil(inventory) - n.IsType(&storage.NodeInventory{}, inventory) -} - -// TODO: Test conversion functions and real Scan! From cb77bec12d729b6db1e942a626e81204f84b9217 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 20 Dec 2022 15:23:48 +0100 Subject: [PATCH 13/14] Update CHANGELOG.md Co-authored-by: Misha Sugakov <537715+msugakov@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cfe2b7aa115f..9b68044b6fb25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ Please avoid adding duplicate information across this changelog and JIRA/doc inp ### Deprecated Features ### Technical Changes -- ROX-12967: Introduce `rpm` to the main image to parse installed packages on RHCOS nodes +- ROX-12967: Re-introduce `rpm` to the main image in order to be able parse installed packages on RHCOS nodes (from Compliance container) ## [3.73.1] From 17897d704ecf7d4643ad0d2facc18e25efee21e7 Mon Sep 17 00:00:00 2001 From: Matthias Meidinger Date: Tue, 20 Dec 2022 16:00:42 +0100 Subject: [PATCH 14/14] Init component slice with correct length --- compliance/collection/nodeinventorizer/nodeinventory.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compliance/collection/nodeinventorizer/nodeinventory.go b/compliance/collection/nodeinventorizer/nodeinventory.go index 51af40ce60609..c5368bb99f7c7 100644 --- a/compliance/collection/nodeinventorizer/nodeinventory.go +++ b/compliance/collection/nodeinventorizer/nodeinventory.go @@ -63,7 +63,7 @@ func convertRHELComponents(rc *database.RHELv2Components) []*scannerV1.RHELCompo log.Warn("No RHEL packages found in scan result") return nil } - v1rhelc := make([]*scannerV1.RHELComponent, 0) + v1rhelc := make([]*scannerV1.RHELComponent, 0, len(rc.Packages)) for _, rhelc := range rc.Packages { v1rhelc = append(v1rhelc, &scannerV1.RHELComponent{ // TODO(ROX-13936): Find out if ID field is needed here