Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ssh topology scanner initial implementation #557

Merged
merged 11 commits into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions .families.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
sbom:
enabled: true
enabled: false
analyzers_list:
- "syft"
- "gomod"
Expand All @@ -26,7 +26,7 @@ sbom:
token: "token"

vulnerabilities:
enabled: true
enabled: false
scanners_list:
- "grype"
inputs:
Expand Down Expand Up @@ -68,7 +68,7 @@ secrets:
binary_path: "/usr/local/bin/gitleaks"

exploits:
enabled: true
enabled: false
scanners_list:
- "exploitdb"
inputs: []
Expand All @@ -78,10 +78,20 @@ exploits:
base_url: "http://localhost:1326"

misconfiguration:
enabled: true
enabled: false
scanners_list:
- "fake"
inputs:
- input: "./"
input_type: "rootfs"
scanners_configs: {}


infofinder:
enabled: true
scanners_list:
- "sshTopology"
inputs:
- input: "/"
input_type: "rootfs"
scanners_configs: {}
2 changes: 1 addition & 1 deletion Dockerfile.cli
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:1.2
ARG VMCLARITY_TOOLS_BASE=ghcr.io/openclarity/vmclarity-tools-base:v0.2.0@sha256:0e0ed706dc297366af44d736c71aefa350b54a0214290aa81b3603462e39872b
ARG VMCLARITY_TOOLS_BASE=ghcr.io/openclarity/vmclarity-tools-base:v0.3.0@sha256:c592419f5f3f184909363e080b01aea5deef63374b856aed74334afa3bdef793
FROM --platform=$BUILDPLATFORM golang:1.20.7-alpine AS builder

RUN apk add --update --no-cache ca-certificates git
Expand Down
21 changes: 21 additions & 0 deletions pkg/cli/presenter/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (

"github.com/openclarity/vmclarity/pkg/shared/families"
"github.com/openclarity/vmclarity/pkg/shared/families/exploits"
"github.com/openclarity/vmclarity/pkg/shared/families/infofinder"
"github.com/openclarity/vmclarity/pkg/shared/families/malware"
"github.com/openclarity/vmclarity/pkg/shared/families/rootkits"
"github.com/openclarity/vmclarity/pkg/shared/families/sbom"
Expand Down Expand Up @@ -54,6 +55,8 @@ func (p *DefaultPresenter) ExportFamilyResult(ctx context.Context, res families.
err = p.ExportRootkitResult(ctx, res)
case types.Malware:
err = p.ExportMalwareResult(ctx, res)
case types.InfoFinder:
err = p.ExportInfoFinderResult(ctx, res)
}

return err
Expand Down Expand Up @@ -167,3 +170,21 @@ func (p *DefaultPresenter) ExportRootkitResult(_ context.Context, res families.F
}
return nil
}

func (p *DefaultPresenter) ExportInfoFinderResult(_ context.Context, res families.FamilyResult) error {
infoFinderResults, ok := res.Result.(*infofinder.Results)
if !ok {
return fmt.Errorf("failed to convert to infofinder results")
}

bytes, err := json.Marshal(infoFinderResults)
if err != nil {
return fmt.Errorf("failed to marshal infofinder results: %w", err)
}

if err = p.Write(bytes, "infofinder.json"); err != nil {
return fmt.Errorf("failed to output infofinder results: %w", err)
}

return nil
}
2 changes: 2 additions & 0 deletions pkg/cli/presenter/vmclarity.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ func (v *VMClarityPresenter) ExportFamilyResult(ctx context.Context, res familie
err = v.ExportRootkitResult(ctx, res)
case types.Malware:
err = v.ExportMalwareResult(ctx, res)
case types.InfoFinder:
err = fmt.Errorf("InfoFinder family is unsupported")
}

return err
Expand Down
2 changes: 2 additions & 0 deletions pkg/cli/state/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ func (l *LocalState) MarkFamilyScanInProgress(ctx context.Context, familyType ty
logger.Info("Rootkit scan is in progress")
case types.Malware:
logger.Info("Malware scan is in progress")
case types.InfoFinder:
logger.Info("InfoFinder scan is in progress")
}
return nil
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/cli/state/vmclarity.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ func (v *VMClarityState) MarkFamilyScanInProgress(ctx context.Context, familyTyp
err = v.markRootkitsScanInProgress(ctx)
case types.Malware:
err = v.markMalwareScanInProgress(ctx)
case types.InfoFinder:
err = fmt.Errorf("InfoFinder family is unsupported")
}
return err
}
Expand Down
13 changes: 13 additions & 0 deletions pkg/shared/families/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
kubeclarityutils "github.com/openclarity/kubeclarity/shared/pkg/utils"

"github.com/openclarity/vmclarity/pkg/shared/families/exploits"
infofinderTypes "github.com/openclarity/vmclarity/pkg/shared/families/infofinder/types"
"github.com/openclarity/vmclarity/pkg/shared/families/malware"
misconfigurationTypes "github.com/openclarity/vmclarity/pkg/shared/families/misconfiguration/types"
"github.com/openclarity/vmclarity/pkg/shared/families/rootkits"
Expand All @@ -39,6 +40,7 @@ type Config struct {
Rootkits rootkits.Config `json:"rootkits" yaml:"rootkits" mapstructure:"rootkits"`
Malware malware.Config `json:"malware" yaml:"malware" mapstructure:"malware"`
Misconfiguration misconfigurationTypes.Config `json:"misconfiguration" yaml:"misconfiguration" mapstructure:"misconfiguration"`
InfoFinder infofinderTypes.Config `json:"infofinder" yaml:"infofinder" mapstructure:"infofinder"`

// Enrichers
Exploits exploits.Config `json:"exploits" yaml:"exploits" mapstructure:"exploits"`
Expand Down Expand Up @@ -111,6 +113,17 @@ func SetMountPointsForFamiliesInput(mountPoints []string, familiesConfig *Config
},
)
}

