go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/id/gce/gce.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package gce
     5  
     6  import (
     7  	"encoding/json"
     8  	"errors"
     9  	"io"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"go.mondoo.com/cnquery/providers-sdk/v1/inventory"
    14  	"go.mondoo.com/cnquery/providers/os/connection/shared"
    15  	"go.mondoo.com/cnquery/providers/os/resources/powershell"
    16  )
    17  
    18  // deprecated: use MondooGcpInstancePlatformMrn
    19  func MondooGcpInstanceID(project string, zone string, instanceID uint64) string {
    20  	return "//platformid.api.mondoo.app/runtime/gcp/compute/v1/projects/" + project + "/zones/" + zone + "/instances/" + strconv.FormatUint(uint64(instanceID), 10)
    21  }
    22  
    23  func MondooGcpInstancePlatformMrn(project string, zone string, instanceName string) string {
    24  	return "//platformid.api.mondoo.app/runtime/gcp/compute/v1/projects/" + project + "/zones/" + zone + "/instances/" + instanceName
    25  }
    26  
    27  type Identity struct {
    28  	ProjectID string
    29  	// deprecated: use PlatformMrn
    30  	InstanceID  string
    31  	PlatformMrn string
    32  }
    33  type InstanceIdentifier interface {
    34  	Identify() (Identity, error)
    35  }
    36  
    37  func Resolve(conn shared.Connection, pf *inventory.Platform) (InstanceIdentifier, error) {
    38  	if pf.IsFamily(inventory.FAMILY_UNIX) || pf.IsFamily(inventory.FAMILY_WINDOWS) {
    39  		return NewCommandInstanceMetadata(conn, pf), nil
    40  	}
    41  	return nil, errors.New("gce id detector is not supported for your asset: " + pf.Name + " " + pf.Version)
    42  }
    43  
    44  const (
    45  	metadataSvcURL                = "http://metadata.google.internal/computeMetadata/v1/"
    46  	metadataIdentityScriptWindows = `
    47  $projectID = Invoke-RestMethod -Headers @{"Metadata-Flavor"="Google"} -Method GET -URI http://metadata.google.internal/computeMetadata/v1/project/project-id?alt=json -UseBasicParsing
    48  $instanceID = Invoke-RestMethod -Headers @{"Metadata-Flavor"="Google"} -Method GET -URI http://metadata.google.internal/computeMetadata/v1/instance/id?alt=json -UseBasicParsing
    49  $instanceName = Invoke-RestMethod -Headers @{"Metadata-Flavor"="Google"} -Method GET -URI http://metadata.google.internal/computeMetadata/v1/instance/name?alt=json -UseBasicParsing
    50  $zone = Invoke-RestMethod -Headers @{"Metadata-Flavor"="Google"} -Method GET -URI http://metadata.google.internal/computeMetadata/v1/instance/zone?alt=json -UseBasicParsing
    51  
    52  $doc = New-Object -TypeName PSObject
    53  $doc | Add-Member -MemberType NoteProperty -Value $projectID -Name ProjectID
    54  $doc | Add-Member -MemberType NoteProperty -Value $instanceID -Name InstanceID
    55  $doc | Add-Member -MemberType NoteProperty -Value $instanceName -Name InstanceName
    56  $doc | Add-Member -MemberType NoteProperty -Value $zone -Name ZoneInfo
    57  
    58  $doc | ConvertTo-Json
    59  `
    60  )
    61  
    62  func NewCommandInstanceMetadata(conn shared.Connection, platform *inventory.Platform) *CommandInstanceMetadata {
    63  	return &CommandInstanceMetadata{
    64  		connection: conn,
    65  		platform:   platform,
    66  	}
    67  }
    68  
    69  type CommandInstanceMetadata struct {
    70  	connection shared.Connection
    71  	platform   *inventory.Platform
    72  }
    73  
    74  func (m *CommandInstanceMetadata) curl(key string, v interface{}) error {
    75  	cmd, err := m.connection.RunCommand("curl --noproxy '*' -H Metadata-Flavor:Google " + metadataSvcURL + key + "?alt=json")
    76  	if err != nil {
    77  		return err
    78  	}
    79  
    80  	return json.NewDecoder(cmd.Stdout).Decode(v)
    81  }
    82  
    83  func (m *CommandInstanceMetadata) Identify() (Identity, error) {
    84  	switch {
    85  	case m.platform.IsFamily(inventory.FAMILY_UNIX):
    86  		var projectID string
    87  		var instanceID uint64
    88  		var instanceName string
    89  		var zoneInfo string
    90  
    91  		if err := m.curl("project/project-id", &projectID); err != nil {
    92  			return Identity{}, err
    93  		}
    94  
    95  		if err := m.curl("instance/id", &instanceID); err != nil {
    96  			return Identity{}, err
    97  		}
    98  
    99  		if err := m.curl("instance/name", &instanceName); err != nil {
   100  			return Identity{}, err
   101  		}
   102  
   103  		if err := m.curl("instance/zone", &zoneInfo); err != nil {
   104  			return Identity{}, err
   105  		}
   106  
   107  		zone := zoneInfo[strings.LastIndex(zoneInfo, "/")+1:]
   108  		return Identity{
   109  			ProjectID:   "//platformid.api.mondoo.app/runtime/gcp/projects/" + projectID,
   110  			InstanceID:  MondooGcpInstanceID(projectID, zone, instanceID),
   111  			PlatformMrn: MondooGcpInstancePlatformMrn(projectID, zone, instanceName),
   112  		}, nil
   113  	case m.platform.IsFamily(inventory.FAMILY_WINDOWS):
   114  		cmd, err := m.connection.RunCommand(powershell.Encode(metadataIdentityScriptWindows))
   115  		if err != nil {
   116  			return Identity{}, err
   117  		}
   118  		data, err := io.ReadAll(cmd.Stdout)
   119  		if err != nil {
   120  			return Identity{}, err
   121  		}
   122  
   123  		instanceDocument := strings.TrimSpace(string(data))
   124  		doc := struct {
   125  			ProjectID    string `json:"ProjectID"`
   126  			InstanceID   uint64 `json:"InstanceID"`
   127  			InstanceName string `json:"InstanceName"`
   128  			ZoneInfo     string `json:"ZoneInfo"`
   129  		}{}
   130  		json.Unmarshal([]byte(instanceDocument), &doc)
   131  		zone := doc.ZoneInfo[strings.LastIndex(doc.ZoneInfo, "/")+1:]
   132  
   133  		return Identity{
   134  			ProjectID:   "//platformid.api.mondoo.app/runtime/gcp/projects/" + doc.ProjectID,
   135  			InstanceID:  MondooGcpInstanceID(doc.ProjectID, zone, doc.InstanceID),
   136  			PlatformMrn: MondooGcpInstancePlatformMrn(doc.ProjectID, zone, doc.InstanceName),
   137  		}, nil
   138  	default:
   139  		return Identity{}, errors.New("your platform is not supported by azure metadata identifier resource")
   140  	}
   141  }