diff --git a/feature_string.go b/feature_string.go index 16b3aec562..c2e0695fdf 100644 --- a/feature_string.go +++ b/feature_string.go @@ -16,11 +16,12 @@ func _() { _ = x[ErrorsAsFailures-6] _ = x[StoreResourcesData-7] _ = x[FineGrainedAssets-8] + _ = x[SerialNumberAsID-9] } -const _Feature_name = "MassQueriesPiperCodeBoolAssertionsK8sNodeDiscoveryMQLAssetContextErrorsAsFailuresStoreResourcesDataFineGrainedAssets" +const _Feature_name = "MassQueriesPiperCodeBoolAssertionsK8sNodeDiscoveryMQLAssetContextErrorsAsFailuresStoreResourcesDataFineGrainedAssetsSerialNumberAsID" -var _Feature_index = [...]uint8{0, 11, 20, 34, 50, 65, 81, 99, 116} +var _Feature_index = [...]uint8{0, 11, 20, 34, 50, 65, 81, 99, 116, 132} func (i Feature) String() string { i -= 1 diff --git a/featureflags.go b/featureflags.go index 947ad629fb..0595c3cc6d 100644 --- a/featureflags.go +++ b/featureflags.go @@ -88,6 +88,12 @@ const ( // start: v11.x // end: tbd (candidate: v12.0) FineGrainedAssets + + // SerialNumberAsID feature flag + // desc: Use serial number as the asset ID + // start: v11.x + // end: tbd (candidate: v12.0) + SerialNumberAsID ) // FeaturesValue is a map from feature name to feature flag @@ -99,6 +105,7 @@ var FeaturesValue = map[string]Feature{ ErrorsAsFailures.String(): ErrorsAsFailures, StoreResourcesData.String(): StoreResourcesData, FineGrainedAssets.String(): FineGrainedAssets, + SerialNumberAsID.String(): SerialNumberAsID, } // DefaultFeatures are a set of default flags that are active diff --git a/providers-sdk/v1/sysinfo/sysinfo.go b/providers-sdk/v1/sysinfo/sysinfo.go index 4e5aa72fe3..0ae78eeb84 100644 --- a/providers-sdk/v1/sysinfo/sysinfo.go +++ b/providers-sdk/v1/sysinfo/sysinfo.go @@ -11,6 +11,7 @@ import ( "go.mondoo.com/cnquery/v11" "go.mondoo.com/cnquery/v11/cli/execruntime" "go.mondoo.com/cnquery/v11/providers-sdk/v1/inventory" + "go.mondoo.com/cnquery/v11/providers-sdk/v1/plugin" "go.mondoo.com/cnquery/v11/providers/os/connection/local" "go.mondoo.com/cnquery/v11/providers/os/id" "go.mondoo.com/cnquery/v11/providers/os/id/hostname" @@ -46,7 +47,7 @@ func Get() (*SystemInfo, error) { Type: "local", }, &asset) - fingerprint, platform, _ := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) + fingerprint, platform, _ := id.IdentifyPlatform(conn, &plugin.ConnectReq{}, asset.Platform, asset.IdDetector) if fingerprint != nil { if len(fingerprint.PlatformIDs) > 0 { sysInfo.PlatformId = fingerprint.PlatformIDs[0] diff --git a/providers/os/connection/device/device_connection.go b/providers/os/connection/device/device_connection.go index da236f4a51..e484124964 100644 --- a/providers/os/connection/device/device_connection.go +++ b/providers/os/connection/device/device_connection.go @@ -111,7 +111,7 @@ func NewDeviceConnection(connId uint32, conf *inventory.Config, asset *inventory } asset.Platform = p asset.IdDetector = []string{ids.IdDetector_Hostname} - fingerprint, p, err := id.IdentifyPlatform(res, asset.Platform, asset.IdDetector) + fingerprint, p, err := id.IdentifyPlatform(res, &plugin.ConnectReq{}, asset.Platform, asset.IdDetector) if err == nil { if asset.Name == "" { asset.Name = fingerprint.Name diff --git a/providers/os/id/ids/ids.go b/providers/os/id/ids/ids.go index 94f14597c1..b6c606a3c0 100644 --- a/providers/os/id/ids/ids.go +++ b/providers/os/id/ids/ids.go @@ -4,11 +4,12 @@ package ids const ( - IdDetector_Hostname = "hostname" - IdDetector_MachineID = "machine-id" - IdDetector_CloudDetect = "cloud-detect" - IdDetector_SshHostkey = "ssh-host-key" - IdDetector_AwsEcs = "aws-ecs" + IdDetector_Hostname = "hostname" + IdDetector_MachineID = "machine-id" + IdDetector_SerialNumber = "serialnumber" + IdDetector_CloudDetect = "cloud-detect" + IdDetector_SshHostkey = "ssh-host-key" + IdDetector_AwsEcs = "aws-ecs" // IdDetector_PlatformID = "transport-platform-id" // TODO: how does this work? ) diff --git a/providers/os/id/platform.go b/providers/os/id/platform.go index ed44fdc99a..a52ea6ab7a 100644 --- a/providers/os/id/platform.go +++ b/providers/os/id/platform.go @@ -8,7 +8,9 @@ import ( "fmt" "github.com/rs/zerolog/log" + "go.mondoo.com/cnquery/v11" "go.mondoo.com/cnquery/v11/providers-sdk/v1/inventory" + "go.mondoo.com/cnquery/v11/providers-sdk/v1/plugin" "go.mondoo.com/cnquery/v11/providers/os/connection/shared" "go.mondoo.com/cnquery/v11/providers/os/detector" "go.mondoo.com/cnquery/v11/providers/os/id/awsec2" @@ -17,6 +19,7 @@ import ( "go.mondoo.com/cnquery/v11/providers/os/id/hostname" "go.mondoo.com/cnquery/v11/providers/os/id/ids" "go.mondoo.com/cnquery/v11/providers/os/id/machineid" + "go.mondoo.com/cnquery/v11/providers/os/id/serialnumber" "go.mondoo.com/cnquery/v11/providers/os/id/sshhostkey" ) @@ -35,7 +38,7 @@ type PlatformInfo struct { RelatedPlatformIDs []string } -func IdentifyPlatform(conn shared.Connection, p *inventory.Platform, idDetectors []string) (*PlatformFingerprint, *inventory.Platform, error) { +func IdentifyPlatform(conn shared.Connection, req *plugin.ConnectReq, p *inventory.Platform, idDetectors []string) (*PlatformFingerprint, *inventory.Platform, error) { var ok bool if p == nil { p, ok = detector.DetectOS(conn) @@ -53,6 +56,9 @@ func IdentifyPlatform(conn shared.Connection, p *inventory.Platform, idDetectors switch conn.Type() { case shared.Type_Local: idDetectors = []string{ids.IdDetector_Hostname, ids.IdDetector_CloudDetect} + if cnquery.Features(req.Features).IsActive(cnquery.SerialNumberAsID) { + idDetectors = append(idDetectors, ids.IdDetector_SerialNumber) + } case shared.Type_SSH: idDetectors = []string{ids.IdDetector_Hostname, ids.IdDetector_CloudDetect, ids.IdDetector_SshHostkey} case shared.Type_Tar, shared.Type_FileSystem, shared.Type_DockerSnapshot: @@ -161,6 +167,17 @@ func GatherPlatformInfo(conn shared.Connection, pf *inventory.Platform, idDetect }, hostErr } return &PlatformInfo{}, nil + case idDetector == ids.IdDetector_SerialNumber: + serial, err := serialnumber.SerialNumber(conn, pf) + if err == nil && len(serial) > 0 { + identifier = "//platformid.api.mondoo.app/serialnumber/" + serial + return &PlatformInfo{ + IDs: []string{identifier}, + Name: "", + RelatedPlatformIDs: []string{}, + }, nil + } + return &PlatformInfo{}, nil case idDetector == ids.IdDetector_AwsEcs: metadata, err := awsecs.Resolve(conn, pf) if err != nil { diff --git a/providers/os/id/serialnumber/serial.go b/providers/os/id/serialnumber/serial.go new file mode 100644 index 0000000000..4275de664c --- /dev/null +++ b/providers/os/id/serialnumber/serial.go @@ -0,0 +1,28 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package serialnumber + +import ( + "github.com/pkg/errors" + "go.mondoo.com/cnquery/v11/providers-sdk/v1/inventory" + "go.mondoo.com/cnquery/v11/providers/os/connection/shared" + "go.mondoo.com/cnquery/v11/providers/os/resources/smbios" +) + +func SerialNumber(conn shared.Connection, p *inventory.Platform) (string, error) { + mgr, err := smbios.ResolveManager(conn, p) + if err != nil { + return "", errors.Wrap(err, "cannot determine platform serial number") + } + if mgr == nil { + return "", errors.New("cannot determine platform serial number") + } + + info, err := mgr.Info() + if err != nil { + return "", errors.New("cannot determine platform serial number") + } + + return info.SysInfo.SerialNumber, nil +} diff --git a/providers/os/provider/provider.go b/providers/os/provider/provider.go index 891b46380a..a2b935d885 100644 --- a/providers/os/provider/provider.go +++ b/providers/os/provider/provider.go @@ -350,7 +350,7 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba case shared.Type_Local.String(), "k8s": // FIXME: k8s is a temp workaround for cross-provider resources conn = local.NewConnection(connId, conf, asset) - fingerprint, p, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) + fingerprint, p, err := id.IdentifyPlatform(conn, req, asset.Platform, asset.IdDetector) if err == nil { if asset.Name == "" { asset.Name = fingerprint.Name @@ -368,7 +368,7 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba return nil, err } - fingerprint, p, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) + fingerprint, p, err := id.IdentifyPlatform(conn, req, asset.Platform, asset.IdDetector) if err == nil { if conn.Asset().Connections[0].Runtime != "vagrant" { asset.Name = fingerprint.Name @@ -385,7 +385,7 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba return nil, err } - fingerprint, p, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) + fingerprint, p, err := id.IdentifyPlatform(conn, req, asset.Platform, asset.IdDetector) if err == nil { asset.Name = fingerprint.Name asset.PlatformIds = fingerprint.PlatformIDs @@ -400,7 +400,7 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba return nil, err } - fingerprint, p, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) + fingerprint, p, err := id.IdentifyPlatform(conn, req, asset.Platform, asset.IdDetector) if err == nil { asset.Name = fingerprint.Name asset.PlatformIds = fingerprint.PlatformIDs @@ -415,7 +415,7 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba return nil, err } - fingerprint, p, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) + fingerprint, p, err := id.IdentifyPlatform(conn, req, asset.Platform, asset.IdDetector) if err == nil { asset.Name = fingerprint.Name asset.PlatformIds = fingerprint.PlatformIDs @@ -467,7 +467,7 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba // This is a workaround to set Google COS platform IDs when scanned from inside k8s pID, err := conn.(*fs.FileSystemConnection).Identifier() if err != nil { - fingerprint, p, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) + fingerprint, p, err := id.IdentifyPlatform(conn, req, asset.Platform, asset.IdDetector) if err == nil { asset.Name = fingerprint.Name asset.PlatformIds = fingerprint.PlatformIDs