if familiesConfig.InfoFinder.Enabled {
familiesConfig.InfoFinder.Inputs = append(
familiesConfig.InfoFinder.Inputs,
types.Input{
StripPathFromResult: utils.PointerTo(true),
Input: mountDir,
InputType: string(kubeclarityutils.ROOTFS),
},
)
}
}
return familiesConfig
}
97 changes: 97 additions & 0 deletions pkg/shared/families/infofinder/family.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright © 2023 Cisco Systems, Inc. and its affiliates.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package infofinder

import (
"context"
"fmt"
"time"

"github.com/openclarity/kubeclarity/shared/pkg/job_manager"
"github.com/openclarity/kubeclarity/shared/pkg/utils"

"github.com/openclarity/vmclarity/pkg/shared/families/infofinder/job"
infofinderTypes "github.com/openclarity/vmclarity/pkg/shared/families/infofinder/types"
"github.com/openclarity/vmclarity/pkg/shared/families/interfaces"
"github.com/openclarity/vmclarity/pkg/shared/families/results"
"github.com/openclarity/vmclarity/pkg/shared/families/types"
familiesutils "github.com/openclarity/vmclarity/pkg/shared/families/utils"
"github.com/openclarity/vmclarity/pkg/shared/log"
)

type InfoFinder struct {
conf infofinderTypes.Config
}

func (i InfoFinder) Run(ctx context.Context, _ *results.Results) (interfaces.IsResults, error) {
logger := log.GetLoggerFromContextOrDiscard(ctx).WithField("family", "info finder")
logger.Info("InfoFinder Run...")

infoFinderResults := NewResults()

manager := job_manager.New(i.conf.ScannersList, i.conf.ScannersConfig, logger, job.Factory)
for _, input := range i.conf.Inputs {
startTime := time.Now()
managerResults, err := manager.Run(utils.SourceType(input.InputType), input.Input)
if err != nil {
return nil, fmt.Errorf("failed to scan input %q for info: %v", input.Input, err)
}
endTime := time.Now()
inputSize, err := familiesutils.GetInputSize(input)
if err != nil {
logger.Warnf("Failed to calculate input %v size: %v", input, err)
}

// Merge results.
for name, result := range managerResults {
logger.Infof("Merging result from %q", name)
if assetScan, ok := result.(*infofinderTypes.ScannerResult); ok {
if familiesutils.ShouldStripInputPath(input.StripPathFromResult, i.conf.StripInputPaths) {
assetScan = stripPathFromResult(assetScan, input.Input)
}
infoFinderResults.AddScannerResult(assetScan)
} else {
return nil, fmt.Errorf("received bad scanner result type %T, expected infofinderTypes.ScannerResult", result)
}
}
infoFinderResults.Metadata.InputScans = append(infoFinderResults.Metadata.InputScans, types.CreateInputScanMetadata(startTime, endTime, inputSize, input))
}

logger.Info("InfoFinder Done...")

return infoFinderResults, nil
}

// stripPathFromResult strip input path from results wherever it is found.
func stripPathFromResult(result *infofinderTypes.ScannerResult, path string) *infofinderTypes.ScannerResult {
for i := range result.Infos {
result.Infos[i].Path = familiesutils.TrimMountPath(result.Infos[i].Path, path)
}
return result
}

func (i InfoFinder) GetType() types.FamilyType {
return types.InfoFinder
}

// ensure types implement the requisite interfaces.
var _ interfaces.Family = &InfoFinder{}

func New(conf infofinderTypes.Config) *InfoFinder {
return &InfoFinder{
conf: conf,
}
}
28 changes: 28 additions & 0 deletions pkg/shared/families/infofinder/job/job.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright © 2023 Cisco Systems, Inc. and its affiliates.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package job

import (
"github.com/openclarity/kubeclarity/shared/pkg/job_manager"

"github.com/openclarity/vmclarity/pkg/shared/families/infofinder/sshtopology"
)

var Factory = job_manager.NewJobFactory()

func init() {
Factory.Register(sshtopology.ScannerName, sshtopology.New)
}
68 changes: 68 additions & 0 deletions pkg/shared/families/infofinder/result.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright © 2023 Cisco Systems, Inc. and its affiliates.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package infofinder

import (
"time"

"github.com/openclarity/vmclarity/pkg/shared/families/infofinder/types"
familiestypes "github.com/openclarity/vmclarity/pkg/shared/families/types"
)

type FlattenedInfos struct {
ScannerName string `json:"ScannerName"`
types.Info
}

type Results struct {
Metadata familiestypes.Metadata `json:"Metadata"`
Infos []FlattenedInfos `json:"Infos"`
}

func NewResults() *Results {
return &Results{
Metadata: familiestypes.Metadata{
Timestamp: time.Now(),
Scanners: []string{},
},
Infos: []FlattenedInfos{},
}
}

func (*Results) IsResults() {}

func (r *Results) addScannerNameToMetadata(name string) {
for _, scannerName := range r.Metadata.Scanners {
if scannerName == name {
return
}
}
r.Metadata.Scanners = append(r.Metadata.Scanners, name)
}

func (r *Results) AddScannerResult(scannerResult *types.ScannerResult) {
r.addScannerNameToMetadata(scannerResult.ScannerName)

for _, info := range scannerResult.Infos {
r.Infos = append(r.Infos, FlattenedInfos{
ScannerName: scannerResult.ScannerName,
Info: info,
})
}

// bump the timestamp as there are new results
r.Metadata.Timestamp = time.Now()
}
Loading
Loading