Skip to content

Commit

Permalink
🐛 fix asset name for local, ssh conn (#1740)
Browse files Browse the repository at this point in the history
this fixes the asset name detection for local and ssh - it's a portover
from v8.
  • Loading branch information
vjeffrey authored Sep 19, 2023
1 parent e46f977 commit c814c3e
Show file tree
Hide file tree
Showing 6 changed files with 330 additions and 22 deletions.
15 changes: 15 additions & 0 deletions providers/os/id/awsec2/id.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,18 @@ func ParseMondooAccountID(path string) (string, error) {
func IsValidMondooAccountId(path string) bool {
return VALID_MONDOO_ACCOUNT_ID.MatchString(path)
}

func ParseEc2PlatformID(uri string) *MondooInstanceId {
// aws://ec2/v1/accounts/{account}/regions/{region}/instances/{instanceid}
awsec2 := regexp.MustCompile(`^\/\/platformid.api.mondoo.app\/runtime\/aws\/ec2\/v1\/accounts\/(.*)\/regions\/(.*)\/instances\/(.*)$`)
m := awsec2.FindStringSubmatch(uri)
if len(m) == 0 {
return nil
}

return &MondooInstanceId{
Account: m[1],
Region: m[2],
Id: m[3],
}
}
77 changes: 77 additions & 0 deletions providers/os/id/clouddetect/clouddetect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package clouddetect

import (
"sync"

"github.com/rs/zerolog/log"
"go.mondoo.com/cnquery/providers-sdk/v1/inventory"
"go.mondoo.com/cnquery/providers/os/connection/shared"
"go.mondoo.com/cnquery/providers/os/id/aws"
"go.mondoo.com/cnquery/providers/os/id/azure"
"go.mondoo.com/cnquery/providers/os/id/gcp"
)

type (
RelatedPlatformID = string
PlatformName = string
PlatformID = string
)

type detectorFunc func(conn shared.Connection, p *inventory.Platform) (PlatformID, PlatformName, []RelatedPlatformID)

var detectors = []detectorFunc{
aws.Detect,
azure.Detect,
gcp.Detect,
}

type detectResult struct {
platformId string
platformName string
relatedPlatformIds []string
}

func Detect(conn shared.Connection, p *inventory.Platform) (PlatformID, PlatformName, []RelatedPlatformID) {
wg := sync.WaitGroup{}
wg.Add(len(detectors))

valChan := make(chan detectResult, len(detectors))
for i := range detectors {
go func(f detectorFunc) {
defer wg.Done()

v, name, related := f(conn, p)
if v != "" {
valChan <- detectResult{
platformName: name,
platformId: v,
relatedPlatformIds: related,
}
}
}(detectors[i])
}

wg.Wait()
close(valChan)

platformIds := []string{}
relatedPlatformIds := []string{}
var name string
for v := range valChan {
platformIds = append(platformIds, v.platformId)
name = v.platformName
relatedPlatformIds = append(relatedPlatformIds, v.relatedPlatformIds...)
}

if len(platformIds) == 0 {
return "", "", nil
} else if len(platformIds) > 1 {
log.Error().Strs("detected", platformIds).Msg("multiple cloud platform ids detected")
return "", "", nil
}

return platformIds[0], name, relatedPlatformIds
}
14 changes: 14 additions & 0 deletions providers/os/id/ids/ids.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package ids

const (
IdDetector_Hostname = "hostname"
IdDetector_MachineID = "machine-id"
IdDetector_CloudDetect = "cloud-detect"
IdDetector_SshHostkey = "ssh-host-key"
IdDetector_AwsEcs = "aws-ecs"

// IdDetector_PlatformID = "transport-platform-id" // TODO: how does this work?
)
31 changes: 9 additions & 22 deletions providers/os/provider/detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,16 @@ import (
"go.mondoo.com/cnquery/providers/os/id/azure"
"go.mondoo.com/cnquery/providers/os/id/gcp"
"go.mondoo.com/cnquery/providers/os/id/hostname"
"go.mondoo.com/cnquery/providers/os/id/ids"
"go.mondoo.com/cnquery/providers/os/id/machineid"
"go.mondoo.com/cnquery/providers/os/id/sshhostkey"
)

const (
IdDetector_Hostname = "hostname"
IdDetector_MachineID = "machine-id"
IdDetector_CloudDetect = "cloud-detect"
IdDetector_SshHostkey = "ssh-host-key"

// FIXME: DEPRECATED, remove in v9.0 vv
// this is now cloud-detect
IdDetector_AwsEc2 = "aws-ec2"
// ^^

// IdDetector_PlatformID = "transport-platform-id" // TODO: how does this work?
)

var IdDetectors = []string{
IdDetector_Hostname,
IdDetector_MachineID,
IdDetector_CloudDetect,
IdDetector_SshHostkey,
ids.IdDetector_Hostname,
ids.IdDetector_MachineID,
ids.IdDetector_CloudDetect,
ids.IdDetector_SshHostkey,
}

func hasDetector(detectors map[string]struct{}, any ...string) bool {
Expand Down Expand Up @@ -71,13 +58,13 @@ func (s *Service) detect(asset *inventory.Asset, conn shared.Connection) error {
detectors = mapDetectors(asset.IdDetector)
}

if hasDetector(detectors, IdDetector_Hostname) {
if hasDetector(detectors, ids.IdDetector_Hostname) {
if id, ok := hostname.Hostname(conn, asset.Platform); ok {
asset.PlatformIds = append(asset.PlatformIds, id)
}
}

if hasDetector(detectors, IdDetector_CloudDetect, IdDetector_AwsEc2) {
if hasDetector(detectors, ids.IdDetector_CloudDetect) {
if id, name, related := aws.Detect(conn, asset.Platform); id != "" {
asset.PlatformIds = append(asset.PlatformIds, id)
asset.Platform.Name = name
Expand All @@ -97,7 +84,7 @@ func (s *Service) detect(asset *inventory.Asset, conn shared.Connection) error {
}
}

if hasDetector(detectors, IdDetector_SshHostkey) {
if hasDetector(detectors, ids.IdDetector_SshHostkey) {
ids, err := sshhostkey.Detect(conn, asset.Platform)
if err != nil {
log.Warn().Err(err).Msg("failure in ssh hostkey detector")
Expand All @@ -106,7 +93,7 @@ func (s *Service) detect(asset *inventory.Asset, conn shared.Connection) error {
}
}

if hasDetector(detectors, IdDetector_MachineID) {
if hasDetector(detectors, ids.IdDetector_MachineID) {
id, hostErr := machineid.MachineId(conn, asset.Platform)
if hostErr != nil {
log.Warn().Err(hostErr).Msg("failure in machineID detector")
Expand Down
190 changes: 190 additions & 0 deletions providers/os/provider/platform.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package provider

import (
"errors"
"fmt"

"github.com/rs/zerolog/log"
"go.mondoo.com/cnquery/providers-sdk/v1/inventory"
"go.mondoo.com/cnquery/providers/os/connection/shared"
"go.mondoo.com/cnquery/providers/os/detector"
"go.mondoo.com/cnquery/providers/os/id/awsec2"
"go.mondoo.com/cnquery/providers/os/id/awsecs"
"go.mondoo.com/cnquery/providers/os/id/clouddetect"
"go.mondoo.com/cnquery/providers/os/id/hostname"
"go.mondoo.com/cnquery/providers/os/id/ids"
"go.mondoo.com/cnquery/providers/os/id/machineid"
"go.mondoo.com/cnquery/providers/os/id/sshhostkey"
)

type PlatformFingerprint struct {
PlatformIDs []string
Name string
Runtime string
Kind string
RelatedAssets []PlatformFingerprint
}

type PlatformInfo struct {
IDs []string
Name string
RelatedPlatformIDs []string
}

func IdentifyPlatform(conn shared.Connection, p *inventory.Platform, idDetectors []string) (*PlatformFingerprint, error) {
var ok bool
if p == nil {
p, ok = detector.DetectOS(conn)
if !ok {
return nil, errors.New("cannot detect os")
}
}

var fingerprint PlatformFingerprint
var ids []string
var relatedIds []string

for i := range idDetectors {
idDetector := idDetectors[i]
platformInfo, err := GatherPlatformInfo(conn, p, idDetector)
if err != nil {
// we only err if we found zero platform ids, if we try multiple, a fail of an individual one is okay
log.Debug().Err(err).Str("detector", string(idDetector)).Msg("could not determine platform info")
continue
}
if len(platformInfo.IDs) > 0 {
ids = append(ids, platformInfo.IDs...)
}
if len(platformInfo.RelatedPlatformIDs) > 0 {
relatedIds = append(relatedIds, platformInfo.RelatedPlatformIDs...)
}

if len(platformInfo.Name) > 0 {
fingerprint.Name = platformInfo.Name
} else {
// check if we get a name for the asset, eg. aws instance id
for _, id := range platformInfo.IDs {
name := GatherNameForPlatformId(id)
if name != "" {
fingerprint.Name = name
}
}
}
// check whether we can extract runtime and kind information
for _, id := range platformInfo.IDs {
runtime, kind := ExtractPlatformAndKindFromPlatformId(id)
if runtime != "" {
fingerprint.Runtime = runtime
fingerprint.Kind = kind
}
}
}

// if we found zero platform ids something went wrong
if len(ids) == 0 {
return nil, errors.New("could not determine a platform identifier")
}

fingerprint.PlatformIDs = ids
for _, v := range relatedIds {
fingerprint.RelatedAssets = append(fingerprint.RelatedAssets, PlatformFingerprint{
PlatformIDs: []string{v},
Name: GatherNameForPlatformId(v),
})
}

log.Debug().Interface("id-detector", idDetectors).Strs("platform-ids", ids).Msg("detected platform ids")
return &fingerprint, nil
}

func GatherNameForPlatformId(id string) string {
if awsec2.IsValidMondooInstanceId(id) {
structId, _ := awsec2.ParseMondooInstanceID(id)
return structId.Id
} else if accountID, err := awsec2.ParseMondooAccountID(id); err == nil {
return fmt.Sprintf("AWS Account %s", accountID)
}
return ""
}

func ExtractPlatformAndKindFromPlatformId(id string) (string, string) {
if awsec2.ParseEc2PlatformID(id) != nil {
return "aws-ec2", "virtual-machine"
} else if awsec2.IsValidMondooAccountId(id) {
return "aws", "api"
} else if awsecs.IsValidMondooECSContainerId(id) {
return "aws-ecs", "container"
}
return "", ""
}

func GatherPlatformInfo(conn shared.Connection, pf *inventory.Platform, idDetector string) (*PlatformInfo, error) {
var identifier string
switch {
case idDetector == ids.IdDetector_Hostname:
// NOTE: we need to be careful with hostname's since they are not required to be unique
hostname, ok := hostname.Hostname(conn, pf)
if ok && len(hostname) > 0 {
identifier = "//platformid.api.mondoo.app/hostname/" + hostname
return &PlatformInfo{
IDs: []string{identifier},
Name: hostname,
RelatedPlatformIDs: []string{},
}, nil
}
return &PlatformInfo{}, nil
case idDetector == ids.IdDetector_MachineID:
guid, hostErr := machineid.MachineId(conn, pf)
if hostErr == nil && len(guid) > 0 {
identifier = "//platformid.api.mondoo.app/machineid/" + guid
return &PlatformInfo{
IDs: []string{identifier},
Name: "",
RelatedPlatformIDs: []string{},
}, hostErr
}
return &PlatformInfo{}, nil
case idDetector == ids.IdDetector_AwsEcs:
metadata, err := awsecs.Resolve(conn, pf)
if err != nil {
return nil, err
}
ident, err := metadata.Identify()
if err != nil {
return nil, err
}
if len(ident.PlatformIds) != 0 {
return &PlatformInfo{
IDs: ident.PlatformIds,
Name: ident.Name,
RelatedPlatformIDs: []string{ident.AccountPlatformID},
}, nil
}
return &PlatformInfo{}, nil
case idDetector == ids.IdDetector_CloudDetect:
identifier, name, relatedIdentifiers := clouddetect.Detect(conn, pf)
if identifier != "" {
return &PlatformInfo{
IDs: []string{identifier},
Name: name,
RelatedPlatformIDs: relatedIdentifiers,
}, nil
}
return &PlatformInfo{}, nil
case idDetector == ids.IdDetector_SshHostkey:
identifier, err := sshhostkey.Detect(conn, pf)
if err != nil {
return nil, err
}
return &PlatformInfo{
IDs: identifier,
Name: "",
RelatedPlatformIDs: []string{},
}, nil
default:
return nil, errors.New(fmt.Sprintf("the provided id-detector is not supported: %s", idDetector))
}
}
Loading

0 comments on commit c814c3e

Please sign in to comment.