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

🐛 fix asset name for local, ssh conn #1740

Merged
merged 2 commits into from
Sep 19, 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
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